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