JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
FloatUtil.java
Go to the documentation of this file.
1/**
2 * Copyright 2010-2023 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28package com.jogamp.math;
29
30import java.nio.FloatBuffer;
31import java.util.Locale;
32
33import com.jogamp.opengl.GLException;
34
35import jogamp.opengl.Debug;
36
37import com.jogamp.common.os.Platform;
38
39/**
40 * Basic Float math utility functions.
41 * <p>
42 * Implementation assumes linear matrix layout in column-major order
43 * matching OpenGL's implementation, illustration:
44 * <pre>
45 Row-Major Column-Major (OpenGL):
46
47 | 0 1 2 tx |
48 | |
49 | 4 5 6 ty |
50 M = | |
51 | 8 9 10 tz |
52 | |
53 | 12 13 14 15 |
54
55 R C R C
56 m[0*4+3] = tx; m[0+4*3] = tx;
57 m[1*4+3] = ty; m[1+4*3] = ty;
58 m[2*4+3] = tz; m[2+4*3] = tz;
59
60 RC (std subscript order) RC (std subscript order)
61 m03 = tx; m03 = tx;
62 m13 = ty; m13 = ty;
63 m23 = tz; m23 = tz;
64
65 * </pre>
66 * </p>
67 * <p>
68 * <ul>
69 * <li><a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix-FAQ</a></li>
70 * <li><a href="https://en.wikipedia.org/wiki/Matrix_%28mathematics%29">Wikipedia-Matrix</a></li>
71 * <li><a href="http://www.euclideanspace.com/maths/algebra/matrix/index.htm">euclideanspace.com-Matrix</a></li>
72 * </ul>
73 * </p>
74 * <p>
75 * Implementation utilizes unrolling of small vertices and matrices wherever possible
76 * while trying to access memory in a linear fashion for performance reasons, see:
77 * <ul>
78 * <li><a href="https://lessthanoptimal.github.io/Java-Matrix-Benchmark/">java-matrix-benchmark</a></li>
79 * <li><a href="https://github.com/lessthanoptimal/ejml">EJML Efficient Java Matrix Library</a></li>
80 * </ul>
81 * </p>
82 */
83public final class FloatUtil {
84 public static final boolean DEBUG = Debug.debugExplicit("Math");
85
86 //
87 // Matrix Ops
88 // Only a subset will remain here, try using Matrix4f and perhaps PMVMatrix, SyncMatrix4f16 or SyncMatrices4f16
89 //
90
91 /**
92 * Make matrix an identity matrix
93 * @param m 4x4 matrix in column-major order (also result)
94 * @return given matrix for chaining
95 */
96 public static float[] makeIdentity(final float[] m) {
97 m[0+4*0] = 1f;
98 m[1+4*0] = 0f;
99 m[2+4*0] = 0f;
100 m[3+4*0] = 0f;
101
102 m[0+4*1] = 0f;
103 m[1+4*1] = 1f;
104 m[2+4*1] = 0f;
105 m[3+4*1] = 0f;
106
107 m[0+4*2] = 0f;
108 m[1+4*2] = 0f;
109 m[2+4*2] = 1f;
110 m[3+4*2] = 0f;
111
112 m[0+4*3] = 0f;
113 m[1+4*3] = 0f;
114 m[2+4*3] = 0f;
115 m[3+4*3] = 1f;
116 return m;
117 }
118
119 /**
120 * Make a translation matrix in column-major order from the given axis deltas
121 * <pre>
122 Translation matrix (Column Order):
123 1 0 0 0
124 0 1 0 0
125 0 0 1 0
126 x y z 1
127 * </pre>
128 * <p>
129 * All matrix fields are only set if <code>initM</code> is <code>true</code>.
130 * </p>
131 * @param m 4x4 matrix in column-major order (also result)
132 * @param initM if true, given matrix will be initialized w/ identity matrix,
133 * otherwise only the diagonal and last-row is set.
134 * The latter can be utilized to share a once {@link #makeIdentity(float[], int) identity set} matrix
135 * for {@link #makeScale(float[], int, boolean, float, float, float) scaling}
136 * and {@link #makeTranslation(float[], int, boolean, float, float, float) translation},
137 * while leaving the other fields untouched for performance reasons.
138 * @return given matrix for chaining
139 */
140 public static float[] makeTranslation(final float[] m, final boolean initM, final float tx, final float ty, final float tz) {
141 if( initM ) {
142 makeIdentity(m);
143 } else {
144 m[0+4*0] = 1;
145 m[1+4*1] = 1;
146 m[2+4*2] = 1;
147 m[3+4*3] = 1;
148 }
149 m[0+4*3] = tx;
150 m[1+4*3] = ty;
151 m[2+4*3] = tz;
152 return m;
153 }
154
155 /**
156 * Make a scale matrix in column-major order from the given axis factors
157 * <pre>
158 Scale matrix (Any Order):
159 x 0 0 0
160 0 y 0 0
161 0 0 z 0
162 0 0 0 1
163 * </pre>
164 * <p>
165 * All matrix fields are only set if <code>initM</code> is <code>true</code>.
166 * </p>
167 * @param m 4x4 matrix in column-major order (also result)
168 * @param initM if true, given matrix will be initialized w/ identity matrix,
169 * otherwise only the diagonal and last-row is set.
170 * The latter can be utilized to share a once {@link #makeIdentity(float[], int) identity set} matrix
171 * for {@link #makeScale(float[], int, boolean, float, float, float) scaling}
172 * and {@link #makeTranslation(float[], int, boolean, float, float, float) translation},
173 * while leaving the other fields untouched for performance reasons.
174 * @return given matrix for chaining
175 */
176 public static float[] makeScale(final float[] m, final boolean initM, final float sx, final float sy, final float sz) {
177 if( initM ) {
178 makeIdentity(m);
179 } else {
180 m[0+4*3] = 0;
181 m[1+4*3] = 0;
182 m[2+4*3] = 0;
183 m[3+4*3] = 1;
184 }
185 m[0+4*0] = sx;
186 m[1+4*1] = sy;
187 m[2+4*2] = sz;
188 return m;
189 }
190
191 /**
192 * Make given matrix the frustum matrix based on given parameters.
193 * <pre>
194 Frustum matrix (Column Order):
195 2*zNear/dx 0 0 0
196 0 2*zNear/dy 0 0
197 A B C -1
198 0 0 D 0
199 * </pre>
200 * <p>
201 * All matrix fields are only set if <code>initM</code> is <code>true</code>.
202 * </p>
203 *
204 * @param m 4x4 matrix in column-major order (also result)
205 * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
206 * @param initM if true, given matrix will be initialized w/ identity matrix,
207 * otherwise only the frustum fields are set.
208 * @param left
209 * @param right
210 * @param bottom
211 * @param top
212 * @param zNear
213 * @param zFar
214 * @return given matrix for chaining
215 * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear}
216 * or {@code left == right}, or {@code bottom == top}.
217 */
218 public static float[] makeFrustum(final float[] m, final int m_offset, final boolean initM,
219 final float left, final float right,
220 final float bottom, final float top,
221 final float zNear, final float zFar) throws GLException {
222 if( zNear <= 0.0f || zFar <= zNear ) {
223 throw new GLException("Requirements zNear > 0 and zFar > zNear, but zNear "+zNear+", zFar "+zFar);
224 }
225 if( left == right || top == bottom) {
226 throw new GLException("GL_INVALID_VALUE: top,bottom and left,right must not be equal");
227 }
228 if( initM ) {
229 // m[m_offset+0+4*0] = 1f;
230 m[m_offset+1+4*0] = 0f;
231 m[m_offset+2+4*0] = 0f;
232 m[m_offset+3+4*0] = 0f;
233
234 m[m_offset+0+4*1] = 0f;
235 // m[m_offset+1+4*1] = 1f;
236 m[m_offset+2+4*1] = 0f;
237 m[m_offset+3+4*1] = 0f;
238
239 // m[m_offset+0+4*2] = 0f;
240 // m[m_offset+1+4*2] = 0f;
241 // m[m_offset+2+4*2] = 1f;
242 // m[m_offset+3+4*2] = 0f;
243
244 m[m_offset+0+4*3] = 0f;
245 m[m_offset+1+4*3] = 0f;
246 // m[m_offset+2+4*3] = 0f;
247 // m[m_offset+3+4*3] = 1f;
248 }
249 final float zNear2 = 2.0f*zNear;
250 final float dx=right-left;
251 final float dy=top-bottom;
252 final float dz=zFar-zNear;
253 final float A=(right+left)/dx;
254 final float B=(top+bottom)/dy;
255 final float C=-1.0f*(zFar+zNear)/dz;
256 final float D=-2.0f*(zFar*zNear)/dz;
257
258 m[m_offset+0+4*0] = zNear2/dx;
259
260 m[m_offset+1+4*1] = zNear2/dy;
261
262 m[m_offset+0+4*2] = A;
263 m[m_offset+1+4*2] = B;
264 m[m_offset+2+4*2] = C;
265 m[m_offset+3+4*2] = -1.0f;
266
267 m[m_offset+2+4*3] = D;
268 m[m_offset+3+4*3] = 0f;
269
270 return m;
271 }
272
273 /**
274 * Make given matrix the perspective {@link #makeFrustum(float[], int, boolean, float, float, float, float, float, float) frustum}
275 * matrix based on given parameters.
276 * <p>
277 * All matrix fields are only set if <code>initM</code> is <code>true</code>.
278 * </p>
279 *
280 * @param m 4x4 matrix in column-major order (also result)
281 * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
282 * @param initM if true, given matrix will be initialized w/ identity matrix,
283 * otherwise only the frustum fields are set.
284 * @param fovy_rad angle in radians
285 * @param aspect aspect ratio width / height
286 * @param zNear
287 * @param zFar
288 * @return given matrix for chaining
289 * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear}
290 * @see #makeFrustum(float[], int, boolean, float, float, float, float, float, float)
291 */
292 public static float[] makePerspective(final float[] m, final int m_off, final boolean initM,
293 final float fovy_rad, final float aspect, final float zNear, final float zFar) throws GLException {
294 final float top = tan(fovy_rad/2f) * zNear; // use tangent of half-fov !
295 final float bottom = -1.0f * top; // -1f * fovhvTan.top * zNear
296 final float left = aspect * bottom; // aspect * -1f * fovhvTan.top * zNear
297 final float right = aspect * top; // aspect * fovhvTan.top * zNear
298 return makeFrustum(m, m_off, initM, left, right, bottom, top, zNear, zFar);
299 }
300
301 /**
302 * Make given matrix the <i>look-at</i> matrix based on given parameters.
303 * <p>
304 * Consist out of two matrix multiplications:
305 * <pre>
306 * <b>R</b> = <b>L</b> x <b>T</b>,
307 * with <b>L</b> for <i>look-at</i> matrix and
308 * <b>T</b> for eye translation.
309 *
310 * Result <b>R</b> can be utilized for <i>modelview</i> multiplication, i.e.
311 * <b>M</b> = <b>M</b> x <b>R</b>,
312 * with <b>M</b> being the <i>modelview</i> matrix.
313 * </pre>
314 * </p>
315 * <p>
316 * All matrix fields are set.
317 * </p>
318 * @param m 4x4 matrix in column-major order, result only
319 * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
320 * @param eye 3 component eye vector
321 * @param eye_offset
322 * @param center 3 component center vector
323 * @param center_offset
324 * @param up 3 component up vector
325 * @param up_offset
326 * @param mat4Tmp temp float[16] storage
327 * @return given matrix <code>m</code> for chaining
328 */
329 public static float[] makeLookAt(final float[] m, final int m_offset,
330 final float[] eye, final int eye_offset,
331 final float[] center, final int center_offset,
332 final float[] up, final int up_offset,
333 final float[] mat4Tmp) {
334 final int forward_off = 0;
335 final int side_off = 3;
336 final int up2_off = 6;
337
338 // forward!
339 mat4Tmp[0] = center[0+center_offset] - eye[0+eye_offset];
340 mat4Tmp[1] = center[1+center_offset] - eye[1+eye_offset];
341 mat4Tmp[2] = center[2+center_offset] - eye[2+eye_offset];
342
343 VectorUtil.normalizeVec3(mat4Tmp); // normalize forward
344
345 /* Side = forward x up */
346 VectorUtil.crossVec3(mat4Tmp, side_off, mat4Tmp, forward_off, up, up_offset);
347 VectorUtil.normalizeVec3(mat4Tmp, side_off); // normalize side
348
349 /* Recompute up as: up = side x forward */
350 VectorUtil.crossVec3(mat4Tmp, up2_off, mat4Tmp, side_off, mat4Tmp, forward_off);
351
352 m[m_offset + 0 * 4 + 0] = mat4Tmp[0+side_off]; // side
353 m[m_offset + 0 * 4 + 1] = mat4Tmp[0+up2_off]; // up2
354 m[m_offset + 0 * 4 + 2] = -mat4Tmp[0]; // forward
355 m[m_offset + 0 * 4 + 3] = 0;
356
357 m[m_offset + 1 * 4 + 0] = mat4Tmp[1+side_off]; // side
358 m[m_offset + 1 * 4 + 1] = mat4Tmp[1+up2_off]; // up2
359 m[m_offset + 1 * 4 + 2] = -mat4Tmp[1]; // forward
360 m[m_offset + 1 * 4 + 3] = 0;
361
362 m[m_offset + 2 * 4 + 0] = mat4Tmp[2+side_off]; // side
363 m[m_offset + 2 * 4 + 1] = mat4Tmp[2+up2_off]; // up2
364 m[m_offset + 2 * 4 + 2] = -mat4Tmp[2]; // forward
365 m[m_offset + 2 * 4 + 3] = 0;
366
367 m[m_offset + 3 * 4 + 0] = 0;
368 m[m_offset + 3 * 4 + 1] = 0;
369 m[m_offset + 3 * 4 + 2] = 0;
370 m[m_offset + 3 * 4 + 3] = 1;
371
372 makeTranslation(mat4Tmp, true, -eye[0+eye_offset], -eye[1+eye_offset], -eye[2+eye_offset]);
373 multMatrix(m, m_offset, mat4Tmp, 0);
374
375 return m;
376 }
377
378 /**
379 * Make given matrix the <i>pick</i> matrix based on given parameters.
380 * <p>
381 * Traditional <code>gluPickMatrix</code> implementation.
382 * </p>
383 * <p>
384 * Consist out of two matrix multiplications:
385 * <pre>
386 * <b>R</b> = <b>T</b> x <b>S</b>,
387 * with <b>T</b> for viewport translation matrix and
388 * <b>S</b> for viewport scale matrix.
389 *
390 * Result <b>R</b> can be utilized for <i>projection</i> multiplication, i.e.
391 * <b>P</b> = <b>P</b> x <b>R</b>,
392 * with <b>P</b> being the <i>projection</i> matrix.
393 * </pre>
394 * </p>
395 * <p>
396 * To effectively use the generated pick matrix for picking,
397 * call {@link #makePick(float[], int, float, float, float, float, int[], int, float[]) makePick}
398 * and multiply a {@link #makePerspective(float[], int, boolean, float, float, float, float) custom perspective matrix}
399 * by this pick matrix. Then you may load the result onto the perspective matrix stack.
400 * </p>
401 * <p>
402 * All matrix fields are set.
403 * </p>
404 * @param m 4x4 matrix in column-major order, result only
405 * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix
406 * @param x the center x-component of a picking region in window coordinates
407 * @param y the center y-component of a picking region in window coordinates
408 * @param deltaX the width of the picking region in window coordinates.
409 * @param deltaY the height of the picking region in window coordinates.
410 * @param viewport 4 component viewport vector
411 * @param viewport_offset
412 * @param mat4Tmp temp float[16] storage
413 * @return given matrix <code>m</code> for chaining or <code>null</code> if either delta value is <= zero.
414 */
415 public static float[] makePick(final float[] m,
416 final float x, final float y,
417 final float deltaX, final float deltaY,
418 final int[] viewport, final int viewport_offset,
419 final float[] mat4Tmp) {
420 if (deltaX <= 0 || deltaY <= 0) {
421 return null;
422 }
423
424 /* Translate and scale the picked region to the entire window */
425 makeTranslation(m, true,
426 (viewport[2+viewport_offset] - 2 * (x - viewport[0+viewport_offset])) / deltaX,
427 (viewport[3+viewport_offset] - 2 * (y - viewport[1+viewport_offset])) / deltaY,
428 0);
429 makeScale(mat4Tmp, true,
430 viewport[2+viewport_offset] / deltaX, viewport[3+viewport_offset] / deltaY, 1.0f);
431 multMatrix(m, mat4Tmp);
432 return m;
433 }
434
435 /**
436 * Transpose the given matrix.
437 *
438 * @param msrc 4x4 matrix in column-major order, the source
439 * @param mres 4x4 matrix in column-major order, the result
440 * @return given result matrix <i>mres</i> for chaining
441 */
442 public static float[] transposeMatrix(final float[] msrc, final float[] mres) {
443 mres[0] = msrc[0*4];
444 mres[1] = msrc[1*4];
445 mres[2] = msrc[2*4];
446 mres[3] = msrc[3*4];
447
448 final int i4_1 = 1*4;
449 mres[0+i4_1] = msrc[1+0*4];
450 mres[1+i4_1] = msrc[1+1*4];
451 mres[2+i4_1] = msrc[1+2*4];
452 mres[3+i4_1] = msrc[1+3*4];
453
454 final int i4_2 = 2*4;
455 mres[0+i4_2] = msrc[2+0*4];
456 mres[1+i4_2] = msrc[2+1*4];
457 mres[2+i4_2] = msrc[2+2*4];
458 mres[3+i4_2] = msrc[2+3*4];
459
460 final int i4_3 = 3*4;
461 mres[0+i4_3] = msrc[3+0*4];
462 mres[1+i4_3] = msrc[3+1*4];
463 mres[2+i4_3] = msrc[3+2*4];
464 mres[3+i4_3] = msrc[3+3*4];
465
466 return mres;
467 }
468
469 /**
470 * Returns the determinant of the given matrix
471 * @param m 4x4 matrix in column-major order, the source
472 * @return the matrix determinant
473 */
474 public static float matrixDeterminant(final float[] m) {
475 float a11 = m[ 1+4*1 ];
476 float a21 = m[ 2+4*1 ];
477 float a31 = m[ 3+4*1 ];
478 float a12 = m[ 1+4*2 ];
479 float a22 = m[ 2+4*2 ];
480 float a32 = m[ 3+4*2 ];
481 float a13 = m[ 1+4*3 ];
482 float a23 = m[ 2+4*3 ];
483 float a33 = m[ 3+4*3 ];
484
485 float ret = 0;
486 ret += m[ 0 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31));
487 a11 = m[ 1+4*0 ];
488 a21 = m[ 2+4*0 ];
489 a31 = m[ 3+4*0 ];
490 ret -= m[ 0+4*1 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31));
491 a12 = m[ 1+4*1 ];
492 a22 = m[ 2+4*1 ];
493 a32 = m[ 3+4*1 ];
494 ret += m[ 0+4*2 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31));
495 a13 = m[ 1+4*2 ];
496 a23 = m[ 2+4*2 ];
497 a33 = m[ 3+4*2 ];
498 ret -= m[ 0+4*3 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31));
499 return ret;
500 }
501 /**
502 * Invert the given matrix.
503 * <p>
504 * Returns <code>null</code> if inversion is not possible,
505 * e.g. matrix is singular due to a bad matrix.
506 * </p>
507 *
508 * @param msrc 4x4 matrix in column-major order, the source
509 * @param mres 4x4 matrix in column-major order, the result - may be <code>msrc</code> (in-place)
510 * @return given result matrix <i>mres</i> for chaining if successful, otherwise <code>null</code>. See above.
511 */
512 public static float[] invertMatrix(final float[] msrc, final float[] mres) {
513 final float scale;
514 {
515 float max = Math.abs(msrc[0]);
516
517 for( int i = 1; i < 16; i++ ) {
518 final float a = Math.abs(msrc[i]);
519 if( a > max ) max = a;
520 }
521 if( 0 == max ) {
522 return null;
523 }
524 scale = 1.0f/max;
525 }
526
527 final float a11 = msrc[0+4*0]*scale;
528 final float a21 = msrc[1+4*0]*scale;
529 final float a31 = msrc[2+4*0]*scale;
530 final float a41 = msrc[3+4*0]*scale;
531 final float a12 = msrc[0+4*1]*scale;
532 final float a22 = msrc[1+4*1]*scale;
533 final float a32 = msrc[2+4*1]*scale;
534 final float a42 = msrc[3+4*1]*scale;
535 final float a13 = msrc[0+4*2]*scale;
536 final float a23 = msrc[1+4*2]*scale;
537 final float a33 = msrc[2+4*2]*scale;
538 final float a43 = msrc[3+4*2]*scale;
539 final float a14 = msrc[0+4*3]*scale;
540 final float a24 = msrc[1+4*3]*scale;
541 final float a34 = msrc[2+4*3]*scale;
542 final float a44 = msrc[3+4*3]*scale;
543
544 final float m11 = + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42);
545 final float m12 = -( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41));
546 final float m13 = + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41);
547 final float m14 = -( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41));
548 final float m21 = -( + a12*(a33*a44 - a34*a43) - a13*(a32*a44 - a34*a42) + a14*(a32*a43 - a33*a42));
549 final float m22 = + a11*(a33*a44 - a34*a43) - a13*(a31*a44 - a34*a41) + a14*(a31*a43 - a33*a41);
550 final float m23 = -( + a11*(a32*a44 - a34*a42) - a12*(a31*a44 - a34*a41) + a14*(a31*a42 - a32*a41));
551 final float m24 = + a11*(a32*a43 - a33*a42) - a12*(a31*a43 - a33*a41) + a13*(a31*a42 - a32*a41);
552 final float m31 = + a12*(a23*a44 - a24*a43) - a13*(a22*a44 - a24*a42) + a14*(a22*a43 - a23*a42);
553 final float m32 = -( + a11*(a23*a44 - a24*a43) - a13*(a21*a44 - a24*a41) + a14*(a21*a43 - a23*a41));
554 final float m33 = + a11*(a22*a44 - a24*a42) - a12*(a21*a44 - a24*a41) + a14*(a21*a42 - a22*a41);
555 final float m34 = -( + a11*(a22*a43 - a23*a42) - a12*(a21*a43 - a23*a41) + a13*(a21*a42 - a22*a41));
556 final float m41 = -( + a12*(a23*a34 - a24*a33) - a13*(a22*a34 - a24*a32) + a14*(a22*a33 - a23*a32));
557 final float m42 = + a11*(a23*a34 - a24*a33) - a13*(a21*a34 - a24*a31) + a14*(a21*a33 - a23*a31);
558 final float m43 = -( + a11*(a22*a34 - a24*a32) - a12*(a21*a34 - a24*a31) + a14*(a21*a32 - a22*a31));
559 final float m44 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31);
560
561 final float det = (a11*m11 + a12*m12 + a13*m13 + a14*m14)/scale;
562 if( 0 == det ) {
563 return null;
564 }
565 final float invdet = 1.0f / det;
566
567 mres[0+4*0] = m11 * invdet;
568 mres[1+4*0] = m12 * invdet;
569 mres[2+4*0] = m13 * invdet;
570 mres[3+4*0] = m14 * invdet;
571 mres[0+4*1] = m21 * invdet;
572 mres[1+4*1] = m22 * invdet;
573 mres[2+4*1] = m23 * invdet;
574 mres[3+4*1] = m24 * invdet;
575 mres[0+4*2] = m31 * invdet;
576 mres[1+4*2] = m32 * invdet;
577 mres[2+4*2] = m33 * invdet;
578 mres[3+4*2] = m34 * invdet;
579 mres[0+4*3] = m41 * invdet;
580 mres[1+4*3] = m42 * invdet;
581 mres[2+4*3] = m43 * invdet;
582 mres[3+4*3] = m44 * invdet;
583 return mres;
584 }
585
586 /**
587 * Map object coordinates to window coordinates.
588 * <p>
589 * Traditional <code>gluProject</code> implementation.
590 * </p>
591 *
592 * @param objx
593 * @param objy
594 * @param objz
595 * @param modelMatrix 4x4 modelview matrix
596 * @param modelMatrix_offset
597 * @param projMatrix 4x4 projection matrix
598 * @param projMatrix_offset
599 * @param viewport 4 component viewport vector
600 * @param viewport_offset
601 * @param win_pos 3 component window coordinate, the result
602 * @param win_pos_offset
603 * @param vec4Tmp1 4 component vector for temp storage
604 * @param vec4Tmp2 4 component vector for temp storage
605 * @return true if successful, otherwise false (z is 1)
606 */
607 public static boolean mapObjToWin(final float objx, final float objy, final float objz,
608 final float[] modelMatrix, final int modelMatrix_offset,
609 final float[] projMatrix, final int projMatrix_offset,
610 final int[] viewport, final int viewport_offset,
611 final float[] win_pos, final int win_pos_offset,
612 final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
613 vec4Tmp1[0] = objx;
614 vec4Tmp1[1] = objy;
615 vec4Tmp1[2] = objz;
616 vec4Tmp1[3] = 1.0f;
617
618 // vec4Tmp2 = Mv * o
619 // vec4Tmp1 = P * vec4Tmp2
620 // vec4Tmp1 = P * ( Mv * o )
621 // vec4Tmp1 = P * Mv * o
622 multMatrixVec(modelMatrix, modelMatrix_offset, vec4Tmp1, 0, vec4Tmp2, 0);
623 multMatrixVec(projMatrix, projMatrix_offset, vec4Tmp2, 0, vec4Tmp1, 0);
624
625 if (vec4Tmp1[3] == 0.0f) {
626 return false;
627 }
628
629 vec4Tmp1[3] = (1.0f / vec4Tmp1[3]) * 0.5f;
630
631 // Map x, y and z to range 0-1
632 vec4Tmp1[0] = vec4Tmp1[0] * vec4Tmp1[3] + 0.5f;
633 vec4Tmp1[1] = vec4Tmp1[1] * vec4Tmp1[3] + 0.5f;
634 vec4Tmp1[2] = vec4Tmp1[2] * vec4Tmp1[3] + 0.5f;
635
636 // Map x,y to viewport
637 win_pos[0+win_pos_offset] = vec4Tmp1[0] * viewport[2+viewport_offset] + viewport[0+viewport_offset];
638 win_pos[1+win_pos_offset] = vec4Tmp1[1] * viewport[3+viewport_offset] + viewport[1+viewport_offset];
639 win_pos[2+win_pos_offset] = vec4Tmp1[2];
640
641 return true;
642 }
643
644 /**
645 * Map window coordinates to object coordinates.
646 * <p>
647 * Traditional <code>gluUnProject</code> implementation.
648 * </p>
649 *
650 * @param winx
651 * @param winy
652 * @param winz
653 * @param modelMatrix 4x4 modelview matrix
654 * @param modelMatrix_offset
655 * @param projMatrix 4x4 projection matrix
656 * @param projMatrix_offset
657 * @param viewport 4 component viewport vector
658 * @param viewport_offset
659 * @param obj_pos 3 component object coordinate, the result
660 * @param obj_pos_offset
661 * @param mat4Tmp1 16 component matrix for temp storage
662 * @param mat4Tmp2 16 component matrix for temp storage
663 * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
664 */
665 public static boolean mapWinToObj(final float winx, final float winy, final float winz,
666 final float[] modelMatrix, final int modelMatrix_offset,
667 final float[] projMatrix, final int projMatrix_offset,
668 final int[] viewport, final int viewport_offset,
669 final float[] obj_pos, final int obj_pos_offset,
670 final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) {
671 // mat4Tmp1 = P x Mv
672 multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0);
673
674 // mat4Tmp1 = Inv(P x Mv)
675 if ( null == invertMatrix(mat4Tmp1, mat4Tmp1) ) {
676 return false;
677 }
678 mat4Tmp2[0] = winx;
679 mat4Tmp2[1] = winy;
680 mat4Tmp2[2] = winz;
681 mat4Tmp2[3] = 1.0f;
682
683 // Map x and y from window coordinates
684 mat4Tmp2[0] = (mat4Tmp2[0] - viewport[0+viewport_offset]) / viewport[2+viewport_offset];
685 mat4Tmp2[1] = (mat4Tmp2[1] - viewport[1+viewport_offset]) / viewport[3+viewport_offset];
686
687 // Map to range -1 to 1
688 mat4Tmp2[0] = mat4Tmp2[0] * 2 - 1;
689 mat4Tmp2[1] = mat4Tmp2[1] * 2 - 1;
690 mat4Tmp2[2] = mat4Tmp2[2] * 2 - 1;
691
692 final int raw_off = 4;
693 // object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2
694 multMatrixVec(mat4Tmp1, 0, mat4Tmp2, 0, mat4Tmp2, raw_off);
695
696 if (mat4Tmp2[3+raw_off] == 0.0) {
697 return false;
698 }
699
700 mat4Tmp2[3+raw_off] = 1.0f / mat4Tmp2[3+raw_off];
701
702 obj_pos[0+obj_pos_offset] = mat4Tmp2[0+raw_off] * mat4Tmp2[3+raw_off];
703 obj_pos[1+obj_pos_offset] = mat4Tmp2[1+raw_off] * mat4Tmp2[3+raw_off];
704 obj_pos[2+obj_pos_offset] = mat4Tmp2[2+raw_off] * mat4Tmp2[3+raw_off];
705
706 return true;
707 }
708
709 /**
710 * Map window coordinates to object coordinates.
711 * <p>
712 * Traditional <code>gluUnProject4</code> implementation.
713 * </p>
714 *
715 * @param winx
716 * @param winy
717 * @param winz
718 * @param clipw
719 * @param modelMatrix 4x4 modelview matrix
720 * @param modelMatrix_offset
721 * @param projMatrix 4x4 projection matrix
722 * @param projMatrix_offset
723 * @param viewport 4 component viewport vector
724 * @param viewport_offset
725 * @param near
726 * @param far
727 * @param obj_pos 4 component object coordinate, the result
728 * @param obj_pos_offset
729 * @param mat4Tmp1 16 component matrix for temp storage
730 * @param mat4Tmp2 16 component matrix for temp storage
731 * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
732 */
733 public static boolean mapWinToObj4(final float winx, final float winy, final float winz, final float clipw,
734 final float[] modelMatrix, final int modelMatrix_offset,
735 final float[] projMatrix, final int projMatrix_offset,
736 final int[] viewport, final int viewport_offset,
737 final float near, final float far,
738 final float[] obj_pos, final int obj_pos_offset,
739 final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) {
740 // mat4Tmp1 = P x Mv
741 multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0);
742
743 // mat4Tmp1 = Inv(P x Mv)
744 if ( null == invertMatrix(mat4Tmp1, mat4Tmp1) ) {
745 return false;
746 }
747
748 mat4Tmp2[0] = winx;
749 mat4Tmp2[1] = winy;
750 mat4Tmp2[2] = winz;
751 mat4Tmp2[3] = clipw;
752
753 // Map x and y from window coordinates
754 mat4Tmp2[0] = (mat4Tmp2[0] - viewport[0+viewport_offset]) / viewport[2+viewport_offset];
755 mat4Tmp2[1] = (mat4Tmp2[1] - viewport[1+viewport_offset]) / viewport[3+viewport_offset];
756 mat4Tmp2[2] = (mat4Tmp2[2] - near) / (far - near);
757
758 // Map to range -1 to 1
759 mat4Tmp2[0] = mat4Tmp2[0] * 2 - 1;
760 mat4Tmp2[1] = mat4Tmp2[1] * 2 - 1;
761 mat4Tmp2[2] = mat4Tmp2[2] * 2 - 1;
762
763 final int raw_off = 4;
764 // object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2
765 multMatrixVec(mat4Tmp1, 0, mat4Tmp2, 0, mat4Tmp2, raw_off);
766
767 if (mat4Tmp2[3+raw_off] == 0.0) {
768 return false;
769 }
770
771 obj_pos[0+obj_pos_offset] = mat4Tmp2[0+raw_off];
772 obj_pos[1+obj_pos_offset] = mat4Tmp2[1+raw_off];
773 obj_pos[2+obj_pos_offset] = mat4Tmp2[2+raw_off];
774 obj_pos[3+obj_pos_offset] = mat4Tmp2[3+raw_off];
775
776 return true;
777 }
778
779 /**
780 * Multiply matrix: [d] = [a] x [b]
781 * @param a 4x4 matrix in column-major order
782 * @param b 4x4 matrix in column-major order
783 * @param d result a*b in column-major order
784 */
785 public static void multMatrix(final float[] a, final int a_off, final float[] b, final int b_off, final float[] d, final int d_off) {
786 final float b00 = b[b_off+0+0*4];
787 final float b10 = b[b_off+1+0*4];
788 final float b20 = b[b_off+2+0*4];
789 final float b30 = b[b_off+3+0*4];
790 final float b01 = b[b_off+0+1*4];
791 final float b11 = b[b_off+1+1*4];
792 final float b21 = b[b_off+2+1*4];
793 final float b31 = b[b_off+3+1*4];
794 final float b02 = b[b_off+0+2*4];
795 final float b12 = b[b_off+1+2*4];
796 final float b22 = b[b_off+2+2*4];
797 final float b32 = b[b_off+3+2*4];
798 final float b03 = b[b_off+0+3*4];
799 final float b13 = b[b_off+1+3*4];
800 final float b23 = b[b_off+2+3*4];
801 final float b33 = b[b_off+3+3*4];
802
803 float ai0=a[a_off+ 0*4]; // row-0 of a
804 float ai1=a[a_off+ 1*4];
805 float ai2=a[a_off+ 2*4];
806 float ai3=a[a_off+ 3*4];
807 d[d_off+ 0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
808 d[d_off+ 1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
809 d[d_off+ 2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
810 d[d_off+ 3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
811
812 ai0=a[a_off+1+0*4]; // row-1 of a
813 ai1=a[a_off+1+1*4];
814 ai2=a[a_off+1+2*4];
815 ai3=a[a_off+1+3*4];
816 d[d_off+1+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
817 d[d_off+1+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
818 d[d_off+1+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
819 d[d_off+1+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
820
821 ai0=a[a_off+2+0*4]; // row-2 of a
822 ai1=a[a_off+2+1*4];
823 ai2=a[a_off+2+2*4];
824 ai3=a[a_off+2+3*4];
825 d[d_off+2+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
826 d[d_off+2+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
827 d[d_off+2+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
828 d[d_off+2+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
829
830 ai0=a[a_off+3+0*4]; // row-3 of a
831 ai1=a[a_off+3+1*4];
832 ai2=a[a_off+3+2*4];
833 ai3=a[a_off+3+3*4];
834 d[d_off+3+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
835 d[d_off+3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
836 d[d_off+3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
837 d[d_off+3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
838 }
839
840 /**
841 * Multiply matrix: [d] = [a] x [b]
842 * @param a 4x4 matrix in column-major order
843 * @param b 4x4 matrix in column-major order
844 * @param d result a*b in column-major order
845 * @return given result matrix <i>d</i> for chaining
846 */
847 public static float[] multMatrix(final float[] a, final float[] b, final float[] d) {
848 final float b00 = b[0+0*4];
849 final float b10 = b[1+0*4];
850 final float b20 = b[2+0*4];
851 final float b30 = b[3+0*4];
852 final float b01 = b[0+1*4];
853 final float b11 = b[1+1*4];
854 final float b21 = b[2+1*4];
855 final float b31 = b[3+1*4];
856 final float b02 = b[0+2*4];
857 final float b12 = b[1+2*4];
858 final float b22 = b[2+2*4];
859 final float b32 = b[3+2*4];
860 final float b03 = b[0+3*4];
861 final float b13 = b[1+3*4];
862 final float b23 = b[2+3*4];
863 final float b33 = b[3+3*4];
864
865 float ai0=a[ 0*4]; // row-0 of a
866 float ai1=a[ 1*4];
867 float ai2=a[ 2*4];
868 float ai3=a[ 3*4];
869 d[ 0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
870 d[ 1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
871 d[ 2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
872 d[ 3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
873
874 ai0=a[1+0*4]; // row-1 of a
875 ai1=a[1+1*4];
876 ai2=a[1+2*4];
877 ai3=a[1+3*4];
878 d[1+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
879 d[1+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
880 d[1+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
881 d[1+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
882
883 ai0=a[2+0*4]; // row-2 of a
884 ai1=a[2+1*4];
885 ai2=a[2+2*4];
886 ai3=a[2+3*4];
887 d[2+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
888 d[2+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
889 d[2+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
890 d[2+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
891
892 ai0=a[3+0*4]; // row-3 of a
893 ai1=a[3+1*4];
894 ai2=a[3+2*4];
895 ai3=a[3+3*4];
896 d[3+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
897 d[3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
898 d[3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
899 d[3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
900
901 return d;
902 }
903
904 /**
905 * Multiply matrix: [a] = [a] x [b]
906 * @param a 4x4 matrix in column-major order (also result)
907 * @param b 4x4 matrix in column-major order
908 */
909 public static void multMatrix(final float[] a, final int a_off, final float[] b, final int b_off) {
910 final float b00 = b[b_off+0+0*4];
911 final float b10 = b[b_off+1+0*4];
912 final float b20 = b[b_off+2+0*4];
913 final float b30 = b[b_off+3+0*4];
914 final float b01 = b[b_off+0+1*4];
915 final float b11 = b[b_off+1+1*4];
916 final float b21 = b[b_off+2+1*4];
917 final float b31 = b[b_off+3+1*4];
918 final float b02 = b[b_off+0+2*4];
919 final float b12 = b[b_off+1+2*4];
920 final float b22 = b[b_off+2+2*4];
921 final float b32 = b[b_off+3+2*4];
922 final float b03 = b[b_off+0+3*4];
923 final float b13 = b[b_off+1+3*4];
924 final float b23 = b[b_off+2+3*4];
925 final float b33 = b[b_off+3+3*4];
926
927 float ai0=a[a_off+ 0*4]; // row-0 of a
928 float ai1=a[a_off+ 1*4];
929 float ai2=a[a_off+ 2*4];
930 float ai3=a[a_off+ 3*4];
931 a[a_off+ 0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
932 a[a_off+ 1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
933 a[a_off+ 2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
934 a[a_off+ 3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
935
936 ai0=a[a_off+1+0*4]; // row-1 of a
937 ai1=a[a_off+1+1*4];
938 ai2=a[a_off+1+2*4];
939 ai3=a[a_off+1+3*4];
940 a[a_off+1+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
941 a[a_off+1+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
942 a[a_off+1+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
943 a[a_off+1+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
944
945 ai0=a[a_off+2+0*4]; // row-2 of a
946 ai1=a[a_off+2+1*4];
947 ai2=a[a_off+2+2*4];
948 ai3=a[a_off+2+3*4];
949 a[a_off+2+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
950 a[a_off+2+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
951 a[a_off+2+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
952 a[a_off+2+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
953
954 ai0=a[a_off+3+0*4]; // row-3 of a
955 ai1=a[a_off+3+1*4];
956 ai2=a[a_off+3+2*4];
957 ai3=a[a_off+3+3*4];
958 a[a_off+3+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
959 a[a_off+3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
960 a[a_off+3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
961 a[a_off+3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
962 }
963
964 /**
965 * Multiply matrix: [a] = [a] x [b]
966 * @param a 4x4 matrix in column-major order (also result)
967 * @param b 4x4 matrix in column-major order
968 * @return given result matrix <i>a</i> for chaining
969 */
970 public static float[] multMatrix(final float[] a, final float[] b) {
971 final float b00 = b[0+0*4];
972 final float b10 = b[1+0*4];
973 final float b20 = b[2+0*4];
974 final float b30 = b[3+0*4];
975 final float b01 = b[0+1*4];
976 final float b11 = b[1+1*4];
977 final float b21 = b[2+1*4];
978 final float b31 = b[3+1*4];
979 final float b02 = b[0+2*4];
980 final float b12 = b[1+2*4];
981 final float b22 = b[2+2*4];
982 final float b32 = b[3+2*4];
983 final float b03 = b[0+3*4];
984 final float b13 = b[1+3*4];
985 final float b23 = b[2+3*4];
986 final float b33 = b[3+3*4];
987
988 float ai0=a[ 0*4]; // row-0 of a
989 float ai1=a[ 1*4];
990 float ai2=a[ 2*4];
991 float ai3=a[ 3*4];
992 a[ 0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
993 a[ 1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
994 a[ 2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
995 a[ 3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
996
997 ai0=a[1+0*4]; // row-1 of a
998 ai1=a[1+1*4];
999 ai2=a[1+2*4];
1000 ai3=a[1+3*4];
1001 a[1+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
1002 a[1+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
1003 a[1+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
1004 a[1+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
1005
1006 ai0=a[2+0*4]; // row-2 of a
1007 ai1=a[2+1*4];
1008 ai2=a[2+2*4];
1009 ai3=a[2+3*4];
1010 a[2+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
1011 a[2+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
1012 a[2+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
1013 a[2+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
1014
1015 ai0=a[3+0*4]; // row-3 of a
1016 ai1=a[3+1*4];
1017 ai2=a[3+2*4];
1018 ai3=a[3+3*4];
1019 a[3+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
1020 a[3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
1021 a[3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
1022 a[3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
1023
1024 return a;
1025 }
1026
1027 /**
1028 * Multiply matrix: [d] = [a] x [b]
1029 * @param a 4x4 matrix in column-major order
1030 * @param b 4x4 matrix in column-major order
1031 * @param d result a*b in column-major order
1032 */
1033 public static void multMatrix(final FloatBuffer a, final FloatBuffer b, final float[] d) {
1034 final int a_off = a.position();
1035 final int b_off = b.position();
1036 for (int i = 0; i < 4; i++) {
1037 // one row in column-major order
1038 final int a_off_i = a_off+i;
1039 final float ai0=a.get(a_off_i+0*4), ai1=a.get(a_off_i+1*4), ai2=a.get(a_off_i+2*4), ai3=a.get(a_off_i+3*4); // row-i of a
1040 d[i+0*4] = ai0 * b.get(b_off+0+0*4) + ai1 * b.get(b_off+1+0*4) + ai2 * b.get(b_off+2+0*4) + ai3 * b.get(b_off+3+0*4) ;
1041 d[i+1*4] = ai0 * b.get(b_off+0+1*4) + ai1 * b.get(b_off+1+1*4) + ai2 * b.get(b_off+2+1*4) + ai3 * b.get(b_off+3+1*4) ;
1042 d[i+2*4] = ai0 * b.get(b_off+0+2*4) + ai1 * b.get(b_off+1+2*4) + ai2 * b.get(b_off+2+2*4) + ai3 * b.get(b_off+3+2*4) ;
1043 d[i+3*4] = ai0 * b.get(b_off+0+3*4) + ai1 * b.get(b_off+1+3*4) + ai2 * b.get(b_off+2+3*4) + ai3 * b.get(b_off+3+3*4) ;
1044 }
1045 }
1046
1047 /**
1048 * Multiply matrix: [a] = [a] x [b]
1049 * @param a 4x4 matrix in column-major order (also result)
1050 * @param b 4x4 matrix in column-major order
1051 */
1052 public static void multMatrix(final FloatBuffer a, final FloatBuffer b) {
1053 final int a_off = a.position();
1054 final int b_off = b.position();
1055 for (int i = 0; i < 4; i++) {
1056 // one row in column-major order
1057 final int a_off_i = a_off+i;
1058 final float ai0=a.get(a_off_i+0*4), ai1=a.get(a_off_i+1*4), ai2=a.get(a_off_i+2*4), ai3=a.get(a_off_i+3*4); // row-i of a
1059 a.put(a_off_i+0*4 , ai0 * b.get(b_off+0+0*4) + ai1 * b.get(b_off+1+0*4) + ai2 * b.get(b_off+2+0*4) + ai3 * b.get(b_off+3+0*4) );
1060 a.put(a_off_i+1*4 , ai0 * b.get(b_off+0+1*4) + ai1 * b.get(b_off+1+1*4) + ai2 * b.get(b_off+2+1*4) + ai3 * b.get(b_off+3+1*4) );
1061 a.put(a_off_i+2*4 , ai0 * b.get(b_off+0+2*4) + ai1 * b.get(b_off+1+2*4) + ai2 * b.get(b_off+2+2*4) + ai3 * b.get(b_off+3+2*4) );
1062 a.put(a_off_i+3*4 , ai0 * b.get(b_off+0+3*4) + ai1 * b.get(b_off+1+3*4) + ai2 * b.get(b_off+2+3*4) + ai3 * b.get(b_off+3+3*4) );
1063 }
1064 }
1065
1066 /**
1067 * @param m_in 4x4 matrix in column-major order
1068 * @param m_in_off
1069 * @param v_in 4-component column-vector
1070 * @param v_out m_in * v_in
1071 */
1072 public static void multMatrixVec(final float[] m_in, final int m_in_off,
1073 final float[] v_in, final int v_in_off,
1074 final float[] v_out, final int v_out_off) {
1075 // (one matrix row in column-major order) X (column vector)
1076 v_out[0 + v_out_off] = v_in[0+v_in_off] * m_in[0*4+m_in_off ] + v_in[1+v_in_off] * m_in[1*4+m_in_off ] +
1077 v_in[2+v_in_off] * m_in[2*4+m_in_off ] + v_in[3+v_in_off] * m_in[3*4+m_in_off ];
1078
1079 final int m_in_off_1 = 1+m_in_off;
1080 v_out[1 + v_out_off] = v_in[0+v_in_off] * m_in[0*4+m_in_off_1] + v_in[1+v_in_off] * m_in[1*4+m_in_off_1] +
1081 v_in[2+v_in_off] * m_in[2*4+m_in_off_1] + v_in[3+v_in_off] * m_in[3*4+m_in_off_1];
1082
1083 final int m_in_off_2 = 2+m_in_off;
1084 v_out[2 + v_out_off] = v_in[0+v_in_off] * m_in[0*4+m_in_off_2] + v_in[1+v_in_off] * m_in[1*4+m_in_off_2] +
1085 v_in[2+v_in_off] * m_in[2*4+m_in_off_2] + v_in[3+v_in_off] * m_in[3*4+m_in_off_2];
1086
1087 final int m_in_off_3 = 3+m_in_off;
1088 v_out[3 + v_out_off] = v_in[0+v_in_off] * m_in[0*4+m_in_off_3] + v_in[1+v_in_off] * m_in[1*4+m_in_off_3] +
1089 v_in[2+v_in_off] * m_in[2*4+m_in_off_3] + v_in[3+v_in_off] * m_in[3*4+m_in_off_3];
1090 }
1091
1092 /**
1093 * @param m_in 4x4 matrix in column-major order
1094 * @param m_in_off
1095 * @param v_in 4-component column-vector
1096 * @param v_out m_in * v_in
1097 */
1098 public static void multMatrixVec(final float[] m_in, final int m_in_off,
1099 final float[] v_in, final float[] v_out) {
1100 // (one matrix row in column-major order) X (column vector)
1101 v_out[0] = v_in[0] * m_in[0*4+m_in_off ] + v_in[1] * m_in[1*4+m_in_off ] +
1102 v_in[2] * m_in[2*4+m_in_off ] + v_in[3] * m_in[3*4+m_in_off ];
1103
1104 final int m_in_off_1 = 1+m_in_off;
1105 v_out[1] = v_in[0] * m_in[0*4+m_in_off_1] + v_in[1] * m_in[1*4+m_in_off_1] +
1106 v_in[2] * m_in[2*4+m_in_off_1] + v_in[3] * m_in[3*4+m_in_off_1];
1107
1108 final int m_in_off_2 = 2+m_in_off;
1109 v_out[2] = v_in[0] * m_in[0*4+m_in_off_2] + v_in[1] * m_in[1*4+m_in_off_2] +
1110 v_in[2] * m_in[2*4+m_in_off_2] + v_in[3] * m_in[3*4+m_in_off_2];
1111
1112 final int m_in_off_3 = 3+m_in_off;
1113 v_out[3] = v_in[0] * m_in[0*4+m_in_off_3] + v_in[1] * m_in[1*4+m_in_off_3] +
1114 v_in[2] * m_in[2*4+m_in_off_3] + v_in[3] * m_in[3*4+m_in_off_3];
1115 }
1116
1117 /**
1118 * @param m_in 4x4 matrix in column-major order
1119 * @param m_in_off
1120 * @param v_in 4-component column-vector
1121 * @param v_out m_in * v_in
1122 * @return given result vector <i>v_out</i> for chaining
1123 */
1124 public static float[] multMatrixVec(final float[] m_in, final float[] v_in, final float[] v_out) {
1125 // (one matrix row in column-major order) X (column vector)
1126 v_out[0] = v_in[0] * m_in[0*4 ] + v_in[1] * m_in[1*4 ] +
1127 v_in[2] * m_in[2*4 ] + v_in[3] * m_in[3*4 ];
1128
1129 v_out[1] = v_in[0] * m_in[0*4+1] + v_in[1] * m_in[1*4+1] +
1130 v_in[2] * m_in[2*4+1] + v_in[3] * m_in[3*4+1];
1131
1132 v_out[2] = v_in[0] * m_in[0*4+2] + v_in[1] * m_in[1*4+2] +
1133 v_in[2] * m_in[2*4+2] + v_in[3] * m_in[3*4+2];
1134
1135 v_out[3] = v_in[0] * m_in[0*4+3] + v_in[1] * m_in[1*4+3] +
1136 v_in[2] * m_in[2*4+3] + v_in[3] * m_in[3*4+3];
1137
1138 return v_out;
1139 }
1140
1141 /**
1142 * @param m_in 4x4 matrix in column-major order
1143 * @param v_in 4-component column-vector
1144 * @param v_out m_in * v_in
1145 */
1146 public static void multMatrixVec(final FloatBuffer m_in, final float[] v_in, final float[] v_out) {
1147 final int m_in_off = m_in.position();
1148 for (int i = 0; i < 4; i++) {
1149 // (one matrix row in column-major order) X (column vector)
1150 final int i_m_in_off = i+m_in_off;
1151 v_out[i] =
1152 v_in[0] * m_in.get(0*4+i_m_in_off) +
1153 v_in[1] * m_in.get(1*4+i_m_in_off) +
1154 v_in[2] * m_in.get(2*4+i_m_in_off) +
1155 v_in[3] * m_in.get(3*4+i_m_in_off);
1156 }
1157 }
1158
1159 /**
1160 * Affine 3f-vector transformation by 4x4 matrix
1161 *
1162 * 4x4 matrix multiplication with 3-component vector,
1163 * using {@code 1} for for {@code v_in[3]} and dropping {@code v_out[3]},
1164 * which shall be {@code 1}.
1165 *
1166 * @param m_in 4x4 matrix in column-major order
1167 * @param m_in_off
1168 * @param v_in 3-component column-vector
1169 * @param v_out m_in * v_in, 3-component column-vector
1170 * @return given result vector <i>v_out</i> for chaining
1171 */
1172 public static float[] multMatrixVec3(final float[] m_in, final float[] v_in, final float[] v_out) {
1173 // (one matrix row in column-major order) X (column vector)
1174 v_out[0] = v_in[0] * m_in[0*4 ] + v_in[1] * m_in[1*4 ] +
1175 v_in[2] * m_in[2*4 ] + 1f * m_in[3*4 ];
1176
1177 v_out[1] = v_in[0] * m_in[0*4+1] + v_in[1] * m_in[1*4+1] +
1178 v_in[2] * m_in[2*4+1] + 1f * m_in[3*4+1];
1179
1180 v_out[2] = v_in[0] * m_in[0*4+2] + v_in[1] * m_in[1*4+2] +
1181 v_in[2] * m_in[2*4+2] + 1f * m_in[3*4+2];
1182
1183 return v_out;
1184 }
1185
1186 /**
1187 * @param sb optional passed StringBuilder instance to be used
1188 * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
1189 * @param a mxn matrix (rows x columns)
1190 * @param aOffset offset to <code>a</code>'s current position
1191 * @param rows
1192 * @param columns
1193 * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL)
1194 * @param row row number to print
1195 * @return matrix row string representation
1196 */
1197 public static StringBuilder matrixRowToString(StringBuilder sb, final String f,
1198 final FloatBuffer a, final int aOffset,
1199 final int rows, final int columns, final boolean rowMajorOrder, final int row) {
1200 if(null == sb) {
1201 sb = new StringBuilder();
1202 }
1203 final int a0 = aOffset + a.position();
1204 if(rowMajorOrder) {
1205 for(int c=0; c<columns; c++) {
1206 sb.append( String.format((Locale)null, f+", ", a.get( a0 + row*columns + c ) ) );
1207 }
1208 } else {
1209 for(int r=0; r<columns; r++) {
1210 sb.append( String.format((Locale)null, f+", ", a.get( a0 + row + r*rows ) ) );
1211 }
1212 }
1213 return sb;
1214 }
1215
1216 /**
1217 * @param sb optional passed StringBuilder instance to be used
1218 * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
1219 * @param a mxn matrix (rows x columns)
1220 * @param aOffset offset to <code>a</code>'s current position
1221 * @param rows
1222 * @param columns
1223 * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL)
1224 * @param row row number to print
1225 * @return matrix row string representation
1226 */
1227 public static StringBuilder matrixRowToString(StringBuilder sb, final String f,
1228 final float[] a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder, final int row) {
1229 if(null == sb) {
1230 sb = new StringBuilder();
1231 }
1232 if(rowMajorOrder) {
1233 for(int c=0; c<columns; c++) {
1234 sb.append( String.format((Locale)null, f+", ", a[ aOffset + row*columns + c ] ) );
1235 }
1236 } else {
1237 for(int r=0; r<columns; r++) {
1238 sb.append( String.format((Locale)null, f+", ", a[ aOffset + row + r*rows ] ) );
1239 }
1240 }
1241 return sb;
1242 }
1243
1244 /**
1245 * @param sb optional passed StringBuilder instance to be used
1246 * @param rowPrefix optional prefix for each row
1247 * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
1248 * @param a mxn matrix (rows x columns)
1249 * @param aOffset offset to <code>a</code>'s current position
1250 * @param rows
1251 * @param columns
1252 * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL)
1253 * @return matrix string representation
1254 */
1255 public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f,
1256 final FloatBuffer a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder) {
1257 if(null == sb) {
1258 sb = new StringBuilder();
1259 }
1260 final String prefix = ( null == rowPrefix ) ? "" : rowPrefix;
1261 sb.append(prefix).append("{ ");
1262 for(int i=0; i<rows; i++) {
1263 if( 0 < i ) {
1264 sb.append(prefix).append(" ");
1265 }
1266 matrixRowToString(sb, f, a, aOffset, rows, columns, rowMajorOrder, i);
1267 sb.append(System.lineSeparator());
1268 }
1269 sb.append(prefix).append("}").append(System.lineSeparator());
1270 return sb;
1271 }
1272
1273 /**
1274 * @param sb optional passed StringBuilder instance to be used
1275 * @param rowPrefix optional prefix for each row
1276 * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
1277 * @param a mxn matrix (rows x columns)
1278 * @param aOffset offset to <code>a</code>'s current position
1279 * @param rows
1280 * @param columns
1281 * @param rowMajorOrder if true floats are laid out in row-major-order, otherwise column-major-order (OpenGL)
1282 * @return matrix string representation
1283 */
1284 public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f,
1285 final float[] a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder) {
1286 if(null == sb) {
1287 sb = new StringBuilder();
1288 }
1289 final String prefix = ( null == rowPrefix ) ? "" : rowPrefix;
1290 sb.append(prefix).append("{ ");
1291 for(int i=0; i<rows; i++) {
1292 if( 0 < i ) {
1293 sb.append(prefix).append(" ");
1294 }
1295 matrixRowToString(sb, f, a, aOffset, rows, columns, rowMajorOrder, i);
1296 sb.append(System.lineSeparator());
1297 }
1298 sb.append(prefix).append("}").append(System.lineSeparator());
1299 return sb;
1300 }
1301
1302 //
1303 // Scalar Ops
1304 //
1305
1306 @SuppressWarnings("unused")
1307 private static void calculateMachineEpsilonFloat() {
1308 final long t0;
1309 if( DEBUG_EPSILON ) {
1310 t0 = Platform.currentTimeMillis();
1311 }
1312 float machEps = 1.0f;
1313 int i=0;
1314 do {
1315 machEps /= 2.0f;
1316 i++;
1317 } while (1.0f + (machEps / 2.0f) != 1.0f);
1318 machEpsilon = machEps;
1319 if( DEBUG_EPSILON ) {
1320 final long t1 = Platform.currentTimeMillis();
1321 System.err.println("MachineEpsilon: "+machEpsilon+", in "+i+" iterations within "+(t1-t0)+" ms");
1322 }
1323 }
1324 private static volatile boolean machEpsilonAvail = false;
1325 private static float machEpsilon = 0f;
1326 private static final boolean DEBUG_EPSILON = false;
1327
1328 /**
1329 * Return computed machine Epsilon value.
1330 * <p>
1331 * The machine Epsilon value is computed once.
1332 * </p>
1333 * <p>
1334 * On a reference machine the result was {@link #EPSILON} in 23 iterations.
1335 * </p>
1336 * @see #EPSILON
1337 */
1338 public static float getMachineEpsilon() {
1339 if( !machEpsilonAvail ) {
1340 synchronized(FloatUtil.class) {
1341 if( !machEpsilonAvail ) {
1342 machEpsilonAvail = true;
1343 calculateMachineEpsilonFloat();
1344 }
1345 }
1346 }
1347 return machEpsilon;
1348 }
1349
1350 public static final float E = 2.7182818284590452354f;
1351
1352 /** The value PI, i.e. 180 degrees in radians. */
1353 public static final float PI = 3.14159265358979323846f;
1354
1355 /** The value 2PI, i.e. 360 degrees in radians. */
1356 public static final float TWO_PI = 2f * PI;
1357
1358 /** The value PI/2, i.e. 90 degrees in radians. */
1359 public static final float HALF_PI = PI / 2f;
1360
1361 /** The value PI/4, i.e. 45 degrees in radians. */
1362 public static final float QUARTER_PI = PI / 4f;
1363
1364 /** The value PI^2. */
1365 public final static float SQUARED_PI = PI * PI;
1366
1367 /** Converts arc-degree to radians */
1368 public static float adegToRad(final float arc_degree) {
1369 return arc_degree * PI / 180.0f;
1370 }
1371
1372 /** Converts radians to arc-degree */
1373 public static float radToADeg(final float rad) {
1374 return rad * 180.0f / PI;
1375 }
1376
1377 /**
1378 * Epsilon for floating point {@value}, as once computed via {@link #getMachineEpsilon()} on an AMD-64 CPU.
1379 * <p>
1380 * Definition of machine epsilon guarantees that:
1381 * <pre>
1382 * 1.0f + EPSILON != 1.0f
1383 * </pre>
1384 * In other words: <i>machEps</i> is the maximum relative error of the chosen rounding procedure.
1385 * </p>
1386 * <p>
1387 * A number can be considered zero if it is in the range (or in the set):
1388 * <pre>
1389 * <b>MaybeZeroSet</b> e ]-<i>machEps</i> .. <i>machEps</i>[ <i>(exclusive)</i>
1390 * </pre>
1391 * While comparing floating point values, <i>machEps</i> allows to clip the relative error:
1392 * <pre>
1393 * boolean isZero = afloat < EPSILON;
1394 * boolean isNotZero = afloat >= EPSILON;
1395 *
1396 * boolean isEqual = abs(bfloat - afloat) < EPSILON;
1397 * boolean isNotEqual = abs(bfloat - afloat) >= EPSILON;
1398 * </pre>
1399 * </p>
1400 * @see #isEqual(float, float, float)
1401 * @see #isZero(float, float)
1402 */
1403 public static final float EPSILON = 1.1920929E-7f; // Float.MIN_VALUE == 1.4e-45f ; double EPSILON 2.220446049250313E-16d
1404
1405 /**
1406 * Inversion Epsilon, used with equals method to determine if two inverted matrices are close enough to be considered equal.
1407 * <p>
1408 * Using {@value}, which is ~100 times {@link FloatUtil#EPSILON}.
1409 * </p>
1410 */
1411 public static final float INV_DEVIANCE = 1.0E-5f; // FloatUtil.EPSILON == 1.1920929E-7f; double ALLOWED_DEVIANCE: 1.0E-8f
1412
1413 /** Signed bit 31 of IEEE 754 (IEC 559) single float-point bit layout, i.e. `0x80000000`. */
1414 public static final int IEC559_SIGN_BIT = 1 << 31; // 0x80000000;
1415
1416 /**
1417 * Returns true if both values are equal
1418 * disregarding {@link EPSILON} but considering {@code NaN}, {@code -Inf} and {@code +Inf}.
1419 * <p>
1420 * Implementation considers following corner cases:
1421 * <ul>
1422 * <li>NaN == NaN</li>
1423 * <li>+Inf == +Inf</li>
1424 * <li>-Inf == -Inf</li>
1425 * </ul>
1426 * </p>
1427 * @see #isEqual(float, float, float)
1428 */
1429 public static boolean isEqualRaw(final float a, final float b) {
1430 // Values are equal (Inf, Nan .. )
1431 return Float.floatToIntBits(a) == Float.floatToIntBits(b);
1432 }
1433
1434 /**
1435 * Returns true if both values are equal, i.e. their absolute delta < {@code epsilon},
1436 * considering {@code epsilon} and {@code NaN}, {@code -Inf} and {@code +Inf}.
1437 * <p>
1438 * {@code epsilon} must be > 0.
1439 * </p>
1440 * <p>
1441 * Implementation considers following corner cases:
1442 * <ul>
1443 * <li>NaN == NaN</li>
1444 * <li>+Inf == +Inf</li>
1445 * <li>-Inf == -Inf</li>
1446 * </ul>
1447 * </p>
1448 * @see #EPSILON
1449 */
1450 public static boolean isEqual(final float a, final float b, final float epsilon) {
1451 if( Math.abs(a - b) < epsilon ) {
1452 return true;
1453 } else {
1454 // Values are equal (Inf, Nan .. )
1455 return Float.floatToIntBits(a) == Float.floatToIntBits(b);
1456 }
1457 }
1458
1459 /**
1460 * Returns true if both values are equal, i.e. their absolute delta < {@link #EPSILON},
1461 * considering {@link EPSILON} and {@code NaN}, {@code -Inf} and {@code +Inf}.
1462 * <p>
1463 * Implementation considers following corner cases:
1464 * <ul>
1465 * <li>NaN == NaN</li>
1466 * <li>+Inf == +Inf</li>
1467 * <li>-Inf == -Inf</li>
1468 * </ul>
1469 * </p>
1470 * @see #EPSILON
1471 */
1472 public static boolean isEqual(final float a, final float b) {
1473 if ( Math.abs(a - b) < EPSILON ) {
1474 return true;
1475 } else {
1476 // Values are equal (Inf, Nan .. )
1477 return Float.floatToIntBits(a) == Float.floatToIntBits(b);
1478 }
1479 }
1480
1481 /**
1482 * Returns true if both values are equal, i.e. their absolute delta < {@link #EPSILON},
1483 * considering {@link EPSILON} but disregarding {@code NaN}, {@code -Inf} and {@code +Inf}.
1484 * <p>
1485 * Implementation does not consider corner cases like {@link #isEqual(float, float, float)}.
1486 * </p>
1487 * @see #EPSILON
1488 */
1489 public static boolean isEqual2(final float a, final float b) {
1490 return Math.abs(a - b) < EPSILON;
1491 }
1492
1493 /**
1494 * Returns {@code -1}, {@code 0} or {@code 1} if {@code a} is less, equal or greater than {@code b},
1495 * disregarding epsilon but considering {@code NaN}, {@code -Inf} and {@code +Inf}.
1496 * <p>
1497 * Implementation considers following corner cases:
1498 * <ul>
1499 * <li>NaN == NaN</li>
1500 * <li>+Inf == +Inf</li>
1501 * <li>-Inf == -Inf</li>
1502 * <li>NaN > 0</li>
1503 * <li>+Inf > -Inf</li>
1504 * </ul>
1505 * </p>
1506 * @see #compare(float, float, float)
1507 */
1508 public static int compare(final float a, final float b) {
1509 if (a < b) {
1510 return -1; // Neither is NaN, a is smaller
1511 }
1512 if (a > b) {
1513 return 1; // Neither is NaN, a is larger
1514 }
1515 final int aBits = Float.floatToIntBits(a);
1516 final int bBits = Float.floatToIntBits(b);
1517 if( aBits == bBits ) {
1518 return 0; // Values are equal (Inf, Nan .. )
1519 } else if( aBits < bBits ) {
1520 return -1; // (-0.0, 0.0) or (!NaN, NaN)
1521 } else {
1522 return 1; // ( 0.0, -0.0) or ( NaN, !NaN)
1523 }
1524 }
1525
1526 /**
1527 * Returns {@code -1}, {@code 0} or {@code 1} if {@code a} is less, equal or greater than {@code b},
1528 * considering epsilon and {@code NaN}, {@code -Inf} and {@code +Inf}.
1529 * <p>
1530 * {@code epsilon} must be > 0.
1531 * </p>
1532 * <p>
1533 * Implementation considers following corner cases:
1534 * <ul>
1535 * <li>NaN == NaN</li>
1536 * <li>+Inf == +Inf</li>
1537 * <li>-Inf == -Inf</li>
1538 * <li>NaN > 0</li>
1539 * <li>+Inf > -Inf</li>
1540 * </ul>
1541 * </p>
1542 * @see #EPSILON
1543 */
1544 public static int compare(final float a, final float b, final float epsilon) {
1545 if( Math.abs(a - b) < epsilon ) {
1546 return 0;
1547 } else {
1548 return compare(a, b);
1549 }
1550 }
1551
1552 /**
1553 * Returns true if value is zero, i.e. it's absolute value < {@code epsilon}.
1554 * <p>
1555 * {@code epsilon} must be > 0.
1556 * </p>
1557 * @param a value to test
1558 * @param epsilon optional positive epsilon value, must be > 0
1559 * @see #EPSILON
1560 */
1561 public static boolean isZero(final float a, final float epsilon) {
1562 return Math.abs(a) < epsilon;
1563 }
1564
1565 /**
1566 * Returns true if value is zero, i.e. it's absolute value < {@link #EPSILON}.
1567 * @see #EPSILON
1568 */
1569 public static boolean isZero(final float a) {
1570 return Math.abs(a) < FloatUtil.EPSILON;
1571 }
1572
1573 /**
1574 * Returns true if value is zero,
1575 * disregarding {@link EPSILON} but considering {@code NaN}, {@code -Inf} and {@code +Inf}.
1576 * <p>
1577 * Implementation considers following corner cases:
1578 * <ul>
1579 * <li>NaN == NaN</li>
1580 * <li>+Inf == +Inf</li>
1581 * <li>-Inf == -Inf</li>
1582 * </ul>
1583 * </p>
1584 */
1585 public static boolean isZeroRaw(final float a) {
1586 // Values are equal (Inf, Nan .. )
1587 return ( Float.floatToIntBits(a) & ~IEC559_SIGN_BIT ) == 0;
1588 }
1589
1590 /**
1591 * Invokes {@link Math#abs(float)}
1592 * @param a float to process
1593 * @return absolute value of {@code a}
1594 * @deprecated use {@link Math#abs(float)} directly
1595 */
1596 @Deprecated
1597 public static float abs(final float a) { return java.lang.Math.abs(a); }
1598
1599 public static float pow(final float a, final float b) { return (float) java.lang.Math.pow(a, b); }
1600
1601 public static float sin(final float a) { return (float) java.lang.Math.sin(a); }
1602
1603 public static float asin(final float a) { return (float) java.lang.Math.asin(a); }
1604
1605 public static float cos(final float a) { return (float) java.lang.Math.cos(a); }
1606
1607 public static float acos(final float a) { return (float) java.lang.Math.acos(a); }
1608
1609 public static float tan(final float a) { return (float) java.lang.Math.tan(a); }
1610
1611 public static float atan(final float a) { return (float) java.lang.Math.atan(a); }
1612
1613 public static float atan2(final float y, final float x) { return (float) java.lang.Math.atan2(y, x); }
1614
1615 public static float sqrt(final float a) { return (float) java.lang.Math.sqrt(a); }
1616
1617 /**
1618 * Returns resolution of Z buffer of given parameter,
1619 * see <a href="http://www.sjbaker.org/steve/omniv/love_your_z_buffer.html">Love Your Z-Buffer</a>.
1620 * <pre>
1621 * return z * z / ( zNear * (1&lt;&lt;zBits) - z )
1622 * </pre>
1623 * Examples:
1624 * <pre>
1625 * 1.5256461E-4 = 16 zBits, -0.2 zDist, 0.1 zNear
1626 * 6.1033297E-6 = 16 zBits, -1.0 zDist, 0.1 zNear
1627 * </pre>
1628 * @param zBits number of bits of Z precision, i.e. z-buffer depth
1629 * @param z distance from the eye to the object
1630 * @param zNear distance from eye to near clip plane
1631 * @return smallest resolvable Z separation at this range.
1632 */
1633 public static float getZBufferEpsilon(final int zBits, final float z, final float zNear) {
1634 return z * z / ( zNear * ( 1 << zBits ) - z );
1635 }
1636
1637 /**
1638 * Returns Z buffer value of given parameter,
1639 * see <a href="http://www.sjbaker.org/steve/omniv/love_your_z_buffer.html">Love Your Z-Buffer</a>.
1640 * <pre>
1641 * float a = zFar / ( zFar - zNear )
1642 * float b = zFar * zNear / ( zNear - zFar )
1643 * return (int) ( (1&lt;&lt;zBits) * ( a + b / z ) )
1644 * </pre>
1645 * @param zBits number of bits of Z precision, i.e. z-buffer depth
1646 * @param z distance from the eye to the object
1647 * @param zNear distance from eye to near clip plane
1648 * @param zFar distance from eye to far clip plane
1649 * @return z buffer value
1650 */
1651 public static int getZBufferValue(final int zBits, final float z, final float zNear, final float zFar) {
1652 final float a = zFar / ( zFar - zNear );
1653 final float b = zFar * zNear / ( zNear - zFar );
1654 return (int) ( (1<<zBits) * ( a + b / z ) );
1655 }
1656
1657 /**
1658 * Returns orthogonal distance
1659 * (1f/zNear-1f/orthoZ) / (1f/zNear-1f/zFar);
1660 */
1661 public static float getOrthoWinZ(final float orthoZ, final float zNear, final float zFar) {
1662 return (1f/zNear-1f/orthoZ) / (1f/zNear-1f/zFar);
1663 }
1664
1665}
Basic Float math utility functions.
Definition: FloatUtil.java:83
static boolean isEqualRaw(final float a, final float b)
Returns true if both values are equal disregarding EPSILON but considering NaN, -Inf and +Inf.
static int compare(final float a, final float b)
Returns -1, 0 or 1 if a is less, equal or greater than b, disregarding epsilon but considering NaN,...
static boolean mapWinToObj4(final float winx, final float winy, final float winz, final float clipw, final float[] modelMatrix, final int modelMatrix_offset, final float[] projMatrix, final int projMatrix_offset, final int[] viewport, final int viewport_offset, final float near, final float far, final float[] obj_pos, final int obj_pos_offset, final float[] mat4Tmp1, final float[] mat4Tmp2)
Map window coordinates to object coordinates.
Definition: FloatUtil.java:733
static float getOrthoWinZ(final float orthoZ, final float zNear, final float zFar)
Returns orthogonal distance (1f/zNear-1f/orthoZ) / (1f/zNear-1f/zFar);.
static final float TWO_PI
The value 2PI, i.e.
static float getZBufferEpsilon(final int zBits, final float z, final float zNear)
Returns resolution of Z buffer of given parameter, see Love Your Z-Buffer.
static float acos(final float a)
static float sin(final float a)
static float[] makeLookAt(final float[] m, final int m_offset, final float[] eye, final int eye_offset, final float[] center, final int center_offset, final float[] up, final int up_offset, final float[] mat4Tmp)
Make given matrix the look-at matrix based on given parameters.
Definition: FloatUtil.java:329
static final float QUARTER_PI
The value PI/4, i.e.
static float atan(final float a)
static boolean mapObjToWin(final float objx, final float objy, final float objz, final float[] modelMatrix, final int modelMatrix_offset, final float[] projMatrix, final int projMatrix_offset, final int[] viewport, final int viewport_offset, final float[] win_pos, final int win_pos_offset, final float[] vec4Tmp1, final float[] vec4Tmp2)
Map object coordinates to window coordinates.
Definition: FloatUtil.java:607
static boolean isZero(final float a)
Returns true if value is zero, i.e.
static final int IEC559_SIGN_BIT
Signed bit 31 of IEEE 754 (IEC 559) single float-point bit layout, i.e.
static float[] makeScale(final float[] m, final boolean initM, final float sx, final float sy, final float sz)
Make a scale matrix in column-major order from the given axis factors.
Definition: FloatUtil.java:176
static final float PI
The value PI, i.e.
static void multMatrix(final FloatBuffer a, final FloatBuffer b)
Multiply matrix: [a] = [a] x [b].
static float[] makePerspective(final float[] m, final int m_off, final boolean initM, final float fovy_rad, final float aspect, final float zNear, final float zFar)
Make given matrix the perspective frustum matrix based on given parameters.
Definition: FloatUtil.java:292
static float atan2(final float y, final float x)
static boolean mapWinToObj(final float winx, final float winy, final float winz, final float[] modelMatrix, final int modelMatrix_offset, final float[] projMatrix, final int projMatrix_offset, final int[] viewport, final int viewport_offset, final float[] obj_pos, final int obj_pos_offset, final float[] mat4Tmp1, final float[] mat4Tmp2)
Map window coordinates to object coordinates.
Definition: FloatUtil.java:665
static boolean isEqual2(final float a, final float b)
Returns true if both values are equal, i.e.
static final float EPSILON
Epsilon for floating point {@value}, as once computed via getMachineEpsilon() on an AMD-64 CPU.
static StringBuilder matrixRowToString(StringBuilder sb, final String f, final FloatBuffer a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder, final int row)
static final float INV_DEVIANCE
Inversion Epsilon, used with equals method to determine if two inverted matrices are close enough to ...
static void multMatrixVec(final float[] m_in, final int m_in_off, final float[] v_in, final int v_in_off, final float[] v_out, final int v_out_off)
static float[] multMatrix(final float[] a, final float[] b)
Multiply matrix: [a] = [a] x [b].
Definition: FloatUtil.java:970
static float abs(final float a)
Invokes Math#abs(float).
static float[] makeFrustum(final float[] m, final int m_offset, final boolean initM, final float left, final float right, final float bottom, final float top, final float zNear, final float zFar)
Make given matrix the frustum matrix based on given parameters.
Definition: FloatUtil.java:218
static void multMatrix(final float[] a, final int a_off, final float[] b, final int b_off, final float[] d, final int d_off)
Multiply matrix: [d] = [a] x [b].
Definition: FloatUtil.java:785
static float matrixDeterminant(final float[] m)
Returns the determinant of the given matrix.
Definition: FloatUtil.java:474
static boolean isEqual(final float a, final float b)
Returns true if both values are equal, i.e.
static float[] makePick(final float[] m, final float x, final float y, final float deltaX, final float deltaY, final int[] viewport, final int viewport_offset, final float[] mat4Tmp)
Make given matrix the pick matrix based on given parameters.
Definition: FloatUtil.java:415
static boolean isZeroRaw(final float a)
Returns true if value is zero, disregarding EPSILON but considering NaN, -Inf and +Inf.
static void multMatrixVec(final FloatBuffer m_in, final float[] v_in, final float[] v_out)
static float radToADeg(final float rad)
Converts radians to arc-degree.
static StringBuilder matrixRowToString(StringBuilder sb, final String f, final float[] a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder, final int row)
static float cos(final float a)
static float tan(final float a)
static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f, final FloatBuffer a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder)
static float asin(final float a)
static float[] multMatrixVec3(final float[] m_in, final float[] v_in, final float[] v_out)
Affine 3f-vector transformation by 4x4 matrix.
static void multMatrixVec(final float[] m_in, final int m_in_off, final float[] v_in, final float[] v_out)
static float[] transposeMatrix(final float[] msrc, final float[] mres)
Transpose the given matrix.
Definition: FloatUtil.java:442
static void multMatrix(final float[] a, final int a_off, final float[] b, final int b_off)
Multiply matrix: [a] = [a] x [b].
Definition: FloatUtil.java:909
static float getMachineEpsilon()
Return computed machine Epsilon value.
static void multMatrix(final FloatBuffer a, final FloatBuffer b, final float[] d)
Multiply matrix: [d] = [a] x [b].
static float[] multMatrix(final float[] a, final float[] b, final float[] d)
Multiply matrix: [d] = [a] x [b].
Definition: FloatUtil.java:847
static float adegToRad(final float arc_degree)
Converts arc-degree to radians.
static boolean isZero(final float a, final float epsilon)
Returns true if value is zero, i.e.
static final float SQUARED_PI
The value PI^2.
static int getZBufferValue(final int zBits, final float z, final float zNear, final float zFar)
Returns Z buffer value of given parameter, see Love Your Z-Buffer.
static float[] invertMatrix(final float[] msrc, final float[] mres)
Invert the given matrix.
Definition: FloatUtil.java:512
static boolean isEqual(final float a, final float b, final float epsilon)
Returns true if both values are equal, i.e.
static float[] makeTranslation(final float[] m, final boolean initM, final float tx, final float ty, final float tz)
Make a translation matrix in column-major order from the given axis deltas.
Definition: FloatUtil.java:140
static float[] makeIdentity(final float[] m)
Make matrix an identity matrix.
Definition: FloatUtil.java:96
static final float HALF_PI
The value PI/2, i.e.
static float sqrt(final float a)
static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f, final float[] a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder)
static int compare(final float a, final float b, final float epsilon)
Returns -1, 0 or 1 if a is less, equal or greater than b, considering epsilon and NaN,...
static float[] multMatrixVec(final float[] m_in, final float[] v_in, final float[] v_out)
static final boolean DEBUG
Definition: FloatUtil.java:84
static final float E
static float pow(final float a, final float b)
static float[] crossVec3(final float[] r, final int r_offset, final float[] v1, final int v1_offset, final float[] v2, final int v2_offset)
cross product vec1 x vec2
static float[] normalizeVec3(final float[] vector)
Normalize a vector in place.
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...