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