Formatting update
[sixth-3d.git] / src / main / java / eu / svjatoslav / sixth / e3d / renderer / raster / shapes / basic / texturedpolygon / TexturedPolygon.java
1 /*
2  * Sixth 3D engine. Author: Svjatoslav Agejenko. 
3  * This project is released under Creative Commons Zero (CC0) license.
4  */
5 package eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.texturedpolygon;
6
7 import eu.svjatoslav.sixth.e3d.geometry.Point2D;
8 import eu.svjatoslav.sixth.e3d.geometry.Point3D;
9 import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
10 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractCoordinateShape;
11 import eu.svjatoslav.sixth.e3d.renderer.raster.slicer.PolygonCoordinate;
12 import eu.svjatoslav.sixth.e3d.renderer.raster.texture.Texture;
13 import eu.svjatoslav.sixth.e3d.renderer.raster.texture.TextureBitmap;
14
15 import java.awt.*;
16
17 import static eu.svjatoslav.sixth.e3d.geometry.Polygon.pointWithinPolygon;
18
19 public class TexturedPolygon extends AbstractCoordinateShape {
20
21     public final Texture texture;
22     final PolygonBorderInterpolator[] is = new PolygonBorderInterpolator[]{
23             new PolygonBorderInterpolator(), new PolygonBorderInterpolator(),
24             new PolygonBorderInterpolator()};
25     /**
26      * Polygon texture coordinates.
27      */
28     public Point2D texturePoint1, texturePoint2, texturePoint3;
29     private boolean showBorders = false;
30     private double totalTextureDistance = -1;
31
32     public TexturedPolygon(final Point3D p1, final Point3D p2,
33                            final Point3D p3, final Point2D tp1, final Point2D tp2,
34                            final Point2D tp3, final Texture texture) {
35
36         super(p1, p2, p3);
37
38         texturePoint1 = tp1;
39         texturePoint2 = tp2;
40         texturePoint3 = tp3;
41
42         this.texture = texture;
43     }
44
45     public TexturedPolygon(final PolygonCoordinate pc1,
46                            final PolygonCoordinate pc2, final PolygonCoordinate pc3,
47                            final Texture texture) {
48
49         this(pc1.space, pc2.space, pc3.space, pc1.texture, pc2.texture,
50                 pc3.texture, texture);
51     }
52
53     private void computeTotalTextureDistance() {
54         // compute total texture distance
55         totalTextureDistance = texturePoint1.getDistanceTo(texturePoint2);
56         totalTextureDistance += texturePoint1.getDistanceTo(texturePoint3);
57         totalTextureDistance += texturePoint2.getDistanceTo(texturePoint3);
58     }
59
60     private void drawHorizontalLine(final PolygonBorderInterpolator line1,
61                                     final PolygonBorderInterpolator line2, final int y,
62                                     final RenderingContext renderBuffer,
63                                     final TextureBitmap textureBitmap) {
64
65         line1.setCurrentY(y);
66         line2.setCurrentY(y);
67
68         int x1 = line1.getX();
69         int x2 = line2.getX();
70
71         final double tx2, ty2;
72         final double tx1, ty1;
73
74         if (x1 <= x2) {
75
76             tx1 = line1.getTX() * textureBitmap.multiplicationFactor;
77             ty1 = line1.getTY() * textureBitmap.multiplicationFactor;
78
79             tx2 = line2.getTX() * textureBitmap.multiplicationFactor;
80             ty2 = line2.getTY() * textureBitmap.multiplicationFactor;
81
82         } else {
83             final int tmp = x1;
84             x1 = x2;
85             x2 = tmp;
86
87             tx1 = line2.getTX() * textureBitmap.multiplicationFactor;
88             ty1 = line2.getTY() * textureBitmap.multiplicationFactor;
89
90             tx2 = line1.getTX() * textureBitmap.multiplicationFactor;
91             ty2 = line1.getTY() * textureBitmap.multiplicationFactor;
92         }
93
94         final double realWidth = x2 - x1;
95         final double realX1 = x1;
96
97         if (x1 < 0)
98             x1 = 0;
99
100         if (x2 >= renderBuffer.width)
101             x2 = renderBuffer.width - 1;
102
103         int renderBufferOffset = ((y * renderBuffer.width) + x1) * 4;
104         final byte[] renderBufferBytes = renderBuffer.pixels;
105
106         final double twidth = tx2 - tx1;
107         final double theight = ty2 - ty1;
108
109         for (int x = x1; x < x2; x++) {
110
111             final double distance = x - realX1;
112
113             final double tx = tx1 + ((twidth * distance) / realWidth);
114             final double ty = ty1 + ((theight * distance) / realWidth);
115
116             final int textureOffset = textureBitmap.getAddress((int) tx,
117                     (int) ty);
118
119             textureBitmap.drawPixel(textureOffset, renderBufferBytes,
120                     renderBufferOffset);
121
122             renderBufferOffset += 4;
123         }
124
125     }
126
127     @Override
128     public void paint(final RenderingContext renderBuffer) {
129
130         final Point2D projectedPoint1 = coordinates[0].onScreenCoordinate;
131         final Point2D projectedPoint2 = coordinates[1].onScreenCoordinate;
132         final Point2D projectedPoint3 = coordinates[2].onScreenCoordinate;
133
134         projectedPoint1.roundToInteger();
135         projectedPoint2.roundToInteger();
136         projectedPoint3.roundToInteger();
137
138         if (mouseInteractionController != null)
139             if (renderBuffer.getMouseEvent() != null)
140                 if (pointWithinPolygon(
141                         renderBuffer.getMouseEvent().coordinate, projectedPoint1,
142                         projectedPoint2, projectedPoint3))
143                     renderBuffer.setObjectUnderMouse(mouseInteractionController);
144
145         // Show polygon boundaries (for debugging)
146         if (showBorders)
147             showBorders(renderBuffer);
148
149         // find top-most point
150         int yTop = (int) projectedPoint1.y;
151
152         if (projectedPoint2.y < yTop)
153             yTop = (int) projectedPoint2.y;
154
155         if (projectedPoint3.y < yTop)
156             yTop = (int) projectedPoint3.y;
157
158         if (yTop < 0)
159             yTop = 0;
160
161         // find bottom-most point
162         int yBottom = (int) projectedPoint1.y;
163
164         if (projectedPoint2.y > yBottom)
165             yBottom = (int) projectedPoint2.y;
166
167         if (projectedPoint3.y > yBottom)
168             yBottom = (int) projectedPoint3.y;
169
170         if (yBottom >= renderBuffer.height)
171             yBottom = renderBuffer.height - 1;
172
173         // paint
174         double totalVisibleDistance = projectedPoint1
175                 .getDistanceTo(projectedPoint2);
176         totalVisibleDistance += projectedPoint1.getDistanceTo(projectedPoint3);
177         totalVisibleDistance += projectedPoint2.getDistanceTo(projectedPoint3);
178
179         if (totalTextureDistance == -1)
180             computeTotalTextureDistance();
181         final double scaleFactor = (totalVisibleDistance / totalTextureDistance) * 1.2d;
182
183         final TextureBitmap zoomedBitmap = texture.getZoomedBitmap(scaleFactor);
184
185         is[0].setPoints(projectedPoint1, projectedPoint2, texturePoint1,
186                 texturePoint2);
187         is[1].setPoints(projectedPoint1, projectedPoint3, texturePoint1,
188                 texturePoint3);
189         is[2].setPoints(projectedPoint2, projectedPoint3, texturePoint2,
190                 texturePoint3);
191
192         java.util.Arrays.sort(is);
193
194         for (int y = yTop; y < yBottom; y++)
195             if (is[0].containsY(y)) {
196
197                 if (is[1].containsY(y))
198                     drawHorizontalLine(is[0], is[1], y, renderBuffer,
199                             zoomedBitmap);
200                 else if (is[2].containsY(y))
201                     drawHorizontalLine(is[0], is[2], y, renderBuffer,
202                             zoomedBitmap);
203             } else if (is[1].containsY(y))
204                 if (is[2].containsY(y))
205                     drawHorizontalLine(is[1], is[2], y, renderBuffer,
206                             zoomedBitmap);
207
208     }
209
210     private void showBorders(final RenderingContext renderBuffer) {
211
212         final Point2D projectedPoint1 = coordinates[0].onScreenCoordinate;
213         final Point2D projectedPoint2 = coordinates[1].onScreenCoordinate;
214         final Point2D projectedPoint3 = coordinates[2].onScreenCoordinate;
215
216         renderBuffer.graphics.setColor(Color.YELLOW);
217         renderBuffer.graphics.drawLine((int) projectedPoint1.x,
218                 (int) projectedPoint1.y, (int) projectedPoint2.x,
219                 (int) projectedPoint2.y);
220         renderBuffer.graphics.drawLine((int) projectedPoint3.x,
221                 (int) projectedPoint3.y, (int) projectedPoint2.x,
222                 (int) projectedPoint2.y);
223         renderBuffer.graphics.drawLine((int) projectedPoint1.x,
224                 (int) projectedPoint1.y, (int) projectedPoint3.x,
225                 (int) projectedPoint3.y);
226     }
227
228 }