00ae317565d37cad9a011938e521697f29c398db
[sixth-3d.git] / src / main / java / eu / svjatoslav / sixth / e3d / renderer / raster / shapes / basic / solidpolygon / SolidPolygon.java
1 /*
2  * Sixth 3D engine. Copyright ©2012-2018, 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.solidpolygon;
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.gui.humaninput.MouseInteractionController;
17 import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
18 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractCoordinateShape;
19
20 public class SolidPolygon extends AbstractCoordinateShape {
21
22     private final static LineInterpolator polygonBoundary1 = new LineInterpolator();
23     private final static LineInterpolator polygonBoundary2 = new LineInterpolator();
24     private final static LineInterpolator polygonBoundary3 = new LineInterpolator();
25     private Color color;
26
27     public SolidPolygon(final Point3D point1, final Point3D point2,
28                         final Point3D point3, final Color color) {
29         super(point1, point2, point3);
30         this.color = color;
31     }
32
33     public static void drawHorizontalLine(final LineInterpolator line1,
34                                           final LineInterpolator line2, final int y,
35                                           final RenderingContext renderBuffer, final Color color) {
36
37         int x1 = line1.getX(y);
38         int x2 = line2.getX(y);
39
40         if (x1 > x2) {
41             final int tmp = x1;
42             x1 = x2;
43             x2 = tmp;
44         }
45
46         if (x1 < 0)
47             x1 = 0;
48
49         if (x2 >= renderBuffer.width)
50             x2 = renderBuffer.width - 1;
51
52         final int width = x2 - x1;
53
54         int offset = ((y * renderBuffer.width) + x1) * 4;
55         final byte[] offSreenBufferBytes = renderBuffer.pixels;
56
57         final int polygonAlpha = color.a;
58         final int b = color.b;
59         final int g = color.g;
60         final int r = color.r;
61
62         if (polygonAlpha == 255)
63             for (int i = 0; i < width; i++) {
64                 offSreenBufferBytes[offset] = (byte) 255;
65                 offset++;
66                 offSreenBufferBytes[offset] = (byte) b;
67                 offset++;
68                 offSreenBufferBytes[offset] = (byte) g;
69                 offset++;
70                 offSreenBufferBytes[offset] = (byte) r;
71                 offset++;
72             }
73         else {
74             final int backgroundAlpha = 255 - polygonAlpha;
75
76             final int blueWithAlpha = b * polygonAlpha;
77             final int greenWithAlpha = g * polygonAlpha;
78             final int redWithAlpha = r * polygonAlpha;
79
80             for (int i = 0; i < width; i++) {
81                 offSreenBufferBytes[offset] = (byte) 255;
82                 offset++;
83                 offSreenBufferBytes[offset] = (byte) ((((offSreenBufferBytes[offset] & 0xff) * backgroundAlpha) + blueWithAlpha) / 256);
84                 offset++;
85                 offSreenBufferBytes[offset] = (byte) ((((offSreenBufferBytes[offset] & 0xff) * backgroundAlpha) + greenWithAlpha) / 256);
86                 offset++;
87                 offSreenBufferBytes[offset] = (byte) ((((offSreenBufferBytes[offset] & 0xff) * backgroundAlpha) + redWithAlpha) / 256);
88                 offset++;
89             }
90
91         }
92
93     }
94
95     public static void drawPolygon(final RenderingContext context,
96                                    final Point2D onScreenPoint1, final Point2D onScreenPoint2,
97                                    final Point2D onScreenPoint3,
98                                    final MouseInteractionController mouseInteractionController,
99                                    final Color color) {
100
101         onScreenPoint1.roundToInteger();
102         onScreenPoint2.roundToInteger();
103         onScreenPoint3.roundToInteger();
104
105         if (mouseInteractionController != null)
106             if (context.mouseClick != null)
107                 if (Polygon.pointWithinPolygon(context.mouseClick.coordinate,
108                         onScreenPoint1, onScreenPoint2, onScreenPoint3))
109                     context.clickedItem = mouseInteractionController;
110
111         if (color.isTransparent())
112             return;
113
114         // find top-most point
115         int yTop = (int) onScreenPoint1.y;
116
117         if (onScreenPoint2.y < yTop)
118             yTop = (int) onScreenPoint2.y;
119
120         if (onScreenPoint3.y < yTop)
121             yTop = (int) onScreenPoint3.y;
122
123         if (yTop < 0)
124             yTop = 0;
125
126         // find bottom-most point
127         int yBottom = (int) onScreenPoint1.y;
128
129         if (onScreenPoint2.y > yBottom)
130             yBottom = (int) onScreenPoint2.y;
131
132         if (onScreenPoint3.y > yBottom)
133             yBottom = (int) onScreenPoint3.y;
134
135         if (yBottom >= context.height)
136             yBottom = context.height - 1;
137
138         // paint
139         polygonBoundary1.setPoints(onScreenPoint1, onScreenPoint2);
140         polygonBoundary2.setPoints(onScreenPoint1, onScreenPoint3);
141         polygonBoundary3.setPoints(onScreenPoint2, onScreenPoint3);
142
143         final LineInterpolator[] is = new LineInterpolator[3];
144         is[0] = polygonBoundary1;
145         is[1] = polygonBoundary2;
146         is[2] = polygonBoundary3;
147
148         java.util.Arrays.sort(is);
149
150         for (int y = yTop; y < yBottom; y++)
151             if (is[0].containsY(y)) {
152
153                 if (is[1].containsY(y))
154                     drawHorizontalLine(is[0], is[1], y, context, color);
155                 else if (is[2].containsY(y))
156                     drawHorizontalLine(is[0], is[2], y, context, color);
157             } else if (is[1].containsY(y))
158                 if (is[2].containsY(y))
159                     drawHorizontalLine(is[1], is[2], y, context, color);
160     }
161
162     public Color getColor() {
163         return color;
164     }
165
166     public void setColor(final Color color) {
167         this.color = color;
168     }
169
170     @Override
171     public void paint(final RenderingContext renderBuffer) {
172
173         final Point2D onScreenPoint1 = coordinates[0].onScreenCoordinate;
174         final Point2D onScreenPoint2 = coordinates[1].onScreenCoordinate;
175         final Point2D onScreenPoint3 = coordinates[2].onScreenCoordinate;
176
177         drawPolygon(renderBuffer, onScreenPoint1, onScreenPoint2,
178                 onScreenPoint3, mouseInteractionController, color);
179
180     }
181
182 }