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