1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package view.f32;
 26 
 27 import view.f32.pool.F32x3TrianglePool;
 28 
 29 public interface F32 {
 30     F32x4x4.Factory f32x4x4Factory();
 31 
 32     F32x3.Factory f32x3Factory();
 33 
 34     F32x2.Factory f32x2Factory();
 35 
 36     F32x3Triangle.Factory f32x3TriangleFactory();
 37 
 38     F32x2Triangle.Factory f32x2TriangleFactory();
 39 
 40     default F32x4x4 f32x4x4(
 41             float x0y0, float x1y0, float x2y0, float x3y0,
 42             float x0y1, float x1y1, float x2y1, float x3y1,
 43             float x0y2, float x1y2, float x2y2, float x3y2,
 44             float x0y3, float x1y3, float x2y3, float x3y3
 45     ) {
 46         return f32x4x4Factory().of(x0y0, x1y0, x2y0, x3y0,
 47                 x0y1, x1y1, x2y1, x3y1,
 48                 x0y2, x1y2, x2y2, x3y2,
 49                 x0y3, x1y3, x2y3, x3y3);
 50     }
 51 
 52     default F32x2 f32x2(float x, float y) {
 53         return f32x2Factory().of(x, y);
 54     }
 55 
 56     default F32x3 f32x3(float x, float y, float z) {
 57         return f32x3Factory().of(x, y, z);
 58     }
 59 
 60     default F32x3Triangle f32x3Triangle(F32x3 v0, F32x3 v1, F32x3 v2, int rgb) {
 61         return f32x3TriangleFactory().of(v0, v1, v2, rgb);
 62     }
 63 
 64     default F32x2Triangle f32x2Triangle(F32x2 v0, F32x2 v1, F32x2 v2, float zplane, float normal, int rgb) {
 65         return f32x2TriangleFactory().of(v0, v1, v2, zplane, normal, rgb);
 66     }
 67 
 68     default F32x4x4 mul(F32x4x4 lhs, F32x4x4 rhs) {
 69         return f32x4x4(
 70                 lhs.x0y0() * rhs.x0y0() + lhs.x1y0() * rhs.x0y1() + lhs.x2y0() * rhs.x0y2() + lhs.x3y0() * rhs.x0y3(),
 71                 lhs.x0y0() * rhs.x1y0() + lhs.x1y0() * rhs.x1y1() + lhs.x2y0() * rhs.x1y2() + lhs.x3y0() * rhs.x1y3(),
 72                 lhs.x0y0() * rhs.x2y0() + lhs.x1y0() * rhs.x2y1() + lhs.x2y0() * rhs.x2y2() + lhs.x3y0() * rhs.x2y3(),
 73                 lhs.x0y0() * rhs.x3y0() + lhs.x1y0() * rhs.x3y1() + lhs.x2y0() * rhs.x3y2() + lhs.x3y0() * rhs.x3y3(),
 74 
 75                 lhs.x0y1() * rhs.x0y0() + lhs.x1y1() * rhs.x0y1() + lhs.x2y1() * rhs.x0y2() + lhs.x3y1() * rhs.x0y3(),
 76                 lhs.x0y1() * rhs.x1y0() + lhs.x1y1() * rhs.x1y1() + lhs.x2y1() * rhs.x1y2() + lhs.x3y1() * rhs.x1y3(),
 77                 lhs.x0y1() * rhs.x2y0() + lhs.x1y1() * rhs.x2y1() + lhs.x2y1() * rhs.x2y2() + lhs.x3y1() * rhs.x2y3(),
 78                 lhs.x0y1() * rhs.x3y0() + lhs.x1y1() * rhs.x3y1() + lhs.x2y1() * rhs.x3y2() + lhs.x3y1() * rhs.x3y3(),
 79 
 80                 lhs.x0y2() * rhs.x0y0() + lhs.x1y2() * rhs.x0y1() + lhs.x2y2() * rhs.x0y2() + lhs.x3y2() * rhs.x0y3(),
 81                 lhs.x0y2() * rhs.x1y0() + lhs.x1y2() * rhs.x1y1() + lhs.x2y2() * rhs.x1y2() + lhs.x3y2() * rhs.x1y3(),
 82                 lhs.x0y2() * rhs.x2y0() + lhs.x1y2() * rhs.x2y1() + lhs.x2y2() * rhs.x2y2() + lhs.x3y2() * rhs.x2y3(),
 83                 lhs.x0y2() * rhs.x3y0() + lhs.x1y2() * rhs.x3y1() + lhs.x2y2() * rhs.x3y2() + lhs.x3y2() * rhs.x3y3(),
 84 
 85                 lhs.x0y3() * rhs.x0y0() + lhs.x1y3() * rhs.x0y1() + lhs.x2y3() * rhs.x0y2() + lhs.x3y3() * rhs.x0y3(),
 86                 lhs.x0y3() * rhs.x1y0() + lhs.x1y3() * rhs.x1y1() + lhs.x2y3() * rhs.x1y2() + lhs.x3y3() * rhs.x1y3(),
 87                 lhs.x0y3() * rhs.x2y0() + lhs.x1y3() * rhs.x2y1() + lhs.x2y3() * rhs.x2y2() + lhs.x3y3() * rhs.x2y3(),
 88                 lhs.x0y3() * rhs.x3y0() + lhs.x1y3() * rhs.x3y1() + lhs.x2y3() * rhs.x3y2() + lhs.x3y3() * rhs.x3y3()
 89 
 90         );
 91     }
 92 
 93     //  https://stackoverflow.com/questions/28075743/how-do-i-compose-a-rotation-matrix-with-human-readable-angles-from-scratch/28084380#28084380
 94 
 95 
 96     //https://medium.com/swlh/understanding-3d-matrix-transforms-with-pixijs-c76da3f8bd8
 97     default F32x4x4 transformation(float x, float y, float z) {
 98         return f32x4x4(
 99                 1f, 0f, 0f, 0f,
100                 0f, 1f, 0f, 0f,
101                 0f, 0f, 1f, 0f,
102                 x, y, z, 1f
103         );
104     }
105 
106     default F32x4x4 transformation(float v) {
107         return transformation(v, v, v);
108     }
109 
110     default F32x4x4 scale(float x, float y, float z) {
111         return f32x4x4(
112                 x, 0f, 0f, 0f,
113                 0f, y, 0f, 0f,
114                 0f, 0f, z, 0f,
115                 0f, 0f, 0f, 1f
116         );
117     }
118 
119     default F32x4x4 scale(float v) {
120         return scale(v, v, v);
121     }
122 
123     default F32x4x4 rotX(float thetaRadians) {
124         float sinTheta = (float) Math.sin(thetaRadians);
125         float cosTheta = (float) Math.cos(thetaRadians);
126         return f32x4x4(
127                 1f, 0f, 0f, 0f,
128                 0f, cosTheta, -sinTheta, 0f,
129                 0f, sinTheta, cosTheta, 0f,
130                 0f, 0f, 0f, 1f
131 
132         );
133     }
134 
135     default F32x4x4 rotZ(float thetaRadians) {
136         float sinTheta = (float) Math.sin(thetaRadians);
137         float cosTheta = (float) Math.cos(thetaRadians);
138         return f32x4x4(
139                 cosTheta, sinTheta, 0f, 0f,
140                 -sinTheta, cosTheta, 0f, 0f,
141                 0f, 0f, 1f, 0f,
142                 0f, 0f, 0f, 1f
143         );
144     }
145 
146     default F32x4x4 rotY(float thetaRadians) {
147         float sinTheta = (float) Math.sin(thetaRadians);
148         float cosTheta = (float) Math.cos(thetaRadians);
149         return f32x4x4(
150                 cosTheta, 0f, sinTheta, 0f,
151                 0f, 1f, 0f, 0f,
152                 -sinTheta, 0f, cosTheta, 0f,
153                 0f, 0f, 0f, 1f
154         );
155     }
156 
157     default F32x4x4 rot(float thetaX, float thetaY, float thetaZ) {
158         return mul(mul(rotX(thetaX), rotY(thetaY)), rotZ(thetaZ));
159     }
160 
161     // https://medium.com/swlh/understanding-3d-matrix-transforms-with-pixijs-c76da3f8bd8
162 
163 
164     /*
165                  https://youtu.be/ih20l3pJoeU?t=973
166                  https://stackoverflow.com/questions/28075743/how-do-i-compose-a-rotation-matrix-with-human-readable-angles-from-scratch/28084380#28084380^
167                 --------------------            far
168                  \                /              ^    ^
169                   \              /               |    |   far-near
170                    \            /                |    |
171                     \__________/         near    |    v
172                                           ^      |
173                                           v      v
174                         \^/
175                       [x,y,z]
176 
177                */
178     default F32x4x4 projection(float width, float height, float near, float far, float fieldOfViewDeg) {
179         float aspectRatio = height / width;
180         float fieldOfViewRadians = (float) (1.0f / Math.tan((fieldOfViewDeg * 0.5f) / 180.0 * Math.PI));
181         return f32x4x4(
182                 aspectRatio * fieldOfViewRadians, 0f, 0f, 0f,
183                 0f, fieldOfViewRadians, 0f, 0f,
184                 0f, 0f, far / (far - near), (-far * near) / (far - near),
185                 0f, 0f, (-far * near) / (far - near), 0f);
186     }
187 
188     static float side(float x, float y, F32x2 v0, F32x2 v1) {
189         return (v1.y() - v0.y() * (x - v0.x()) + (-v1.x() + v0.x()) * (y - v0.y()));
190     }
191 
192      /*
193               V0                V0
194               |  \              |  \
195               |    \            |    \        P2
196               |  P1  \          |      \
197               V1------V0        V1------V0
198 
199 
200 Barycentric coordinate allows to express new p coordinates as a linear combination of p1, p2, p3.
201  More precisely, it defines 3 scalars a, b, c such that :
202 
203 x = a * x1 + b * x2  + c * x3
204 y = a * y1 + b * y2 + c * y3
205 a + b + c = 1
206 
207 
208 a = ((y2 - y3)*(x - x3) + (x3 - x2)*(y - y3)) / ((y2 - y3)*(x1 - x3) + (x3 - x2)*(y1 - y3))
209 b = ((y3 - y1)*(x - x3) + (x1 - x3)*(y - y3)) / ((y2 - y3)*(x1 - x3) + (x3 - x2)*(y1 - y3))
210 c = 1 - a - b
211 
212 p lies in T if and only if 0 <= a <= 1 and 0 <= b <= 1 and 0 <= c <= 1
213 */
214 
215     static boolean inside(float x, float y, float x0, float y0, float x1, float y1, float x2, float y2) {
216         var denominator = ((y1 - y2) * (x0 - x2) + (x2 - x1) * (y0 - y2));
217         var a = ((y1 - y2) * (x - x2) + (x2 - x1) * (y - y2)) / denominator;
218         var b = ((y2 - y0) * (x - x2) + (x0 - x2) * (y - y2)) / denominator;
219         var c = 1 - a - b;
220         return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
221     }
222 
223     static boolean inside(float x, float y, F32x2 v0, F32x2 v1, F32x2 v2) {
224         return inside(x, y, v0.x(), v0.y(), v1.x(), v1.y(), v2.x(), v2.y());
225     }
226 
227     static boolean inside(float x, float y, F32x2Triangle tri) {
228         return inside(x, y, tri.v0(), tri.v1(), tri.v2());
229     }
230 
231     static boolean onLine(float x, float y, F32x2 v0, F32x2 v1, float deltaSquare) {
232         float dxl = v1.x() - v0.x();
233         float dyl = v1.y() - v0.y();
234         ;
235         float cross = (x - v0.x()) * dyl - (y - v0.y()) * dxl;
236         if ((cross * cross) < deltaSquare) {
237             if (dxl * dxl >= dyl * dyl)
238                 return dxl > 0 ? v0.x() <= x && x <= v1.x() : v1.x() <= x && x <= v0.x();
239             else
240                 return dyl > 0 ? v0.y() <= y && y <= v1.y() : v1.y() <= y && y <= v0.y();
241         } else {
242             return false;
243         }
244     }
245 
246     float deltaSquare = 2000f;
247 
248     static boolean onEdge(float x, float y, F32x2Triangle tri) {
249         return onLine(x, y, tri.v0(), tri.v1(), deltaSquare)
250                 || onLine(x, y, tri.v1(), tri.v2(), deltaSquare)
251                 || onLine(x, y, tri.v2(), tri.v0(), deltaSquare);
252     }
253 
254     static boolean useRgb(boolean filled, float x, float y, F32x2Triangle tri) {
255         return filled ? inside(x, y, tri) : onEdge(x, y, tri);
256     }
257 
258     static int rgb(boolean filled, float x, float y, F32x2Triangle tri, int rgb) {
259         return useRgb(filled, x, y, tri) ? tri.rgb() : rgb;
260     }
261 
262     /*
263       v0----v1         v0----v2
264        \    |           \    |
265         \   |            \   |
266          \  |    --->     \  |
267           \ |              \ |
268            \|               \|
269             v2               v1
270   */
271     static F32x3Triangle rewind(F32x3Triangle i) {
272         var temp = i.v1();
273         ((F32x3TrianglePool.PoolEntry) i).pool().f32x3Entries[((F32x3TrianglePool.PoolEntry) i).v1Idx()] = i.v2();
274         ((F32x3TrianglePool.PoolEntry) i).pool().f32x3Entries[((F32x3TrianglePool.PoolEntry) i).v2Idx()] = temp;
275         return i;
276     }
277 
278     default F32x3Triangle mul(F32x3Triangle i, F32x4x4 m4) {
279         return f32x3Triangle(mul(i.v0(), m4), mul(i.v1(), m4), mul(i.v2(), m4), i.rgb());
280     }
281 
282     default F32x3Triangle add(F32x3Triangle i, F32x3 v3) {
283         return f32x3Triangle(add(i.v0(), v3), add(i.v1(), v3), add(i.v2(), v3), i.rgb());
284     }
285 
286     default F32x3Triangle mul(F32x3Triangle i, float s) {
287         return f32x3Triangle(mul(i.v0(), s), mul(i.v1(), s), mul(i.v2(), s), i.rgb());
288     }
289 
290     default F32x3Triangle add(F32x3Triangle i, float s) {
291         return f32x3Triangle(add(i.v0(), s), add(i.v1(), s), add(i.v2(), s), i.rgb());
292     }
293 
294     default F32x3 centre(F32x3Triangle i) {// the average of all the vertices
295         return div(getVectorSum(i), 3);
296     }
297 
298     default F32x3 getVectorSum(F32x3Triangle i) {// the sum of all the vertices
299         return add(add(i.v0(), i.v1()), i.v2());
300     }
301 
302     default F32x3 normal(F32x3Triangle i) {
303         return crossProd(sub(i.v1(), i.v0()), sub(i.v2(), i.v0()));
304     }
305 
306     default F32x3 normalSumOfSquares(F32x3Triangle i) {
307         return div(normal(i), sumOfSq(normal(i)));
308     }
309 
310     /* return another vec3 after multiplying by m4
311      we pad this vec3 to vec 4 with '1' as w
312      we normalize the result
313      */
314 
315     default F32x3 mul(F32x3 f32x3, F32x4x4 m) {
316         F32x3 o = f32x3(
317                 f32x3.x() * m.x0y0() + f32x3.y() * m.x0y1() + f32x3.z() * m.x0y2() + 1f * m.x0y3(),
318                 f32x3.x() * m.x1y0() + f32x3.y() * m.x1y1() + f32x3.z() * m.x1y2() + 1f * m.x1y3(),
319                 f32x3.x() * m.x2y0() + f32x3.y() * m.x2y1() + f32x3.z() * m.x2y2() + 1f * m.x2y3()
320         );
321         float w = f32x3.x() * m.x3y0() + f32x3.y() * m.x3y1() + f32x3.z() * m.x3y2() + 1f * m.x3y3();
322         //  if (w!=0.0) {
323         o = div(o, w);
324         // }
325         return o;
326     }
327 
328     default F32x3 mul(F32x3 i, float s) {
329         return f32x3(i.x() * s, i.y() * s, i.z() * s);
330     }
331 
332     default F32x3 add(F32x3 i, float s) {
333 
334         return f32x3(i.x() + s, i.y() + s, i.z() + s);
335     }
336 
337     default F32x3 div(F32x3 i, float s) {
338         if (s == 0) {
339             return i;
340         }
341         return f32x3(i.x() / s, i.y() / s, i.z() / s);
342     }
343 
344     default F32x3 add(F32x3 lhs, F32x3 rhs) {
345         return f32x3(lhs.x() + rhs.x(), lhs.y() + rhs.y(), lhs.z() + rhs.z());
346     }
347 
348     default F32x3 sub(F32x3 lhs, F32x3 rhs) {
349         return f32x3(lhs.x() - rhs.x(), lhs.y() - rhs.y(), lhs.z() - rhs.z());
350     }
351 
352     default F32x3 mul(F32x3 lhs, F32x3 rhs) {
353         return f32x3(lhs.x() * rhs.x(), lhs.y() * rhs.y(), lhs.z() * rhs.z());
354     }
355 
356     default F32x3 div(F32x3 lhs, F32x3 rhs) {
357         return f32x3(lhs.x() / rhs.x(), lhs.y() / rhs.y(), lhs.z() / rhs.z());
358     }
359 
360     default float sumOfSq(F32x3 i) {
361         return i.x() * i.x() + i.y() * i.y() + i.z() * i.z();
362     }
363 
364     default float sumOf(F32x3 i) {
365         return i.x() + i.y() + i.z();
366     }
367 
368     default float hypot(F32x3 i) {
369         return (float) Math.sqrt(sumOfSq(i));
370     }
371 
372     default F32x3 crossProd(F32x3 lhs, F32x3 rhs) {
373         return f32x3(
374                 lhs.y() * rhs.z() - lhs.z() * rhs.x(),
375                 lhs.z() * rhs.x() - lhs.x() * rhs.z(),
376                 lhs.x() * rhs.y() - lhs.y() * rhs.x());
377 
378     }
379 
380     /*
381            lhs= | 1|   rhs= | 2|
382                 | 3|        | 7|
383                 | 4|        |-5|
384 
385            lhs0*rhs0 + lhs1*rhs1 + lhs2*rhs2
386             1  * 2   +  3  * 7   +  4  *-5
387 
388                3     +    21     +   -20
389 
390                           4
391 
392         */
393     default float dotProd(F32x3 lhs, F32x3 rhs) {
394         return lhs.x() * rhs.x() + lhs.y() * rhs.y() + lhs.z() * rhs.z();
395     }
396 }