ec4caeb22bd0b2fdad547a5ef9b1e569d7d3c2f9
[sixth-3d.git] /
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.texturedpolygon;
6
7 import eu.svjatoslav.sixth.e3d.geometry.Point2D;
8
9 import static java.lang.Math.abs;
10
11 /**
12  * Interpolator for textured polygon edges with perspective correction.
13  * <p>
14  * This class maps screen coordinates to texture coordinates while maintaining
15  * perspective accuracy.
16  * It's used to create texture-mapped scanlines that adjust for depth (z) to
17  * prevent texture distortion.
18  * <p>
19  * The comparison logic ensures proper scanline ordering based on vertical
20  * coverage and horizontal span.
21  */
22 public class PolygonBorderInterpolator implements
23         Comparable<PolygonBorderInterpolator> {
24
25     // on-screen coordinates
26     Point2D onScreenPoint1;
27     Point2D onScreenPoint2;
28
29     double distanceFromY1;
30     private int onScreenHeight;
31     private int onScreenWidth;
32     private int onscreenAbsoluteHeight;
33     private double textureWidth;
34     private double textureHeight;
35     // texture coordinates
36     private Point2D texturePoint1;
37     private Point2D texturePoint2;
38
39     /**
40      * Creates a new polygon border interpolator.
41      */
42     public PolygonBorderInterpolator() {
43     }
44
45     @Override
46     public boolean equals(final Object o) {
47         if (o == null) return false;
48
49         return o instanceof PolygonBorderInterpolator && compareTo((PolygonBorderInterpolator) o) == 0;
50     }
51
52     @Override
53     public int hashCode() {
54         int result = onScreenWidth;
55         result = 31 * result + onscreenAbsoluteHeight;
56         return result;
57     }
58
59     @Override
60     public int compareTo(final PolygonBorderInterpolator otherInterpolator) {
61         if (onscreenAbsoluteHeight < otherInterpolator.onscreenAbsoluteHeight)
62             return 1;
63         if (onscreenAbsoluteHeight > otherInterpolator.onscreenAbsoluteHeight)
64             return -1;
65
66         if (onScreenWidth < otherInterpolator.onScreenWidth)
67             return 1;
68         if (onScreenWidth > otherInterpolator.onScreenWidth)
69             return -1;
70
71         return 0;
72     }
73
74     /**
75      * Checks if the given Y coordinate falls within the vertical span of this edge.
76      *
77      * @param y the Y coordinate to test
78      * @return {@code true} if y is within the edge's vertical range
79      */
80     public boolean containsY(final int y) {
81
82         if (onScreenPoint1.y < onScreenPoint2.y) {
83             if (y >= onScreenPoint1.y)
84                 return y <= onScreenPoint2.y;
85         } else if (y >= onScreenPoint2.y)
86             return y <= onScreenPoint1.y;
87
88         return false;
89     }
90
91     /**
92      * Returns the interpolated texture X coordinate at the current Y position.
93      *
94      * @return the texture X coordinate
95      */
96     public double getTX() {
97
98         if (onScreenHeight == 0)
99             return (texturePoint2.x + texturePoint1.x) / 2d;
100
101         return texturePoint1.x + ((textureWidth * distanceFromY1) / onScreenHeight);
102     }
103
104     /**
105      * Returns the interpolated texture Y coordinate at the current Y position.
106      *
107      * @return the texture Y coordinate
108      */
109     public double getTY() {
110
111         if (onScreenHeight == 0)
112             return (texturePoint2.y + texturePoint1.y) / 2d;
113
114         return texturePoint1.y + ((textureHeight * distanceFromY1) / onScreenHeight);
115     }
116
117     /**
118      * Returns the interpolated screen X coordinate at the current Y position.
119      *
120      * @return the screen X coordinate
121      */
122     public int getX() {
123
124         if (onScreenHeight == 0)
125             return (int) ((onScreenPoint2.x + onScreenPoint1.x) / 2d);
126
127         return (int) (onScreenPoint1.x + ((onScreenWidth * distanceFromY1) / onScreenHeight));
128     }
129
130     /**
131      * Sets the current Y coordinate for interpolation.
132      *
133      * @param y the current Y coordinate
134      */
135     public void setCurrentY(final int y) {
136         distanceFromY1 = y - onScreenPoint1.y;
137     }
138
139     /**
140      * Sets the screen and texture coordinates for this edge.
141      *
142      * @param onScreenPoint1 the first screen-space endpoint
143      * @param onScreenPoint2 the second screen-space endpoint
144      * @param texturePoint1  the texture coordinate for the first endpoint
145      * @param texturePoint2  the texture coordinate for the second endpoint
146      */
147     public void setPoints(final Point2D onScreenPoint1, final Point2D onScreenPoint2,
148                           final Point2D texturePoint1, final Point2D texturePoint2) {
149
150         this.onScreenPoint1 = onScreenPoint1;
151         this.onScreenPoint2 = onScreenPoint2;
152         this.texturePoint1 = texturePoint1;
153         this.texturePoint2 = texturePoint2;
154
155         onScreenHeight = (int) (onScreenPoint2.y - onScreenPoint1.y);
156         onScreenWidth = (int) (onScreenPoint2.x - onScreenPoint1.x);
157         onscreenAbsoluteHeight = abs(onScreenHeight);
158
159         textureWidth = texturePoint2.x - texturePoint1.x;
160         textureHeight = texturePoint2.y - texturePoint1.y;
161     }
162
163 }