2 * Sixth 3D engine. Copyright ©2012-2016, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
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.
11 package eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.line;
13 import eu.svjatoslav.sixth.e3d.geometry.Point2D;
14 import eu.svjatoslav.sixth.e3d.geometry.Point3D;
15 import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
16 import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
17 import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractCoordinateShape;
19 public class Line extends AbstractCoordinateShape {
21 private static final double MINIMUM_WIDTH_THRESHOLD = 1;
23 private static final double LINE_WIDTH_MULTIPLIER = 0.2d;
25 public final double width;
26 final LineInterpolator[] li = new LineInterpolator[4];
29 public Line(final Line parentLine) {
30 this(parentLine.coordinates[0].coordinate.clone(),
31 parentLine.coordinates[1].coordinate.clone(), new Color(
32 parentLine.color), parentLine.width);
35 public Line(final Point3D point1, final Point3D point2, final Color color,
38 super(point1, point2);
43 for (int i = 0; i < li.length; i++)
44 li[i] = new LineInterpolator();
48 public void drawHorizontalLine(final LineInterpolator line1,
49 final LineInterpolator line2, final int y,
50 final RenderingContext renderBuffer) {
52 int x1 = line1.getX(y);
53 int x2 = line2.getX(y);
55 double d1 = line1.getD();
56 double d2 = line2.getD();
63 final double tmp2 = d1;
68 final int unclippedWidth = x2 - x1;
69 final double dinc = (d2 - d1) / unclippedWidth;
76 if (x2 >= renderBuffer.width)
77 x2 = renderBuffer.width - 1;
79 final int drawnWidth = x2 - x1;
81 int offset = ((y * renderBuffer.width) + x1) * 4;
82 final byte[] offSreenBufferBytes = renderBuffer.bytes;
84 final int lineAlpha = color.a;
86 final int colorB = color.b;
87 final int colorG = color.g;
88 final int colorR = color.r;
90 for (int i = 0; i < drawnWidth; i++) {
92 final double alphaMultiplier = 1d - Math.abs(d1);
94 final int realLineAlpha = (int) (lineAlpha * alphaMultiplier);
95 final int backgroundAlpha = 255 - realLineAlpha;
97 offSreenBufferBytes[offset] = (byte) 255;
99 offSreenBufferBytes[offset] = (byte) ((((offSreenBufferBytes[offset] & 0xff) * backgroundAlpha) + (colorB * realLineAlpha)) / 256);
101 offSreenBufferBytes[offset] = (byte) ((((offSreenBufferBytes[offset] & 0xff) * backgroundAlpha) + (colorG * realLineAlpha)) / 256);
103 offSreenBufferBytes[offset] = (byte) ((((offSreenBufferBytes[offset] & 0xff) * backgroundAlpha) + (colorR * realLineAlpha)) / 256);
111 public void drawSinglePixelHorizontalLine(final RenderingContext buffer,
114 final Point2D onScreenPoint1 = coordinates[0].onScreenCoordinate;
115 final Point2D onScreenPoint2 = coordinates[1].onScreenCoordinate;
117 int xStart = (int) onScreenPoint1.x;
118 int xEnd = (int) onScreenPoint2.x;
124 final int tmp = xStart;
127 lineHeight = (int) (onScreenPoint1.y - onScreenPoint2.y);
128 yBase = (int) onScreenPoint2.y;
130 yBase = (int) onScreenPoint1.y;
131 lineHeight = (int) (onScreenPoint2.y - onScreenPoint1.y);
134 final int lineWidth = xEnd - xStart;
138 final byte[] offSreenBufferBytes = buffer.bytes;
139 final int backgroundAlpha = 255 - alpha;
141 final int blueWithAlpha = color.b * alpha;
142 final int greenWithAplha = color.g * alpha;
143 final int redWithAlpha = color.r * alpha;
145 for (int relativeX = 0; relativeX <= lineWidth; relativeX++) {
146 final int x = xStart + relativeX;
148 if ((x >= 0) && (x < buffer.width)) {
150 final int y = yBase + ((relativeX * lineHeight) / lineWidth);
151 if ((y >= 0) && (y < buffer.height)) {
152 int ramOffset = ((y * buffer.width) + x) * 4;
154 offSreenBufferBytes[ramOffset] = (byte) 255;
156 offSreenBufferBytes[ramOffset] = (byte) ((((offSreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + blueWithAlpha) / 256);
158 offSreenBufferBytes[ramOffset] = (byte) ((((offSreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + greenWithAplha) / 256);
160 offSreenBufferBytes[ramOffset] = (byte) ((((offSreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + redWithAlpha) / 256);
167 public void drawSinglePixelVerticalLine(final RenderingContext buffer,
170 final Point2D onScreenPoint1 = coordinates[0].onScreenCoordinate;
171 final Point2D onScreenPoint2 = coordinates[1].onScreenCoordinate;
173 int yStart = (int) onScreenPoint1.y;
174 int yEnd = (int) onScreenPoint2.y;
180 final int tmp = yStart;
183 lineWidth = (int) (onScreenPoint1.x - onScreenPoint2.x);
184 xBase = (int) onScreenPoint2.x;
186 xBase = (int) onScreenPoint1.x;
187 lineWidth = (int) (onScreenPoint2.x - onScreenPoint1.x);
190 final int lineHeight = yEnd - yStart;
194 final byte[] offSreenBufferBytes = buffer.bytes;
195 final int backgroundAlpha = 255 - alpha;
197 final int blueWithAlpha = color.b * alpha;
198 final int greenWithAplha = color.g * alpha;
199 final int redWithAlpha = color.r * alpha;
201 for (int relativeY = 0; relativeY <= lineHeight; relativeY++) {
202 final int y = yStart + relativeY;
204 if ((y >= 0) && (y < buffer.height)) {
206 final int x = xBase + ((relativeY * lineWidth) / lineHeight);
207 if ((x >= 0) && (x < buffer.width)) {
208 int ramOffset = ((y * buffer.width) + x) * 4;
210 offSreenBufferBytes[ramOffset] = (byte) 255;
212 offSreenBufferBytes[ramOffset] = (byte) ((((offSreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + blueWithAlpha) / 256);
214 offSreenBufferBytes[ramOffset] = (byte) ((((offSreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + greenWithAplha) / 256);
216 offSreenBufferBytes[ramOffset] = (byte) ((((offSreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + redWithAlpha) / 256);
222 public int getLineInterpolator(final int startPointer, final int y) {
224 for (int i = startPointer; i < li.length; i++)
225 if (li[i].containsY(y))
231 public void paint(final RenderingContext buffer) {
233 final Point2D onScreenPoint1 = coordinates[0].onScreenCoordinate;
234 final Point2D onScreenPoint2 = coordinates[1].onScreenCoordinate;
236 final double xp = onScreenPoint2.x - onScreenPoint1.x;
237 final double yp = onScreenPoint2.y - onScreenPoint1.y;
239 final double point1radius = (buffer.width * LINE_WIDTH_MULTIPLIER * width)
240 / coordinates[0].transformedCoordinate.z;
241 final double point2radius = (buffer.width * LINE_WIDTH_MULTIPLIER * width)
242 / coordinates[1].transformedCoordinate.z;
244 if ((point1radius < MINIMUM_WIDTH_THRESHOLD)
245 || (point2radius < MINIMUM_WIDTH_THRESHOLD)) {
247 double averageRadius = (point1radius + point2radius) / 2;
249 if (averageRadius > 1)
252 final int alpha = (int) (color.a * averageRadius);
256 if (Math.abs(xp) > Math.abs(yp))
257 drawSinglePixelHorizontalLine(buffer, alpha);
259 drawSinglePixelVerticalLine(buffer, alpha);
263 final double lineLength = Math.sqrt((xp * xp) + (yp * yp));
265 final double yinc1 = (point1radius * xp) / lineLength;
266 final double yinc2 = (point2radius * xp) / lineLength;
268 final double xdec1 = (point1radius * yp) / lineLength;
269 final double xdec2 = (point2radius * yp) / lineLength;
271 final double p1x1 = onScreenPoint1.x - xdec1;
272 final double p1y1 = onScreenPoint1.y + yinc1;
274 final double p1x2 = onScreenPoint1.x + xdec1;
275 final double p1y2 = onScreenPoint1.y - yinc1;
277 final double p2x1 = onScreenPoint2.x - xdec2;
278 final double p2y1 = onScreenPoint2.y + yinc2;
280 final double p2x2 = onScreenPoint2.x + xdec2;
281 final double p2y2 = onScreenPoint2.y - yinc2;
283 li[0].setPoints(p1x1, p1y1, 1d, p2x1, p2y1, 1d);
284 li[1].setPoints(p1x2, p1y2, -1d, p2x2, p2y2, -1d);
286 li[2].setPoints(p1x1, p1y1, 1d, p1x2, p1y2, -1d);
287 li[3].setPoints(p2x1, p2y1, 1d, p2x2, p2y2, -1d);
306 if (ymax >= buffer.height)
307 ymax = buffer.height - 1;
309 for (int y = (int) ymin; y <= ymax; y++) {
310 final int li1 = getLineInterpolator(0, y);
312 final int li2 = getLineInterpolator(li1 + 1, y);
314 drawHorizontalLine(li[li1], li[li2], y, buffer);