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