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