From 15e60161787224e85172685f74dc0ac195969b51 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Wed, 5 Apr 2023 09:42:28 +0200
Subject: Math: Complete Matrix4f w/ Vec[234]f and adopt it throughout
Quaternion, Ray, AABBox, Frustum, Stereo*, ... adding hook to PMVMatrix
Motivation was to simplify matrix + vector math usage, ease review and avoid usage bugs.
Matrix4f implementation uses dedicated float fields instead of an array.
Performance didn't increase much,
as JVM >= 11(?) has some optimizations to drop the array bounds check.
AMD64 + OpenJDK17
- Matrix4f.mul(a, b) got a roughly ~10% enhancement over FloatUtil.multMatrix(a, b, dest)
- Matrix4f.mul(b) roughly ~3% slower than FloatUtil.multMatrix(a, b, dest)
- FloatUtil.multMatrix(a, a_off, b, b_off, dest) is considerable slower than all
- Matrix4f.invert(..) roughly ~3% slower than FloatUtil.invertMatrix(..)
RaspberryPi 4b aarch64 + OpenJDK17
- Matrix4f.mul(a, b) got a roughly ~10% enhancement over FloatUtil.multMatrix(a, b, dest)
- Matrix4f.mul(b) roughly ~20% slower than FloatUtil.multMatrix(a, b)
- FloatUtil.multMatrix(a, a_off, b, b_off, dest) is considerable slower than all
- Matrix4f.invert(..) roughly ~4% slower than FloatUtil.invertMatrix(..)
Conclusion
- Matrix4f.mul(b) needs to be revised (esp for aarch64)
- Matrix4f.invert(..) should also not be slower ..
---
make/scripts/make.jogl.all.linux-x86_64.sh | 3 +
make/scripts/tests.sh | 13 +-
.../com/jogamp/opengl/demos/av/MovieSBSStereo.java | 68 +-
.../com/jogamp/opengl/demos/av/StereoDemo01.java | 9 +-
.../com/jogamp/opengl/demos/es2/GearsES2.java | 85 +-
.../jogamp/opengl/demos/graph/GPUTextNewtDemo.java | 2 +-
.../demos/graph/GPUTextRendererListenerBase01.java | 3 +-
src/jogl/classes/com/jogamp/graph/font/Font.java | 6 +-
.../jogamp/graph/geom/plane/AffineTransform.java | 52 +-
.../classes/com/jogamp/opengl/math/FloatUtil.java | 286 ++-
.../classes/com/jogamp/opengl/math/Matrix4.java | 172 --
.../classes/com/jogamp/opengl/math/Matrix4f.java | 1878 ++++++++++++++++++++
.../classes/com/jogamp/opengl/math/Quaternion.java | 358 ++--
src/jogl/classes/com/jogamp/opengl/math/Ray.java | 10 +-
src/jogl/classes/com/jogamp/opengl/math/Vec2f.java | 81 +-
src/jogl/classes/com/jogamp/opengl/math/Vec3f.java | 112 +-
src/jogl/classes/com/jogamp/opengl/math/Vec4f.java | 348 ++++
.../classes/com/jogamp/opengl/math/VectorUtil.java | 12 +-
.../com/jogamp/opengl/math/geom/AABBox.java | 433 +++--
.../com/jogamp/opengl/math/geom/Frustum.java | 121 +-
.../classes/com/jogamp/opengl/util/PMVMatrix.java | 128 +-
.../jogamp/opengl/util/stereo/EyeParameter.java | 17 +-
.../util/stereo/LocationSensorParameter.java | 9 +-
.../jogamp/opengl/util/stereo/StereoDevice.java | 15 +-
.../com/jogamp/opengl/util/stereo/StereoUtil.java | 44 +-
.../com/jogamp/opengl/util/stereo/ViewerPose.java | 20 +-
.../stereo/generic/GenericStereoDeviceFactory.java | 7 +-
.../jogamp/graph/font/typecast/TypecastFont.java | 4 +-
.../jogamp/graph/font/typecast/TypecastGlyph.java | 8 +-
.../graph/font/typecast/TypecastHMetrics.java | 4 +-
src/jogl/classes/jogamp/opengl/ProjectFloat.java | 6 +-
.../opengl/util/stereo/GenericStereoDevice.java | 11 +-
.../util/stereo/GenericStereoDeviceRenderer.java | 5 +-
.../jogamp/opengl/oculusvr/OVRStereoDevice.java | 7 +-
.../opengl/oculusvr/OVRStereoDeviceRenderer.java | 5 +-
.../junit/graph/GPUTextRendererListenerBase01.java | 2 +-
.../opengl/test/junit/graph/TestFontsNEWT00.java | 2 +-
.../opengl/test/junit/jogl/demos/es2/GearsES2.java | 89 +-
.../TriangleInstancedRendererWithShaderState.java | 83 +-
.../gl4/TrianglesInstancedRendererHardcoded.java | 107 +-
.../opengl/test/junit/jogl/math/Matrix4fb.java | 1784 +++++++++++++++++++
.../jogl/math/TestFloatUtilProject01NOUI.java | 32 +-
.../jogl/math/TestFloatUtilProject02NOUI.java | 4 +-
.../test/junit/jogl/math/TestMatrix4f01NOUI.java | 177 ++
.../junit/jogl/math/TestMatrix4f02MulNOUI.java | 275 +++
.../jogl/math/TestMatrix4f03InversionNOUI.java | 403 +++++
.../test/junit/jogl/math/TestPMVMatrix03NOUI.java | 8 +-
.../test/junit/jogl/math/TestQuaternion01NOUI.java | 660 ++++---
48 files changed, 6592 insertions(+), 1376 deletions(-)
delete mode 100644 src/jogl/classes/com/jogamp/opengl/math/Matrix4.java
create mode 100644 src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java
create mode 100644 src/jogl/classes/com/jogamp/opengl/math/Vec4f.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/math/Matrix4fb.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f01NOUI.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f02MulNOUI.java
create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f03InversionNOUI.java
diff --git a/make/scripts/make.jogl.all.linux-x86_64.sh b/make/scripts/make.jogl.all.linux-x86_64.sh
index f43112d25..9e91bb171 100755
--- a/make/scripts/make.jogl.all.linux-x86_64.sh
+++ b/make/scripts/make.jogl.all.linux-x86_64.sh
@@ -31,6 +31,9 @@ fi
#
# -Dsetup.addNativeOpenMAX=true \
# -Dsetup.addNativeKD=true \
+#
+# -Doculusvr.enabled=true \
+#
#LD_LIBRARY_PATH=/opt-linux-x86_64/mesa-7.8.1/lib64
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index 9724c7632..2038ceee2 100644
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -495,7 +495,7 @@ function testawtswt() {
#
# Stereo
#
-#testnoawt com.jogamp.opengl.test.junit.jogl.stereo.StereoDemo01 $*
+#testnoawt com.jogamp.opengl.demos.av.StereoDemo01 $*
#
#
# HiDPI
@@ -538,6 +538,7 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestTeapotNEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.gl3.newt.TestGeomShader01TextureGL3NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.gl4.newt.TestTessellationShader01GL4NEWT $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.demos.gl4.newt.TestInstancedReneringGL4NEWT $*
#
# av demos
@@ -546,6 +547,7 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.demos.av.MovieCube $*
#testnoawt com.jogamp.opengl.demos.av.MovieSimple $*
#testnoawt com.jogamp.opengl.demos.av.CrossFadePlayer $*
+#testnoawt com.jogamp.opengl.demos.av.StereoDemo01 $*
#
# performance tests
@@ -574,6 +576,9 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestFloatUtil01NOUI $*
#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestFloatUtil02MatrixMatrixMultNOUI $*
#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestFloatUtil03InversionNOUI $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestMatrix4f01NOUI $*
+testnoawt com.jogamp.opengl.test.junit.jogl.math.TestMatrix4f02MulNOUI $*
+#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestMatrix4f03InversionNOUI $*
#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVMatrix01NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVMatrix02NOUI $*
#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVMatrix03NOUI $*
@@ -972,7 +977,9 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo00 $*
#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo01 $*
#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo02 $*
+#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo03 $*
#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo10 $*
+#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo11 $*
#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo20 $*
#testnoawt com.jogamp.opengl.demos.av.MovieCube $*
@@ -1014,8 +1021,10 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo01 $*
#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo01b $*
#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo02 $*
-testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo03 $*
+#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo03 $*
+#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo03b $*
#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo10 $*
+#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo11 $*
#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo20 $*
#testnoawt com.jogamp.opengl.demos.av.MovieCube $*
diff --git a/src/demos/com/jogamp/opengl/demos/av/MovieSBSStereo.java b/src/demos/com/jogamp/opengl/demos/av/MovieSBSStereo.java
index 3a59216d5..3a0955a05 100644
--- a/src/demos/com/jogamp/opengl/demos/av/MovieSBSStereo.java
+++ b/src/demos/com/jogamp/opengl/demos/av/MovieSBSStereo.java
@@ -61,9 +61,9 @@ import com.jogamp.opengl.GLExtensions;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.JoglVersion;
import com.jogamp.opengl.demos.graph.TextRendererGLELBase;
-import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.Quaternion;
-import com.jogamp.opengl.math.VectorUtil;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.util.CustomGLEventListener;
import com.jogamp.opengl.util.GLArrayDataServer;
import com.jogamp.opengl.util.PMVMatrix;
@@ -641,15 +641,15 @@ public class MovieSBSStereo implements StereoGLEventListener {
pmvMatrix.glTranslatef(0, 0, zoom0);
}
- private final float[] mat4Tmp1 = new float[16];
- private final float[] mat4Tmp2 = new float[16];
- private final float[] vec3Tmp1 = new float[3];
- private final float[] vec3Tmp2 = new float[3];
- private final float[] vec3Tmp3 = new float[3];
+ private final Matrix4f mat4Tmp1 = new Matrix4f();
+ private final Matrix4f mat4Tmp2 = new Matrix4f();
+ private final Vec3f vec3Tmp1 = new Vec3f();
+ private final Vec3f vec3Tmp2 = new Vec3f();
+ private final Vec3f vec3Tmp3 = new Vec3f();
GLArrayDataServer interleavedVBOCurrent = null;
- private static final float[] vec3ScalePos = new float[] { 4f, 4f, 4f };
+ private static final float scalePos = 4f;
@Override
public void reshapeForEye(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height,
@@ -663,26 +663,38 @@ public class MovieSBSStereo implements StereoGLEventListener {
if(null == mPlayer) { return; }
if(null == st) { return; }
- pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
- final float[] mat4Projection = FloatUtil.makePerspective(mat4Tmp1, 0, true, eyeParam.fovhv, zNear, zFar);
- pmvMatrix.glLoadMatrixf(mat4Projection, 0);
-
- pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
- final Quaternion rollPitchYaw = new Quaternion();
- final float[] shiftedEyePos = rollPitchYaw.rotateVector(vec3Tmp1, 0, viewerPose.position, 0);
- VectorUtil.scaleVec3(shiftedEyePos, shiftedEyePos, vec3ScalePos); // amplify viewerPose position
- VectorUtil.addVec3(shiftedEyePos, shiftedEyePos, eyeParam.positionOffset);
-
- rollPitchYaw.mult(viewerPose.orientation);
- final float[] up = rollPitchYaw.rotateVector(vec3Tmp2, 0, VectorUtil.VEC3_UNIT_Y, 0);
- final float[] forward = rollPitchYaw.rotateVector(vec3Tmp3, 0, VectorUtil.VEC3_UNIT_Z_NEG, 0);
- final float[] center = VectorUtil.addVec3(forward, shiftedEyePos, forward);
-
- final float[] mLookAt = FloatUtil.makeLookAt(mat4Tmp1, 0, shiftedEyePos, 0, center, 0, up, 0, mat4Tmp2);
- final float[] mViewAdjust = FloatUtil.makeTranslation(mat4Tmp2, true, eyeParam.distNoseToPupilX, eyeParam.distMiddleToPupilY, eyeParam.eyeReliefZ);
- final float[] mat4Modelview = FloatUtil.multMatrix(mViewAdjust, mLookAt);
- pmvMatrix.glLoadMatrixf(mat4Modelview, 0);
- pmvMatrix.glTranslatef(0, 0, zoom0);
+ {
+ //
+ // Projection
+ //
+ final Matrix4f mat4 = new Matrix4f();
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ mat4.setToPerspective(eyeParam.fovhv, zNear, zFar);
+ pmvMatrix.glLoadMatrixf(mat4);
+
+ //
+ // Modelview
+ //
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ final Quaternion rollPitchYaw = new Quaternion();
+ // private final float eyeYaw = FloatUtil.PI; // 180 degrees in radians
+ // rollPitchYaw.rotateByAngleY(eyeYaw);
+ final Vec3f shiftedEyePos = rollPitchYaw.rotateVector(viewerPose.position, vec3Tmp1);
+ shiftedEyePos.scale(scalePos); // amplify viewerPose position
+ shiftedEyePos.add(eyeParam.positionOffset);
+
+ rollPitchYaw.mult(viewerPose.orientation);
+ final Vec3f up = rollPitchYaw.rotateVector(Vec3f.UNIT_Y, vec3Tmp2);
+ final Vec3f forward = rollPitchYaw.rotateVector(Vec3f.UNIT_Z_NEG, vec3Tmp3); // -> center
+ final Vec3f center = forward.add(shiftedEyePos);
+
+ final Matrix4f mLookAt = mat4Tmp2.setToLookAt(shiftedEyePos, center, up, mat4Tmp1);
+ mat4.mul( mat4Tmp1.setToTranslation( eyeParam.distNoseToPupilX,
+ eyeParam.distMiddleToPupilY,
+ eyeParam.eyeReliefZ ), mLookAt);
+ mat4.translate(0, 0, zoom0, mat4Tmp1);
+ pmvMatrix.glLoadMatrixf(mat4);
+ }
st.useProgram(gl, true);
st.uniform(gl, pmvMatrixUniform);
st.useProgram(gl, false);
diff --git a/src/demos/com/jogamp/opengl/demos/av/StereoDemo01.java b/src/demos/com/jogamp/opengl/demos/av/StereoDemo01.java
index 88a49a09a..139c9f140 100644
--- a/src/demos/com/jogamp/opengl/demos/av/StereoDemo01.java
+++ b/src/demos/com/jogamp/opengl/demos/av/StereoDemo01.java
@@ -52,6 +52,7 @@ import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.newt.opengl.util.stereo.StereoDeviceUtil;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.AnimatorBase;
import com.jogamp.opengl.util.av.GLMediaPlayer;
@@ -289,9 +290,9 @@ public class StereoDemo01 {
}
final boolean usesLenses = 0 != ( StereoDeviceRenderer.DISTORTION_BARREL & stereoDevice.getMinimumDistortionBits() );
- final float[] eyePositionOffset = null != movieSimple && usesLenses ? new float[] { 0f, 0.3f, 0f } // better fixed movie position w/ lenses
- : stereoDevice.getDefaultEyePositionOffset(); // default
- System.err.println("Eye Position Offset: "+Arrays.toString(eyePositionOffset));
+ final Vec3f eyePositionOffset = null != movieSimple && usesLenses ? new Vec3f( 0f, 0.3f, 0f ) // better fixed movie position w/ lenses
+ : stereoDevice.getDefaultEyePositionOffset(); // default
+ System.err.println("Eye Position Offset: "+eyePositionOffset);
final int textureUnit = 0;
final int reqDistortionBits;
@@ -382,7 +383,7 @@ public class StereoDemo01 {
System.err.println("Window.1.surfaceSize: "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight());
if( useAnimator ) {
- animator.setUpdateFPSFrames(60, System.err);
+ animator.setUpdateFPSFrames(60*10, System.err);
}
final long t0 = System.currentTimeMillis();
diff --git a/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java b/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java
index 02c451e9f..5ad6ede76 100644
--- a/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java
+++ b/src/demos/com/jogamp/opengl/demos/es2/GearsES2.java
@@ -33,9 +33,9 @@ import com.jogamp.newt.event.GestureHandler.GestureEvent;
import com.jogamp.opengl.GLRendererQuirks;
import com.jogamp.opengl.JoglVersion;
import com.jogamp.opengl.demos.GearsObject;
-import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.Quaternion;
-import com.jogamp.opengl.math.VectorUtil;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.util.CustomGLEventListener;
import com.jogamp.opengl.util.PMVMatrix;
import com.jogamp.opengl.util.TileRendererBase;
@@ -397,49 +397,58 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
}
// private boolean useAndroidDebug = false;
- private final float[] mat4Tmp1 = new float[16];
- private final float[] mat4Tmp2 = new float[16];
- private final float[] vec3Tmp1 = new float[3];
- private final float[] vec3Tmp2 = new float[3];
- private final float[] vec3Tmp3 = new float[3];
+ private final Matrix4f mat4Tmp1 = new Matrix4f();
+ private final Matrix4f mat4Tmp2 = new Matrix4f();
+ private final Vec3f vec3Tmp1 = new Vec3f();
+ private final Vec3f vec3Tmp2 = new Vec3f();
+ private final Vec3f vec3Tmp3 = new Vec3f();
- private static final float[] vec3ScalePos = new float[] { 20f, 20f, 20f };
+ private static final float scalePos = 20f;
@Override
public void reshapeForEye(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height,
final EyeParameter eyeParam, final ViewerPose viewerPose) {
final GL2ES2 gl = drawable.getGL().getGL2ES2();
- pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
- final float[] mat4Projection = FloatUtil.makePerspective(mat4Tmp1, 0, true, eyeParam.fovhv, zNear, zFar);
- if( flipVerticalInGLOrientation && gl.getContext().getGLDrawable().isGLOriented() ) {
- pmvMatrix.glLoadIdentity();
- pmvMatrix.glScalef(1f, -1f, 1f);
- pmvMatrix.glMultMatrixf(mat4Projection, 0);
- } else {
- pmvMatrix.glLoadMatrixf(mat4Projection, 0);
- }
-
- pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
- final Quaternion rollPitchYaw = new Quaternion();
- // private final float eyeYaw = FloatUtil.PI; // 180 degrees in radians
- // rollPitchYaw.rotateByAngleY(eyeYaw);
- // final float[] shiftedEyePos = rollPitchYaw.rotateVector(vec3Tmp1, 0, viewerPose.position, 0);
- final float[] shiftedEyePos = VectorUtil.copyVec3(vec3Tmp1, 0, viewerPose.position, 0);
- VectorUtil.scaleVec3(shiftedEyePos, shiftedEyePos, vec3ScalePos); // amplify viewerPose position
- VectorUtil.addVec3(shiftedEyePos, shiftedEyePos, eyeParam.positionOffset);
-
- rollPitchYaw.mult(viewerPose.orientation);
- final float[] up = rollPitchYaw.rotateVector(vec3Tmp2, 0, VectorUtil.VEC3_UNIT_Y, 0);
- final float[] forward = rollPitchYaw.rotateVector(vec3Tmp3, 0, VectorUtil.VEC3_UNIT_Z_NEG, 0);
- final float[] center = VectorUtil.addVec3(forward, shiftedEyePos, forward);
-
- final float[] mLookAt = FloatUtil.makeLookAt(mat4Tmp1, 0, shiftedEyePos, 0, center, 0, up, 0, mat4Tmp2);
- final float[] mViewAdjust = FloatUtil.makeTranslation(mat4Tmp2, true, eyeParam.distNoseToPupilX, eyeParam.distMiddleToPupilY, eyeParam.eyeReliefZ);
- final float[] mat4Modelview = FloatUtil.multMatrix(mViewAdjust, mLookAt);
-
- pmvMatrix.glLoadMatrixf(mat4Modelview, 0);
- pmvMatrix.glTranslatef(0.0f, 0.0f, -zViewDist);
+ {
+ //
+ // Projection
+ //
+ final Matrix4f mat4 = new Matrix4f();
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ if( flipVerticalInGLOrientation && gl.getContext().getGLDrawable().isGLOriented() ) {
+ mat4Tmp1.setToScale(1f, -1f, 1f);
+ mat4Tmp2.setToPerspective(eyeParam.fovhv, zNear, zFar);
+ mat4.mul(mat4Tmp1, mat4Tmp2);
+ } else {
+ mat4.setToPerspective(eyeParam.fovhv, zNear, zFar);
+ }
+ pmvMatrix.glLoadMatrixf(mat4);
+
+ //
+ // Modelview
+ //
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ final Quaternion rollPitchYaw = new Quaternion();
+ // private final float eyeYaw = FloatUtil.PI; // 180 degrees in radians
+ // rollPitchYaw.rotateByAngleY(eyeYaw);
+ // final Vec3f shiftedEyePos = rollPitchYaw.rotateVector(viewerPose.position, vec3Tmp1);
+ final Vec3f shiftedEyePos = vec3Tmp1.set(viewerPose.position);
+ shiftedEyePos.scale(scalePos); // amplify viewerPose position
+ shiftedEyePos.add(eyeParam.positionOffset);
+
+ rollPitchYaw.mult(viewerPose.orientation);
+ final Vec3f up = rollPitchYaw.rotateVector(Vec3f.UNIT_Y, vec3Tmp2);
+ final Vec3f forward = rollPitchYaw.rotateVector(Vec3f.UNIT_Z_NEG, vec3Tmp3); // -> center
+ final Vec3f center = forward.add(shiftedEyePos);
+
+ final Matrix4f mLookAt = mat4Tmp2.setToLookAt(shiftedEyePos, center, up, mat4Tmp1);
+ mat4.mul( mat4Tmp1.setToTranslation( eyeParam.distNoseToPupilX,
+ eyeParam.distMiddleToPupilY,
+ eyeParam.eyeReliefZ ), mLookAt);
+ mat4.translate(0, 0, -zViewDist, mat4Tmp1);
+ pmvMatrix.glLoadMatrixf(mat4);
+ }
st.useProgram(gl, true);
st.uniform(gl, pmvMatrixUniform);
st.useProgram(gl, false);
diff --git a/src/demos/com/jogamp/opengl/demos/graph/GPUTextNewtDemo.java b/src/demos/com/jogamp/opengl/demos/graph/GPUTextNewtDemo.java
index ad5434b09..5952326c8 100644
--- a/src/demos/com/jogamp/opengl/demos/graph/GPUTextNewtDemo.java
+++ b/src/demos/com/jogamp/opengl/demos/graph/GPUTextNewtDemo.java
@@ -155,7 +155,7 @@ public class GPUTextNewtDemo {
final AABBox fontNameBox = font2.getMetricBounds(GPUTextRendererListenerBase01.textX1);
System.err.println("GPU Text Newt Demo: "+font2.fullString());
System.err.println("GPU Text Newt Demo: screen-dpi: "+sDPI[0]+"x"+sDPI[1]+", font "+font_ptpi+" pt, "+font_ppi+" pixel");
- System.err.println("GPU Text Newt Demo: textX2: "+fontNameBox+" em, "+fontNameBox.scale(font_ppi, new float[3])+" px");
+ System.err.println("GPU Text Newt Demo: textX2: "+fontNameBox+" em, "+fontNameBox.scale(font_ppi)+" px");
final MonitorDevice monitor = window.getMainMonitor();
System.err.println("GPU Text Newt Demo: "+monitor);
// window.setSurfaceSize((int)(fontNameBox.getWidth()*1.1f), (int)(fontNameBox.getHeight()*2f));
diff --git a/src/demos/com/jogamp/opengl/demos/graph/GPUTextRendererListenerBase01.java b/src/demos/com/jogamp/opengl/demos/graph/GPUTextRendererListenerBase01.java
index dadbcd373..cab25b83d 100644
--- a/src/demos/com/jogamp/opengl/demos/graph/GPUTextRendererListenerBase01.java
+++ b/src/demos/com/jogamp/opengl/demos/graph/GPUTextRendererListenerBase01.java
@@ -51,6 +51,7 @@ import com.jogamp.newt.Window;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.math.geom.AABBox;
import com.jogamp.opengl.util.PMVMatrix;
@@ -491,7 +492,7 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB
System.err.println("Matrix: " + getXTran() + "/" + getYTran() + " x"+getZTran() + " @"+getAngle() +" fontSize "+fontSizeCenter);
if(bbox) {
System.err.println("bbox em: "+font.getMetricBounds(text2));
- System.err.println("bbox px: "+font.getMetricBounds(text2).scale(nearPlaneS * FontScale.toPixels(fontSizeCenter, dpiV), new float[3]));
+ System.err.println("bbox px: "+font.getMetricBounds(text2).scale( nearPlaneS * FontScale.toPixels(fontSizeCenter, dpiV) ) );
}
}
diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java
index 4399bbad7..3d7e9f6a1 100644
--- a/src/jogl/classes/com/jogamp/graph/font/Font.java
+++ b/src/jogl/classes/com/jogamp/graph/font/Font.java
@@ -29,6 +29,7 @@ package com.jogamp.graph.font;
import com.jogamp.graph.curve.OutlineShape;
import com.jogamp.graph.geom.plane.AffineTransform;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.math.geom.AABBox;
/**
@@ -151,7 +152,7 @@ public interface Font {
* @param dest AABBox instance set to this metrics boundary in font em-size [0..1]
* @return the given and set AABBox 'dest' in font units
*/
- AABBox getBounds(final AABBox dest, final float[] tmpV3);
+ AABBox getBounds(final AABBox dest);
}
/**
@@ -193,10 +194,9 @@ public interface Font {
/**
* Return the AABBox in font em-size [0..1], copying into given dest.
* @param dest AABBox instance set to this metrics boundary in font em-size [0..1]
- * @param tmpV3 caller provided temporary 3-component vector
* @return the given and set AABBox 'dest' in font em-size [0..1]
*/
- AABBox getBounds(final AABBox dest, float[] tmpV3);
+ AABBox getBounds(final AABBox dest);
/**
* Return the AABBox in font em-size [0..1], creating a new copy.
diff --git a/src/jogl/classes/com/jogamp/graph/geom/plane/AffineTransform.java b/src/jogl/classes/com/jogamp/graph/geom/plane/AffineTransform.java
index 62cda0322..74036f97d 100644
--- a/src/jogl/classes/com/jogamp/graph/geom/plane/AffineTransform.java
+++ b/src/jogl/classes/com/jogamp/graph/geom/plane/AffineTransform.java
@@ -16,6 +16,7 @@
*/
/**
* @author Denis M. Kishenko
+ * @author Sven Gothel, (c) 2010-2023
*/
package com.jogamp.graph.geom.plane;
@@ -23,6 +24,8 @@ package com.jogamp.graph.geom.plane;
import com.jogamp.graph.geom.Vertex;
import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Vec2f;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.math.geom.AABBox;
public class AffineTransform implements Cloneable {
@@ -53,17 +56,17 @@ public class AffineTransform implements Cloneable {
/**
* The values of transformation matrix
*/
- float m00;
- float m10;
- float m01;
- float m11;
- float m02;
- float m12;
+ private float m00;
+ private float m10;
+ private float m01;
+ private float m11;
+ private float m02;
+ private float m12;
/**
* The transformation type
*/
- transient int type;
+ private transient int type;
public AffineTransform() {
setToIdentity();
@@ -404,10 +407,10 @@ public class AffineTransform implements Cloneable {
* @return dst for chaining
*/
public final AABBox transform(final AABBox src, final AABBox dst) {
- final float[] srcLo = src.getLow();
- final float[] srcHi = src.getHigh();
- dst.setSize(srcLo[0] * m00 + srcLo[1] * m01 + m02, srcLo[0] * m10 + srcLo[1] * m11 + m12, srcLo[2],
- srcHi[0] * m00 + srcHi[1] * m01 + m02, srcHi[0] * m10 + srcHi[1] * m11 + m12, srcHi[2]);
+ final Vec3f lo = src.getLow();
+ final Vec3f hi = src.getHigh();
+ dst.setSize(lo.x() * m00 + lo.y() * m01 + m02, lo.x() * m10 + lo.y() * m11 + m12, lo.z(),
+ hi.x() * m00 + hi.y() * m01 + m02, hi.x() * m10 + hi.y() * m11 + m12, hi.z());
return dst;
}
@@ -474,6 +477,33 @@ public class AffineTransform implements Cloneable {
}
}
+ /**
+ * @param src source of transformation
+ * @param dst destination of transformation, maybe be equal to src
+ * @return dst for chaining
+ */
+ public final Vec2f transform(final Vec2f src, final Vec2f dst) {
+ final float x = src.x();
+ final float y = src.y();
+ dst.setX( x * m00 + y * m01 + m02 );
+ dst.setY( x * m10 + y * m11 + m12 );
+ return dst;
+ }
+
+ /**
+ * @param src source of transformation
+ * @param dst destination of transformation, maybe be equal to src
+ * @return dst for chaining
+ */
+ public final Vec3f transform(final Vec3f src, final Vec3f dst) {
+ final float x = src.x();
+ final float y = src.y();
+ dst.setX( x * m00 + y * m01 + m02 );
+ dst.setY( x * m10 + y * m11 + m12 );
+ dst.setZ( src.z() ); // just copy z
+ return dst;
+ }
+
/**
*
* @param src
diff --git a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
index 7aba7fa73..f793629d6 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -44,20 +44,26 @@ import com.jogamp.opengl.math.geom.Frustum;
* Implementation assumes linear matrix layout in column-major order
* matching OpenGL's implementation, illustration:
*
- Row-Major Column-Major (OpenGL):
+ Row-Major Column-Major (OpenGL):
- | 0 1 2 3 | | 0 4 8 12 |
- | | | |
- | 4 5 6 7 | | 1 5 9 13 |
- M = | | M = | |
- | 8 9 10 11 | | 2 6 10 14 |
- | | | |
- | 12 13 14 15 | | 3 7 11 15 |
+ | 0 1 2 tx |
+ | |
+ | 4 5 6 ty |
+ M = | |
+ | 8 9 10 tz |
+ | |
+ | 12 13 14 15 |
- C R C R
+ R C R C
m[0*4+3] = tx; m[0+4*3] = tx;
m[1*4+3] = ty; m[1+4*3] = ty;
m[2*4+3] = tz; m[2+4*3] = tz;
+
+ RC (std subscript order) RC (std subscript order)
+ m03 = tx; m03 = tx;
+ m13 = ty; m13 = ty;
+ m23 = tz; m23 = tz;
+
*
*
*
@@ -71,7 +77,7 @@ import com.jogamp.opengl.math.geom.Frustum;
* Implementation utilizes unrolling of small vertices and matrices wherever possible
* while trying to access memory in a linear fashion for performance reasons, see:
*
*
@@ -579,35 +585,6 @@ public final class FloatUtil {
return makeFrustum(m, m_off, initM, left, right, bottom, top, zNear, zFar);
}
- /**
- * Make given matrix the perspective {@link #makeFrustum(float[], int, boolean, float, float, float, float, float, float) frustum}
- * matrix based on given parameters.
- *
- * All matrix fields are only set if initM
is true
.
- *
- *
- * @param m 4x4 matrix in column-major order (also result)
- * @param m_offset offset in given array m, i.e. start of the 4x4 matrix
- * @param initM if true, given matrix will be initialized w/ identity matrix,
- * otherwise only the frustum fields are set.
- * @param fovhv {@link FovHVHalves} field of view in both directions, may not be centered, either in radians or tangent
- * @param zNear
- * @param zFar
- * @return given matrix for chaining
- * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear}
- * @see #makeFrustum(float[], int, boolean, float, float, float, float, float, float)
- * @see Frustum#updateByFovDesc(float[], int, boolean, Frustum.FovDesc)
- */
- public static float[] makePerspective(final float[] m, final int m_offset, final boolean initM,
- final FovHVHalves fovhv, final float zNear, final float zFar) throws GLException {
- final FovHVHalves fovhvTan = fovhv.toTangents(); // use tangent of half-fov !
- final float top = fovhvTan.top * zNear;
- final float bottom = -1.0f * fovhvTan.bottom * zNear;
- final float left = -1.0f * fovhvTan.left * zNear;
- final float right = fovhvTan.right * zNear;
- return makeFrustum(m, m_offset, initM, left, right, bottom, top, zNear, zFar);
- }
-
/**
* Make given matrix the look-at matrix based on given parameters.
*
@@ -1072,12 +1049,12 @@ public final class FloatUtil {
* @param vec4Tmp2 4 component vector for temp storage
* @return true if successful, otherwise false (z is 1)
*/
- public static boolean mapObjToWinCoords(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[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
+ public 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[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
vec4Tmp1[0] = objx;
vec4Tmp1[1] = objy;
vec4Tmp1[2] = objz;
@@ -1120,18 +1097,15 @@ public final class FloatUtil {
* @param objz
* @param mat4PMv [projection] x [modelview] matrix, i.e. P x Mv
* @param viewport 4 component viewport vector
- * @param viewport_offset
* @param win_pos 3 component window coordinate, the result
- * @param win_pos_offset
* @param vec4Tmp1 4 component vector for temp storage
* @param vec4Tmp2 4 component vector for temp storage
* @return true if successful, otherwise false (z is 1)
*/
- public static boolean mapObjToWinCoords(final float objx, final float objy, final float objz,
- final float[/*16*/] mat4PMv,
- final int[] viewport, final int viewport_offset,
- final float[] win_pos, final int win_pos_offset,
- final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
+ public static boolean mapObjToWin(final float objx, final float objy, final float objz,
+ final float[/*16*/] mat4PMv,
+ final int[] viewport, final float[] win_pos,
+ final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
vec4Tmp2[0] = objx;
vec4Tmp2[1] = objy;
vec4Tmp2[2] = objz;
@@ -1152,9 +1126,9 @@ public final class FloatUtil {
vec4Tmp1[2] = vec4Tmp1[2] * vec4Tmp1[3] + 0.5f;
// Map x,y to viewport
- win_pos[0+win_pos_offset] = vec4Tmp1[0] * viewport[2+viewport_offset] + viewport[0+viewport_offset];
- win_pos[1+win_pos_offset] = vec4Tmp1[1] * viewport[3+viewport_offset] + viewport[1+viewport_offset];
- win_pos[2+win_pos_offset] = vec4Tmp1[2];
+ win_pos[0] = vec4Tmp1[0] * viewport[2] + viewport[0];
+ win_pos[1] = vec4Tmp1[1] * viewport[3] + viewport[1];
+ win_pos[2] = vec4Tmp1[2];
return true;
}
@@ -1180,12 +1154,12 @@ public final class FloatUtil {
* @param mat4Tmp2 16 component matrix for temp storage
* @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
*/
- public static boolean mapWinToObjCoords(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[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) {
+ public 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[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) {
// mat4Tmp1 = P x Mv
multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0);
@@ -1242,11 +1216,11 @@ public final class FloatUtil {
* @param vec4Tmp2 4 component vector for temp storage
* @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
*/
- public static boolean mapWinToObjCoords(final float winx, final float winy, final float winz,
- final float[/*16*/] mat4PMvI,
- final int[] viewport, final int viewport_offset,
- final float[] obj_pos, final int obj_pos_offset,
- final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz,
+ final float[/*16*/] mat4PMvI,
+ final int[] viewport, final int viewport_offset,
+ final float[] obj_pos, final int obj_pos_offset,
+ final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
vec4Tmp1[0] = winx;
vec4Tmp1[1] = winy;
vec4Tmp1[2] = winz;
@@ -1296,19 +1270,17 @@ public final class FloatUtil {
* @param vec4Tmp2 4 component vector for temp storage
* @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
*/
- public static boolean mapWinToObjCoords(final float winx, final float winy, final float winz1, final float winz2,
- final float[/*16*/] mat4PMvI,
- final int[] viewport, final int viewport_offset,
- final float[] obj1_pos, final int obj1_pos_offset,
- final float[] obj2_pos, final int obj2_pos_offset,
- final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz1, final float winz2,
+ final float[/*16*/] mat4PMvI, final int[] viewport,
+ final Vec3f objPos1, final Vec3f objPos2,
+ final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) {
vec4Tmp1[0] = winx;
vec4Tmp1[1] = winy;
vec4Tmp1[3] = 1.0f;
// Map x and y from window coordinates
- vec4Tmp1[0] = (vec4Tmp1[0] - viewport[0+viewport_offset]) / viewport[2+viewport_offset];
- vec4Tmp1[1] = (vec4Tmp1[1] - viewport[1+viewport_offset]) / viewport[3+viewport_offset];
+ vec4Tmp1[0] = (vec4Tmp1[0] - viewport[0]) / viewport[2];
+ vec4Tmp1[1] = (vec4Tmp1[1] - viewport[1]) / viewport[3];
// Map to range -1 to 1
vec4Tmp1[0] = vec4Tmp1[0] * 2 - 1;
@@ -1329,15 +1301,14 @@ public final class FloatUtil {
vec4Tmp2[3] = 1.0f / vec4Tmp2[3];
- obj1_pos[0+obj1_pos_offset] = vec4Tmp2[0] * vec4Tmp2[3];
- obj1_pos[1+obj1_pos_offset] = vec4Tmp2[1] * vec4Tmp2[3];
- obj1_pos[2+obj1_pos_offset] = vec4Tmp2[2] * vec4Tmp2[3];
+ objPos1.set( vec4Tmp2[0] * vec4Tmp2[3],
+ vec4Tmp2[1] * vec4Tmp2[3],
+ vec4Tmp2[2] * vec4Tmp2[3] );
//
// winz2
//
- vec4Tmp1[2] = winz2;
- vec4Tmp1[2] = vec4Tmp1[2] * 2 - 1;
+ vec4Tmp1[2] = winz2 * 2 - 1;
// object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2
multMatrixVec(mat4PMvI, vec4Tmp1, vec4Tmp2);
@@ -1348,9 +1319,9 @@ public final class FloatUtil {
vec4Tmp2[3] = 1.0f / vec4Tmp2[3];
- obj2_pos[0+obj2_pos_offset] = vec4Tmp2[0] * vec4Tmp2[3];
- obj2_pos[1+obj2_pos_offset] = vec4Tmp2[1] * vec4Tmp2[3];
- obj2_pos[2+obj2_pos_offset] = vec4Tmp2[2] * vec4Tmp2[3];
+ objPos2.set( vec4Tmp2[0] * vec4Tmp2[3],
+ vec4Tmp2[1] * vec4Tmp2[3],
+ vec4Tmp2[2] * vec4Tmp2[3] );
return true;
}
@@ -1379,13 +1350,13 @@ public final class FloatUtil {
* @param mat4Tmp2 16 component matrix for temp storage
* @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
*/
- public static boolean mapWinToObjCoords(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[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) {
+ public 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[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) {
// mat4Tmp1 = P x Mv
multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0);
@@ -1397,7 +1368,7 @@ public final class FloatUtil {
mat4Tmp2[0] = winx;
mat4Tmp2[1] = winy;
mat4Tmp2[2] = winz;
- mat4Tmp2[3] = 1.0f;
+ mat4Tmp2[3] = clipw;
// Map x and y from window coordinates
mat4Tmp2[0] = (mat4Tmp2[0] - viewport[0+viewport_offset]) / viewport[2+viewport_offset];
@@ -1417,8 +1388,6 @@ public final class FloatUtil {
return false;
}
- mat4Tmp2[3+raw_off] = 1.0f / mat4Tmp2[3+raw_off];
-
obj_pos[0+obj_pos_offset] = mat4Tmp2[0+raw_off];
obj_pos[1+obj_pos_offset] = mat4Tmp2[1+raw_off];
obj_pos[2+obj_pos_offset] = mat4Tmp2[2+raw_off];
@@ -1459,7 +1428,7 @@ public final class FloatUtil {
public static boolean mapWinToRay(final float winx, final float winy, final float winz0, final float winz1,
final float[] modelMatrix, final int modelMatrix_offset,
final float[] projMatrix, final int projMatrix_offset,
- final int[] viewport, final int viewport_offset,
+ final int[] viewport,
final Ray ray,
final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2, final float[/*4*/] vec4Tmp2) {
// mat4Tmp1 = P x Mv
@@ -1469,11 +1438,9 @@ public final class FloatUtil {
if ( null == invertMatrix(mat4Tmp1, mat4Tmp1) ) {
return false;
}
- if( mapWinToObjCoords(winx, winy, winz0, winz1, mat4Tmp1,
- viewport, viewport_offset,
- ray.orig, 0, ray.dir, 0,
- mat4Tmp2, vec4Tmp2) ) {
- VectorUtil.normalizeVec3( VectorUtil.subVec3(ray.dir, ray.dir, ray.orig) );
+ if( mapWinToObj(winx, winy, winz0, winz1, mat4Tmp1, viewport,
+ ray.orig, ray.dir, mat4Tmp2, vec4Tmp2) ) {
+ ray.dir.sub(ray.orig).normalize();
return true;
} else {
return false;
@@ -1485,9 +1452,8 @@ public final class FloatUtil {
* @param a 4x4 matrix in column-major order
* @param b 4x4 matrix in column-major order
* @param d result a*b in column-major order
- * @return given result matrix d for chaining
*/
- public static float[] multMatrix(final float[] a, final int a_off, final float[] b, final int b_off, final float[] d, final int d_off) {
+ 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) {
final float b00 = b[b_off+0+0*4];
final float b10 = b[b_off+1+0*4];
final float b20 = b[b_off+2+0*4];
@@ -1540,8 +1506,6 @@ public final class FloatUtil {
d[d_off+3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
d[d_off+3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
d[d_off+3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
-
- return d;
}
/**
@@ -1612,9 +1576,8 @@ public final class FloatUtil {
* Multiply matrix: [a] = [a] x [b]
* @param a 4x4 matrix in column-major order (also result)
* @param b 4x4 matrix in column-major order
- * @return given result matrix a for chaining
*/
- public static float[] multMatrix(final float[] a, final int a_off, final float[] b, final int b_off) {
+ public static void multMatrix(final float[] a, final int a_off, final float[] b, final int b_off) {
final float b00 = b[b_off+0+0*4];
final float b10 = b[b_off+1+0*4];
final float b20 = b[b_off+2+0*4];
@@ -1667,8 +1630,6 @@ public final class FloatUtil {
a[a_off+3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
a[a_off+3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
a[a_off+3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
-
- return a;
}
/**
@@ -1778,11 +1739,10 @@ public final class FloatUtil {
* @param m_in_off
* @param v_in 4-component column-vector
* @param v_out m_in * v_in
- * @return given result vector v_out for chaining
*/
- public static float[] 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) {
+ public 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) {
// (one matrix row in column-major order) X (column vector)
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 ] +
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 ];
@@ -1798,8 +1758,31 @@ public final class FloatUtil {
final int m_in_off_3 = 3+m_in_off;
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] +
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];
+ }
- return v_out;
+ /**
+ * @param m_in 4x4 matrix in column-major order
+ * @param m_in_off
+ * @param v_in 4-component column-vector
+ * @param v_out m_in * v_in
+ */
+ public static void multMatrixVec(final float[] m_in, final int m_in_off,
+ final float[] v_in, final float[] v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ v_out[0] = v_in[0] * m_in[0*4+m_in_off ] + v_in[1] * m_in[1*4+m_in_off ] +
+ v_in[2] * m_in[2*4+m_in_off ] + v_in[3] * m_in[3*4+m_in_off ];
+
+ final int m_in_off_1 = 1+m_in_off;
+ 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] +
+ v_in[2] * m_in[2*4+m_in_off_1] + v_in[3] * m_in[3*4+m_in_off_1];
+
+ final int m_in_off_2 = 2+m_in_off;
+ 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] +
+ v_in[2] * m_in[2*4+m_in_off_2] + v_in[3] * m_in[3*4+m_in_off_2];
+
+ final int m_in_off_3 = 3+m_in_off;
+ 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] +
+ v_in[2] * m_in[2*4+m_in_off_3] + v_in[3] * m_in[3*4+m_in_off_3];
}
/**
@@ -1845,46 +1828,59 @@ public final class FloatUtil {
}
/**
- * Copy the named column of the given column-major matrix to v_out.
- *
- * v_out may be 3 or 4 components long, hence the 4th row may not be stored.
- *
- * @param m_in input column-major matrix
- * @param m_in_off offset to input matrix
- * @param column named column to copy
- * @param v_out the column-vector storage, at least 3 components long
- * @param v_out_off offset to storage
+ * Affine 3f-vector transformation by 4x4 matrix
+ *
+ * 4x4 matrix multiplication with 3-component vector,
+ * using {@code 1} for for {@code v_in[3]} and dropping {@code v_out[3]},
+ * which shall be {@code 1}.
+ *
+ * @param m_in 4x4 matrix in column-major order
+ * @param m_in_off
+ * @param v_in 3-component column-vector
+ * @param v_out m_in * v_in, 3-component column-vector
* @return given result vector v_out for chaining
*/
- public static float[] copyMatrixColumn(final float[] m_in, final int m_in_off, final int column, final float[] v_out, final int v_out_off) {
- v_out[0+v_out_off]=m_in[0+column*4+m_in_off];
- v_out[1+v_out_off]=m_in[1+column*4+m_in_off];
- v_out[2+v_out_off]=m_in[2+column*4+m_in_off];
- if( v_out.length > 3+v_out_off ) {
- v_out[3+v_out_off]=m_in[3+column*4+m_in_off];
- }
+ public static float[] multMatrixVec3(final float[] m_in, final int m_in_off,
+ final float[] v_in, final float[] v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ v_out[0] = v_in[0] * m_in[0*4+m_in_off ] + v_in[1] * m_in[1*4+m_in_off ] +
+ v_in[2] * m_in[2*4+m_in_off ] + 1f * m_in[3*4+m_in_off ];
+
+ final int m_in_off_1 = 1+m_in_off;
+ 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] +
+ v_in[2] * m_in[2*4+m_in_off_1] + 1f * m_in[3*4+m_in_off_1];
+
+ final int m_in_off_2 = 2+m_in_off;
+ 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] +
+ v_in[2] * m_in[2*4+m_in_off_2] + 1f * m_in[3*4+m_in_off_2];
+
return v_out;
}
/**
- * Copy the named row of the given column-major matrix to v_out.
- *
- * v_out may be 3 or 4 components long, hence the 4th column may not be stored.
- *
- * @param m_in input column-major matrix
- * @param m_in_off offset to input matrix
- * @param row named row to copy
- * @param v_out the row-vector storage, at least 3 components long
- * @param v_out_off offset to storage
+ * Affine 3f-vector transformation by 4x4 matrix
+ *
+ * 4x4 matrix multiplication with 3-component vector,
+ * using {@code 1} for for {@code v_in[3]} and dropping {@code v_out[3]},
+ * which shall be {@code 1}.
+ *
+ * @param m_in 4x4 matrix in column-major order
+ * @param m_in_off
+ * @param v_in 3-component column-vector
+ * @param v_out m_in * v_in, 3-component column-vector
* @return given result vector v_out for chaining
*/
- public static float[] copyMatrixRow(final float[] m_in, final int m_in_off, final int row, final float[] v_out, final int v_out_off) {
- v_out[0+v_out_off]=m_in[row+0*4+m_in_off];
- v_out[1+v_out_off]=m_in[row+1*4+m_in_off];
- v_out[2+v_out_off]=m_in[row+2*4+m_in_off];
- if( v_out.length > 3+v_out_off ) {
- v_out[3+v_out_off]=m_in[row+3*4+m_in_off];
- }
+ public static float[] multMatrixVec3(final float[] m_in, final float[] v_in, final float[] v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ v_out[0] = v_in[0] * m_in[0*4 ] + v_in[1] * m_in[1*4 ] +
+ v_in[2] * m_in[2*4 ] + 1f * m_in[3*4 ];
+
+ v_out[1] = v_in[0] * m_in[0*4+1] + v_in[1] * m_in[1*4+1] +
+ v_in[2] * m_in[2*4+1] + 1f * m_in[3*4+1];
+
+ v_out[2] = v_in[0] * m_in[0*4+2] + v_in[1] * m_in[1*4+2] +
+ v_in[2] * m_in[2*4+2] + 1f * m_in[3*4+2];
+
return v_out;
}
@@ -2276,7 +2272,7 @@ public final class FloatUtil {
}
/**
- * Return true if value is zero, i.e. it's absolute value < epsilon
.
+ * Return true if value is zero, i.e. it's absolute value < {@link #EPSILON}.
* @see #EPSILON
*/
public static boolean isZero(final float a) {
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java b/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java
deleted file mode 100644
index a080d4442..000000000
--- a/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * Copyright 2014 JogAmp Community. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of JogAmp Community.
- */
-
-package com.jogamp.opengl.math;
-
-import com.jogamp.opengl.GLException;
-import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
-
-import com.jogamp.opengl.util.PMVMatrix;
-
-/**
- * Simple float array-backed float 4x4 matrix
- * exposing {@link FloatUtil} matrix functionality in an object oriented manner.
- *
- * Unlike {@link PMVMatrix}, this class only represents one single matrix
- * without a complete {@link GLMatrixFunc} implementation,
- * allowing this class to be more lightweight.
- *
- *
- * Implementation is not mature - WIP and subject to change.
- *
- */
-public class Matrix4 {
-
- public Matrix4() {
- matrix = new float[16];
- matrixTxSx = new float[16];
- mat4Tmp1 = new float[16];
- vec4Tmp1 = new float[4];
- FloatUtil.makeIdentity(matrixTxSx);
- loadIdentity();
- }
-
- public final float[] getMatrix() {
- return matrix;
- }
-
- public final void loadIdentity() {
- FloatUtil.makeIdentity(matrix);
- }
-
- /**
- * Multiply matrix: [this] = [this] x [m]
- * @param m 4x4 matrix in column-major order
- */
- public final void multMatrix(final float[] m, final int m_offset) {
- FloatUtil.multMatrix(matrix, 0, m, m_offset);
- }
-
- /**
- * Multiply matrix: [this] = [this] x [m]
- * @param m 4x4 matrix in column-major order
- */
- public final void multMatrix(final float[] m) {
- FloatUtil.multMatrix(matrix, m);
- }
-
- /**
- * Multiply matrix: [this] = [this] x [m]
- * @param m 4x4 matrix in column-major order
- */
- public final void multMatrix(final Matrix4 m) {
- FloatUtil.multMatrix(matrix, m.getMatrix());
- }
-
- /**
- * @param v_in 4-component column-vector
- * @param v_out this * v_in
- */
- public final void multVec(final float[] v_in, final float[] v_out) {
- FloatUtil.multMatrixVec(matrix, v_in, v_out);
- }
-
- /**
- * @param v_in 4-component column-vector
- * @param v_out this * v_in
- */
- public final void multVec(final float[] v_in, final int v_in_offset, final float[] v_out, final int v_out_offset) {
- FloatUtil.multMatrixVec(matrix, 0, v_in, v_in_offset, v_out, v_out_offset);
- }
-
- public final void translate(final float x, final float y, final float z) {
- multMatrix(FloatUtil.makeTranslation(matrixTxSx, false, x, y, z));
- }
-
- public final void scale(final float x, final float y, final float z) {
- multMatrix(FloatUtil.makeScale(matrixTxSx, false, x, y, z));
- }
-
- public final void rotate(final float angrad, final float x, final float y, final float z) {
- multMatrix(FloatUtil.makeRotationAxis(mat4Tmp1, 0, angrad, x, y, z, vec4Tmp1));
- }
-
- /**
- * Rotate the current matrix with the given {@link Quaternion}'s rotation {@link Quaternion#toMatrix(float[], int) matrix representation}.
- */
- public final void rotate(final Quaternion quat) {
- multMatrix(quat.toMatrix(mat4Tmp1, 0));
- }
-
- public final void transpose() {
- System.arraycopy(matrix, 0, mat4Tmp1, 0, 16);
- FloatUtil.transposeMatrix(mat4Tmp1, matrix);
- }
-
- public final float determinant() {
- return FloatUtil.matrixDeterminant(matrix);
- }
-
- public final boolean invert() {
- return null != FloatUtil.invertMatrix(matrix, matrix);
- }
-
- public final void makeOrtho(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) {
- multMatrix( FloatUtil.makeOrtho(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar) );
- }
-
- /**
- * @param left
- * @param right
- * @param bottom
- * @param top
- * @param zNear
- * @param zFar
- * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear}
- * or {@code left == right}, or {@code bottom == top}.
- * @see FloatUtil#makeFrustum(float[], int, boolean, float, float, float, float, float, float)
- */
- public final void makeFrustum(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) throws GLException {
- multMatrix( FloatUtil.makeFrustum(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar) );
- }
-
- /**
- * @param fovy_rad
- * @param aspect
- * @param zNear
- * @param zFar
- * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear}
- * @see FloatUtil#makePerspective(float[], int, boolean, float, float, float, float)
- */
- public final void makePerspective(final float fovy_rad, final float aspect, final float zNear, final float zFar) throws GLException {
- multMatrix( FloatUtil.makePerspective(mat4Tmp1, 0, true, fovy_rad, aspect, zNear, zFar) );
- }
-
- private final float[] matrix, matrixTxSx;
- private final float[] mat4Tmp1, vec4Tmp1;
-}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java b/src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java
new file mode 100644
index 000000000..5951c7d98
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java
@@ -0,0 +1,1878 @@
+/**
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.math;
+
+import java.nio.FloatBuffer;
+
+import com.jogamp.opengl.math.geom.AABBox;
+import com.jogamp.opengl.math.geom.Frustum;
+import com.jogamp.opengl.math.geom.Frustum.Plane;
+
+/**
+ * Basic 4x4 float matrix implementation using fields for intensive use-cases (host operations).
+ *
+ * Implementation covers {@link FloatUtil} matrix functionality, exposed in an object oriented manner.
+ *
+ *
+ * Unlike {@link com.jogamp.opengl.util.PMVMatrix PMVMatrix}, this class only represents one single matrix
+ * without a complete {@link com.jogamp.opengl.fixedfunc.GLMatrixFunc GLMatrixFunc} implementation.
+ *
+ *
+ * For array operations the layout is expected in column-major order
+ * matching OpenGL's implementation, illustration:
+ *
+ Row-Major Column-Major (OpenGL):
+
+ | 0 1 2 tx |
+ | |
+ | 4 5 6 ty |
+ M = | |
+ | 8 9 10 tz |
+ | |
+ | 12 13 14 15 |
+
+ R C R C
+ m[0*4+3] = tx; m[0+4*3] = tx;
+ m[1*4+3] = ty; m[1+4*3] = ty;
+ m[2*4+3] = tz; m[2+4*3] = tz;
+
+ RC (std subscript order) RC (std subscript order)
+ m03 = tx; m03 = tx;
+ m13 = ty; m13 = ty;
+ m23 = tz; m23 = tz;
+
+ *
+ *
+ *
+ *
+ *
+ *
+ * Implementation utilizes unrolling of small vertices and matrices wherever possible
+ * while trying to access memory in a linear fashion for performance reasons, see:
+ *
+ *
+ * @see com.jogamp.opengl.util.PMVMatrix
+ * @see FloatUtil
+ */
+public class Matrix4f {
+
+ /**
+ * Creates a new identity matrix.
+ */
+ public Matrix4f() {
+ m00 = m11 = m22 = m33 = 1.0f;
+ // remaining fields have default init to zero
+ }
+
+ /**
+ * Creates a new matrix copying the values of the given {@code src} matrix.
+ */
+ public Matrix4f(final Matrix4f src) {
+ load(src);
+ }
+
+ /**
+ * Creates a new matrix based on given float[4*4] column major order.
+ * @param m 4x4 matrix in column-major order
+ */
+ public Matrix4f(final float[] m) {
+ load(m);
+ }
+
+ /**
+ * Creates a new matrix based on given float[4*4] column major order.
+ * @param m 4x4 matrix in column-major order
+ * @param m_off offset for matrix {@code m}
+ */
+ public Matrix4f(final float[] m, final int m_off) {
+ load(m, m_off);
+ }
+
+ //
+ // Write to Matrix via load(..)
+ //
+
+ /**
+ * Set this matrix to identity.
+ *
+ Translation matrix (Column Order):
+ 1 0 0 0
+ 0 1 0 0
+ 0 0 1 0
+ 0 0 0 1
+ *
+ * @return this matrix for chaining
+ */
+ public final Matrix4f loadIdentity() {
+ m00 = m11 = m22 = m33 = 1.0f;
+ m01 = m02 = m03 =
+ m10 = m12 = m13 =
+ m20 = m21 = m23 =
+ m30 = m31 = m32 = 0.0f;
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code b} to this matrix.
+ * @param src the source values
+ * @return this matrix for chaining
+ */
+ public Matrix4f load(final Matrix4f src) {
+ m00 = src.m00; m10 = src.m10; m20 = src.m20; m30 = src.m30;
+ m01 = src.m01; m11 = src.m11; m21 = src.m21; m31 = src.m31;
+ m02 = src.m02; m12 = src.m12; m22 = src.m22; m32 = src.m32;
+ m03 = src.m03; m13 = src.m13; m23 = src.m23; m33 = src.m33;
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code src} to this matrix.
+ * @param src 4x4 matrix float[16] in column-major order
+ * @return this matrix for chaining
+ */
+ public Matrix4f load(final float[] src) {
+ m00 = src[0+0*4]; // column 0
+ m10 = src[1+0*4];
+ m20 = src[2+0*4];
+ m30 = src[3+0*4];
+ m01 = src[0+1*4]; // column 1
+ m11 = src[1+1*4];
+ m21 = src[2+1*4];
+ m31 = src[3+1*4];
+ m02 = src[0+2*4]; // column 2
+ m12 = src[1+2*4];
+ m22 = src[2+2*4];
+ m32 = src[3+2*4];
+ m03 = src[0+3*4]; // column 3
+ m13 = src[1+3*4];
+ m23 = src[2+3*4];
+ m33 = src[3+3*4];
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code src} to this matrix.
+ * @param src 4x4 matrix float[16] in column-major order
+ * @param src_off offset for matrix {@code src}
+ * @return this matrix for chaining
+ */
+ public Matrix4f load(final float[] src, final int src_off) {
+ m00 = src[src_off+0+0*4];
+ m10 = src[src_off+1+0*4];
+ m20 = src[src_off+2+0*4];
+ m30 = src[src_off+3+0*4];
+ m01 = src[src_off+0+1*4];
+ m11 = src[src_off+1+1*4];
+ m21 = src[src_off+2+1*4];
+ m31 = src[src_off+3+1*4];
+ m02 = src[src_off+0+2*4];
+ m12 = src[src_off+1+2*4];
+ m22 = src[src_off+2+2*4];
+ m32 = src[src_off+3+2*4];
+ m03 = src[src_off+0+3*4];
+ m13 = src[src_off+1+3*4];
+ m23 = src[src_off+2+3*4];
+ m33 = src[src_off+3+3*4];
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code src} to this matrix.
+ *
+ * Implementation uses relative {@link FloatBuffer#get()},
+ * hence caller may want to issue {@link FloatBuffer#reset()} thereafter.
+ *
+ * @param src 4x4 matrix {@link FloatBuffer} in column-major order
+ * @return this matrix for chaining
+ */
+ public Matrix4f load(final FloatBuffer src) {
+ m00 = src.get();
+ m10 = src.get();
+ m20 = src.get();
+ m30 = src.get();
+ m01 = src.get();
+ m11 = src.get();
+ m21 = src.get();
+ m31 = src.get();
+ m02 = src.get();
+ m12 = src.get();
+ m22 = src.get();
+ m32 = src.get();
+ m03 = src.get();
+ m13 = src.get();
+ m23 = src.get();
+ m33 = src.get();
+ return this;
+ }
+
+ //
+ // Read out Matrix via get(..)
+ //
+
+ /** Gets the ith component, 0 <= i < 16 */
+ public float get(final int i) {
+ switch (i) {
+ case 0+4*0: return m00;
+ case 1+4*0: return m10;
+ case 2+4*0: return m20;
+ case 3+4*0: return m30;
+
+ case 0+4*1: return m01;
+ case 1+4*1: return m11;
+ case 2+4*1: return m21;
+ case 3+4*1: return m31;
+
+ case 0+4*2: return m02;
+ case 1+4*2: return m12;
+ case 2+4*2: return m22;
+ case 3+4*2: return m32;
+
+ case 0+4*3: return m03;
+ case 1+4*3: return m13;
+ case 2+4*3: return m23;
+ case 3+4*3: return m33;
+
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Get the named column of the given column-major matrix to v_out.
+ * @param column named column to copy
+ * @param v_out the column-vector storage
+ * @return given result vector v_out for chaining
+ */
+ public Vec4f getColumn(final int column, final Vec4f v_out) {
+ v_out.set( get(0+column*4),
+ get(1+column*4),
+ get(2+column*4),
+ get(3+column*4) );
+ return v_out;
+ }
+
+ /**
+ * Get the named column of the given column-major matrix to v_out.
+ * @param column named column to copy
+ * @param v_out the column-vector storage
+ * @return given result vector v_out for chaining
+ */
+ public Vec3f getColumn(final int column, final Vec3f v_out) {
+ v_out.set( get(0+column*4),
+ get(1+column*4),
+ get(2+column*4) );
+ return v_out;
+ }
+
+ /**
+ * Get the named row of the given column-major matrix to v_out.
+ * @param row named row to copy
+ * @param v_out the row-vector storage
+ * @return given result vector v_out for chaining
+ */
+ public Vec4f getRow(final int row, final Vec4f v_out) {
+ v_out.set( get(row+0*4),
+ get(row+1*4),
+ get(row+2*4),
+ get(row+3*4) );
+ return v_out;
+ }
+
+ /**
+ * Get the named row of the given column-major matrix to v_out.
+ * @param row named row to copy
+ * @param v_out the row-vector storage
+ * @return given result vector v_out for chaining
+ */
+ public Vec3f getRow(final int row, final Vec3f v_out) {
+ v_out.set( get(row+0*4),
+ get(row+1*4),
+ get(row+2*4) );
+ return v_out;
+ }
+
+ /**
+ * Get this matrix into the given float[16] array at {@code dst_off} in column major order.
+ *
+ * @param dst float[16] array storage in column major order
+ * @param dst_off offset
+ */
+ public void get(final float[] dst, final int dst_off) {
+ dst[dst_off+0+0*4] = m00;
+ dst[dst_off+1+0*4] = m10;
+ dst[dst_off+2+0*4] = m20;
+ dst[dst_off+3+0*4] = m30;
+ dst[dst_off+0+1*4] = m01;
+ dst[dst_off+1+1*4] = m11;
+ dst[dst_off+2+1*4] = m21;
+ dst[dst_off+3+1*4] = m31;
+ dst[dst_off+0+2*4] = m02;
+ dst[dst_off+1+2*4] = m12;
+ dst[dst_off+2+2*4] = m22;
+ dst[dst_off+3+2*4] = m32;
+ dst[dst_off+0+3*4] = m03;
+ dst[dst_off+1+3*4] = m13;
+ dst[dst_off+2+3*4] = m23;
+ dst[dst_off+3+3*4] = m33;
+ }
+
+ /**
+ * Get this matrix into the given float[16] array in column major order.
+ *
+ * @param dst float[16] array storage in column major order
+ */
+ public void get(final float[] dst) {
+ dst[0+0*4] = m00;
+ dst[1+0*4] = m10;
+ dst[2+0*4] = m20;
+ dst[3+0*4] = m30;
+ dst[0+1*4] = m01;
+ dst[1+1*4] = m11;
+ dst[2+1*4] = m21;
+ dst[3+1*4] = m31;
+ dst[0+2*4] = m02;
+ dst[1+2*4] = m12;
+ dst[2+2*4] = m22;
+ dst[3+2*4] = m32;
+ dst[0+3*4] = m03;
+ dst[1+3*4] = m13;
+ dst[2+3*4] = m23;
+ dst[3+3*4] = m33;
+ }
+
+ /**
+ * Get this matrix into the given {@link FloatBuffer} in column major order.
+ *
+ * Implementation uses relative {@link FloatBuffer#put(float)},
+ * hence caller may want to issue {@link FloatBuffer#reset()} thereafter.
+ *
+ *
+ * @param dst {@link FloatBuffer} array storage in column major order
+ */
+ public void get(final FloatBuffer dst) {
+ dst.put( m00 );
+ dst.put( m10 );
+ dst.put( m20 );
+ dst.put( m30 );
+ dst.put( m01 );
+ dst.put( m11 );
+ dst.put( m21 );
+ dst.put( m31 );
+ dst.put( m02 );
+ dst.put( m12 );
+ dst.put( m22 );
+ dst.put( m32 );
+ dst.put( m03 );
+ dst.put( m13 );
+ dst.put( m23 );
+ dst.put( m33 );
+ }
+
+ //
+ // Basic matrix operations
+ //
+
+ /**
+ * Returns the determinant of this matrix
+ * @return the matrix determinant
+ */
+ public float determinant() {
+ float ret = 0;
+ ret += m00 * ( + m11*(m22*m33 - m23*m32) - m12*(m21*m33 - m23*m31) + m13*(m21*m32 - m22*m31));
+ ret -= m01 * ( + m10*(m22*m33 - m23*m32) - m12*(m20*m33 - m23*m30) + m13*(m20*m32 - m22*m30));
+ ret += m02 * ( + m10*(m21*m33 - m23*m31) - m11*(m20*m33 - m23*m30) + m13*(m20*m31 - m21*m30));
+ ret -= m03 * ( + m10*(m21*m32 - m22*m31) - m11*(m20*m32 - m22*m30) + m12*(m20*m31 - m21*m30));
+ return ret;
+ }
+
+ /**
+ * Transpose this matrix.
+ *
+ * @return this matrix for chaining
+ */
+ public final Matrix4f transpose() {
+ float tmp;
+
+ tmp = m10;
+ m10 = m01;
+ m01 = tmp;
+
+ tmp = m20;
+ m20 = m02;
+ m02 = tmp;
+
+ tmp = m30;
+ m30 = m03;
+ m03 = tmp;
+
+ tmp = m21;
+ m21 = m12;
+ m12 = tmp;
+
+ tmp = m31;
+ m31 = m13;
+ m13 = tmp;
+
+ tmp = m32;
+ m32 = m23;
+ m23 = tmp;
+
+ return this;
+ }
+
+ /**
+ * Transpose the given {@code src} matrix into this matrix.
+ *
+ * @param src source 4x4 matrix
+ * @return this matrix (result) for chaining
+ */
+ public final Matrix4f transpose(final Matrix4f src) {
+ if( src == this ) {
+ return transpose();
+ }
+ m00 = src.m00;
+ m10 = src.m01;
+ m20 = src.m02;
+ m30 = src.m03;
+
+ m01 = src.m10;
+ m11 = src.m11;
+ m21 = src.m12;
+ m31 = src.m13;
+
+ m02 = src.m20;
+ m12 = src.m21;
+ m22 = src.m22;
+ m32 = src.m23;
+
+ m03 = src.m30;
+ m13 = src.m31;
+ m23 = src.m32;
+ m33 = src.m33;
+ return this;
+ }
+
+ /**
+ * Invert this matrix.
+ * @return false if this matrix is singular and inversion not possible, otherwise true
+ */
+ public boolean invert() {
+ final float scale;
+ {
+ float a = Math.abs(m00);
+ float max = a;
+
+ a = Math.abs(m01); if( a > max ) max = a;
+ a = Math.abs(m02); if( a > max ) max = a;
+ a = Math.abs(m03); if( a > max ) max = a;
+
+ a = Math.abs(m10); if( a > max ) max = a;
+ a = Math.abs(m11); if( a > max ) max = a;
+ a = Math.abs(m12); if( a > max ) max = a;
+ a = Math.abs(m13); if( a > max ) max = a;
+
+ a = Math.abs(m20); if( a > max ) max = a;
+ a = Math.abs(m21); if( a > max ) max = a;
+ a = Math.abs(m22); if( a > max ) max = a;
+ a = Math.abs(m23); if( a > max ) max = a;
+
+ a = Math.abs(m30); if( a > max ) max = a;
+ a = Math.abs(m31); if( a > max ) max = a;
+ a = Math.abs(m32); if( a > max ) max = a;
+ a = Math.abs(m33); if( a > max ) max = a;
+
+ if( 0 == max ) {
+ return false;
+ }
+ scale = 1.0f/max;
+ }
+
+ final float a00 = m00*scale;
+ final float a10 = m10*scale;
+ final float a20 = m20*scale;
+ final float a30 = m30*scale;
+
+ final float a01 = m01*scale;
+ final float a11 = m11*scale;
+ final float a21 = m21*scale;
+ final float a31 = m31*scale;
+
+ final float a02 = m02*scale;
+ final float a12 = m12*scale;
+ final float a22 = m22*scale;
+ final float a32 = m32*scale;
+
+ final float a03 = m03*scale;
+ final float a13 = m13*scale;
+ final float a23 = m23*scale;
+ final float a33 = m33*scale;
+
+ final float b00 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31);
+ final float b01 = -( + a10*(a22*a33 - a23*a32) - a12*(a20*a33 - a23*a30) + a13*(a20*a32 - a22*a30));
+ final float b02 = + a10*(a21*a33 - a23*a31) - a11*(a20*a33 - a23*a30) + a13*(a20*a31 - a21*a30);
+ final float b03 = -( + a10*(a21*a32 - a22*a31) - a11*(a20*a32 - a22*a30) + a12*(a20*a31 - a21*a30));
+
+ final float b10 = -( + a01*(a22*a33 - a23*a32) - a02*(a21*a33 - a23*a31) + a03*(a21*a32 - a22*a31));
+ final float b11 = + a00*(a22*a33 - a23*a32) - a02*(a20*a33 - a23*a30) + a03*(a20*a32 - a22*a30);
+ final float b12 = -( + a00*(a21*a33 - a23*a31) - a01*(a20*a33 - a23*a30) + a03*(a20*a31 - a21*a30));
+ final float b13 = + a00*(a21*a32 - a22*a31) - a01*(a20*a32 - a22*a30) + a02*(a20*a31 - a21*a30);
+
+ final float b20 = + a01*(a12*a33 - a13*a32) - a02*(a11*a33 - a13*a31) + a03*(a11*a32 - a12*a31);
+ final float b21 = -( + a00*(a12*a33 - a13*a32) - a02*(a10*a33 - a13*a30) + a03*(a10*a32 - a12*a30));
+ final float b22 = + a00*(a11*a33 - a13*a31) - a01*(a10*a33 - a13*a30) + a03*(a10*a31 - a11*a30);
+ final float b23 = -( + a00*(a11*a32 - a12*a31) - a01*(a10*a32 - a12*a30) + a02*(a10*a31 - a11*a30));
+
+ final float b30 = -( + a01*(a12*a23 - a13*a22) - a02*(a11*a23 - a13*a21) + a03*(a11*a22 - a12*a21));
+ final float b31 = + a00*(a12*a23 - a13*a22) - a02*(a10*a23 - a13*a20) + a03*(a10*a22 - a12*a20);
+ final float b32 = -( + a00*(a11*a23 - a13*a21) - a01*(a10*a23 - a13*a20) + a03*(a10*a21 - a11*a20));
+ final float b33 = + a00*(a11*a22 - a12*a21) - a01*(a10*a22 - a12*a20) + a02*(a10*a21 - a11*a20);
+
+ final float det = (a00*b00 + a01*b01 + a02*b02 + a03*b03) / scale;
+
+ if( 0 == det ) {
+ return false;
+ }
+
+ m00 = b00 / det;
+ m10 = b01 / det;
+ m20 = b02 / det;
+ m30 = b03 / det;
+
+ m01 = b10 / det;
+ m11 = b11 / det;
+ m21 = b12 / det;
+ m31 = b13 / det;
+
+ m02 = b20 / det;
+ m12 = b21 / det;
+ m22 = b22 / det;
+ m32 = b23 / det;
+
+ m03 = b30 / det;
+ m13 = b31 / det;
+ m23 = b32 / det;
+ m33 = b33 / det;
+ return true;
+ }
+
+ /**
+ * Invert the {@code src} matrix values into this matrix
+ * @param src the source matrix, which values are to be inverted
+ * @return false if {@code src} matrix is singular and inversion not possible, otherwise true
+ */
+ public boolean invert(final Matrix4f src) {
+ return load(src).invert();
+ }
+
+ /**
+ * Multiply matrix: [this] = [this] x [b]
+ *
+ * Roughly 15% slower than {@link #mul(Matrix4f, Matrix4f)}
+ * Roughly 3% slower than {@link FloatUtil#multMatrix(float[], float[])}
+ *
+ * @param b 4x4 matrix
+ * @return this matrix for chaining
+ * @see #mul(Matrix4f, Matrix4f)
+ */
+ public final Matrix4f mul(final Matrix4f b) {
+ // return mul(new Matrix4f(this), b); // <- roughly half speed
+ float ai0=m00; // row-0, m[0+0*4]
+ float ai1=m01;
+ float ai2=m02;
+ float ai3=m03;
+ m00 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ;
+ m01 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ;
+ m02 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ;
+ m03 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ;
+
+ ai0=m10; //row-1, m[1+0*4]
+ ai1=m11;
+ ai2=m12;
+ ai3=m13;
+ m10 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ;
+ m11 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ;
+ m12 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ;
+ m13 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ;
+
+ ai0=m20; // row-2, m[2+0*4]
+ ai1=m21;
+ ai2=m22;
+ ai3=m23;
+ m20 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ;
+ m21 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ;
+ m22 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ;
+ m23 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ;
+
+ ai0=m30; // row-3, m[3+0*4]
+ ai1=m31;
+ ai2=m32;
+ ai3=m33;
+ m30 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ;
+ m31 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ;
+ m32 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ;
+ m33 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ;
+ return this;
+ }
+
+ /**
+ * Multiply matrix: [this] = [a] x [b]
+ *
+ * Roughly 13% faster than {@link #mul(Matrix4f)}
+ * Roughly 11% faster than {@link FloatUtil#multMatrix(float[], float[])}
+ *
+ * @param a 4x4 matrix, can't be this matrix
+ * @param b 4x4 matrix, can't be this matrix
+ * @return this matrix for chaining
+ * @see #mul(Matrix4f)
+ */
+ public final Matrix4f mul(final Matrix4f a, final Matrix4f b) {
+ // row-0, m[0+0*4]
+ m00 = a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20 + a.m03 * b.m30 ;
+ m01 = a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21 + a.m03 * b.m31 ;
+ m02 = a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22 + a.m03 * b.m32 ;
+ m03 = a.m00 * b.m03 + a.m01 * b.m13 + a.m02 * b.m23 + a.m03 * b.m33 ;
+
+ //row-1, m[1+0*4]
+ m10 = a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20 + a.m13 * b.m30 ;
+ m11 = a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31 ;
+ m12 = a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32 ;
+ m13 = a.m10 * b.m03 + a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33 ;
+
+ // row-2, m[2+0*4]
+ m20 = a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20 + a.m23 * b.m30 ;
+ m21 = a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31 ;
+ m22 = a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32 ;
+ m23 = a.m20 * b.m03 + a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33 ;
+
+ // row-3, m[3+0*4]
+ m30 = a.m30 * b.m00 + a.m31 * b.m10 + a.m32 * b.m20 + a.m33 * b.m30 ;
+ m31 = a.m30 * b.m01 + a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31 ;
+ m32 = a.m30 * b.m02 + a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32 ;
+ m33 = a.m30 * b.m03 + a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33 ;
+
+ return this;
+ }
+
+ /**
+ * @param v_in 4-component column-vector
+ * @param v_out this * v_in
+ * @returns v_out for chaining
+ */
+ public final float[] mulVec4f(final float[/*4*/] v_in, final float[/*4*/] v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_in[0], y = v_in[1], z = v_in[2], w = v_in[3];
+ v_out[0] = x * m00 + y * m01 + z * m02 + w * m03;
+ v_out[1] = x * m10 + y * m11 + z * m12 + w * m13;
+ v_out[2] = x * m20 + y * m21 + z * m22 + w * m23;
+ v_out[3] = x * m30 + y * m31 + z * m32 + w * m33;
+ return v_out;
+ }
+
+ /**
+ * @param v_in 4-component column-vector
+ * @param v_out this * v_in
+ * @returns v_out for chaining
+ */
+ public final Vec4f mulVec4f(final Vec4f v_in, final Vec4f v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_in.x(), y = v_in.y(), z = v_in.z(), w = v_in.w();
+ v_out.set( x * m00 + y * m01 + z * m02 + w * m03,
+ x * m10 + y * m11 + z * m12 + w * m13,
+ x * m20 + y * m21 + z * m22 + w * m23,
+ x * m30 + y * m31 + z * m32 + w * m33 );
+ return v_out;
+ }
+
+ /**
+ * Affine 3f-vector transformation by 4x4 matrix
+ *
+ * 4x4 matrix multiplication with 3-component vector,
+ * using {@code 1} for for {@code v_in[3]} and dropping {@code v_out[3]},
+ * which shall be {@code 1}.
+ *
+ * @param v_in 3-component column-vector
+ * @param v_out m_in * v_in, 3-component column-vector
+ * @returns v_out for chaining
+ */
+ public final float[] mulVec3f(final float[/*3*/] v_in, final float[/*3*/] v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_in[0], y = v_in[1], z = v_in[2];
+ v_out[0] = x * m00 + y * m01 + z * m02 + 1f * m03;
+ v_out[1] = x * m10 + y * m11 + z * m12 + 1f * m13;
+ v_out[2] = x * m20 + y * m21 + z * m22 + 1f * m23;
+ return v_out;
+ }
+
+ /**
+ * Affine 3f-vector transformation by 4x4 matrix
+ *
+ * 4x4 matrix multiplication with 3-component vector,
+ * using {@code 1} for for {@code v_in.w()} and dropping {@code v_out.w()},
+ * which shall be {@code 1}.
+ *
+ * @param v_in 3-component column-vector {@link Vec3f}
+ * @param v_out m_in * v_in, 3-component column-vector {@link Vec3f}
+ * @returns v_out for chaining
+ */
+ public final Vec3f mulVec3f(final Vec3f v_in, final Vec3f v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_in.x(), y = v_in.y(), z = v_in.z();
+ v_out.set( x * m00 + y * m01 + z * m02 + 1f * m03,
+ x * m10 + y * m11 + z * m12 + 1f * m13,
+ x * m20 + y * m21 + z * m22 + 1f * m23 );
+ return v_out;
+ }
+
+ //
+ // Matrix setTo...(), affine + basic
+ //
+
+ /**
+ * Set this matrix to translation.
+ *
+ Translation matrix (Column Order):
+ 1 0 0 0
+ 0 1 0 0
+ 0 0 1 0
+ x y z 1
+ *
+ * @param x x-axis translate
+ * @param y y-axis translate
+ * @param z z-axis translate
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToTranslation(final float x, final float y, final float z) {
+ m00 = m11 = m22 = m33 = 1.0f;
+ m03 = x;
+ m13 = y;
+ m23 = z;
+ m01 = m02 =
+ m10 = m12 =
+ m20 = m21 =
+ m30 = m31 = m32 = 0.0f;
+ return this;
+ }
+
+ /**
+ * Set this matrix to translation.
+ *
+ Translation matrix (Column Order):
+ 1 0 0 0
+ 0 1 0 0
+ 0 0 1 0
+ x y z 1
+ *
+ * @param t translate Vec3f
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToTranslation(final Vec3f t) {
+ return setToTranslation(t.x(), t.y(), t.z());
+ }
+
+ /**
+ * Set this matrix to scale.
+ *
+ Scale matrix (Any Order):
+ x 0 0 0
+ 0 y 0 0
+ 0 0 z 0
+ 0 0 0 1
+ *
+ * @param x x-axis scale
+ * @param y y-axis scale
+ * @param z z-axis scale
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToScale(final float x, final float y, final float z) {
+ m33 = 1.0f;
+ m00 = x;
+ m11 = y;
+ m22 = z;
+ m01 = m02 = m03 =
+ m10 = m12 = m13 =
+ m20 = m21 = m23 =
+ m30 = m31 = m32 = 0.0f;
+ return this;
+ }
+
+ /**
+ * Set this matrix to rotation from the given axis and angle in radians.
+ *
+ Rotation matrix (Column Order):
+ xx(1-c)+c xy(1-c)+zs xz(1-c)-ys 0
+ xy(1-c)-zs yy(1-c)+c yz(1-c)+xs 0
+ xz(1-c)+ys yz(1-c)-xs zz(1-c)+c 0
+ 0 0 0 1
+ *
+ * @see Matrix-FAQ Q38
+ * @param ang_rad angle in radians
+ * @param x x of rotation axis
+ * @param y y of rotation axis
+ * @param z z of rotation axis
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToRotationAxis(final float ang_rad, float x, float y, float z) {
+ final float c = FloatUtil.cos(ang_rad);
+ final float ic= 1.0f - c;
+ final float s = FloatUtil.sin(ang_rad);
+
+ final float[] tmpVec3f = { x, y, z };
+ VectorUtil.normalizeVec3(tmpVec3f);
+ x = tmpVec3f[0]; y = tmpVec3f[1]; z = tmpVec3f[2];
+
+ final float xy = x*y;
+ final float xz = x*z;
+ final float xs = x*s;
+ final float ys = y*s;
+ final float yz = y*z;
+ final float zs = z*s;
+ m00 = x*x*ic+c;
+ m10 = xy*ic+zs;
+ m20 = xz*ic-ys;
+ m30 = 0;
+
+ m01 = xy*ic-zs;
+ m11 = y*y*ic+c;
+ m21 = yz*ic+xs;
+ m31 = 0;
+
+ m02 = xz*ic+ys;
+ m12 = yz*ic-xs;
+ m22 = z*z*ic+c;
+ m32 = 0;
+
+ m03 = 0f;
+ m13 = 0f;
+ m23 = 0f;
+ m33 = 1f;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to rotation from the given axis and angle in radians.
+ *
+ Rotation matrix (Column Order):
+ xx(1-c)+c xy(1-c)+zs xz(1-c)-ys 0
+ xy(1-c)-zs yy(1-c)+c yz(1-c)+xs 0
+ xz(1-c)+ys yz(1-c)-xs zz(1-c)+c 0
+ 0 0 0 1
+ *
+ * @see Matrix-FAQ Q38
+ * @param ang_rad angle in radians
+ * @param axis rotation axis
+ * @return this matrix for chaining
+ */
+ public final Matrix4f setToRotationAxis(final float ang_rad, final Vec3f axis) {
+ return setToRotationAxis(ang_rad, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this matrix to rotation from the given Euler rotation angles in radians.
+ *
+ * The rotations are applied in the given order:
+ *
+ * - y - heading
+ * - z - attitude
+ * - x - bank
+ *
+ *
+ * @param bankX the Euler pitch angle in radians. (rotation about the X axis)
+ * @param headingY the Euler yaw angle in radians. (rotation about the Y axis)
+ * @param attitudeZ the Euler roll angle in radians. (rotation about the Z axis)
+ * @return this matrix for chaining
+ *
+ * Implementation does not use Quaternion and hence is exposed to
+ * Gimbal-Lock,
+ * consider using {@link #setToRotation(Quaternion)}.
+ *
+ * @see Matrix-FAQ Q36
+ * @see euclideanspace.com-eulerToMatrix
+ * @see #setToRotation(Quaternion)
+ */
+ public Matrix4f setToRotationEuler(final float bankX, final float headingY, final float attitudeZ) {
+ // Assuming the angles are in radians.
+ final float ch = FloatUtil.cos(headingY);
+ final float sh = FloatUtil.sin(headingY);
+ final float ca = FloatUtil.cos(attitudeZ);
+ final float sa = FloatUtil.sin(attitudeZ);
+ final float cb = FloatUtil.cos(bankX);
+ final float sb = FloatUtil.sin(bankX);
+
+ m00 = ch*ca;
+ m10 = sa;
+ m20 = -sh*ca;
+ m30 = 0;
+
+ m01 = sh*sb - ch*sa*cb;
+ m11 = ca*cb;
+ m21 = sh*sa*cb + ch*sb;
+ m31 = 0;
+
+ m02 = ch*sa*sb + sh*cb;
+ m12 = -ca*sb;
+ m22 = -sh*sa*sb + ch*cb;
+ m32 = 0;
+
+ m03 = 0;
+ m13 = 0;
+ m23 = 0;
+ m33 = 1;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to rotation using the given Quaternion.
+ *
+ * Implementation Details:
+ *
+ * - makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
+ * - The fields [m00 .. m22] define the rotation
+ *
+ *
+ *
+ * @param q the Quaternion representing the rotation
+ * @return this matrix for chaining
+ * @see Matrix-FAQ Q54
+ * @see Quaternion#toMatrix(float[], int)
+ * @see #getRotation()
+ */
+ public final Matrix4f setToRotation(final Quaternion q) {
+ // pre-multiply scaled-reciprocal-magnitude to reduce multiplications
+ final float norm = q.magnitudeSquared();
+ if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) {
+ // identity matrix -> srecip = 0f
+ loadIdentity();
+ return this;
+ }
+ final float srecip;
+ if ( FloatUtil.isEqual(1f, norm, FloatUtil.EPSILON) ) {
+ srecip = 2f;
+ } else {
+ srecip = 2.0f / norm;
+ }
+
+ final float x = q.x();
+ final float y = q.y();
+ final float z = q.z();
+ final float w = q.w();
+
+ final float xs = srecip * x;
+ final float ys = srecip * y;
+ final float zs = srecip * z;
+
+ final float xx = x * xs;
+ final float xy = x * ys;
+ final float xz = x * zs;
+ final float xw = xs * w;
+ final float yy = y * ys;
+ final float yz = y * zs;
+ final float yw = ys * w;
+ final float zz = z * zs;
+ final float zw = zs * w;
+
+ m00 = 1f - ( yy + zz );
+ m01 = ( xy - zw );
+ m02 = ( xz + yw );
+ m03 = 0f;
+
+ m10 = ( xy + zw );
+ m11 = 1f - ( xx + zz );
+ m12 = ( yz - xw );
+ m13 = 0f;
+
+ m20 = ( xz - yw );
+ m21 = ( yz + xw );
+ m22 = 1f - ( xx + yy );
+ m23 = 0f;
+
+ m30 = m31 = m32 = 0f;
+ m33 = 1f;
+ return this;
+ }
+
+ /**
+ * Returns the rotation [m00 .. m22] fields converted to a Quaternion.
+ * @param res resulting Quaternion
+ * @return the resulting Quaternion for chaining.
+ * @see Quaternion#setFromMatrix(float, float, float, float, float, float, float, float, float)
+ * @see #setToRotation(Quaternion)
+ */
+ public final Quaternion getRotation(final Quaternion res) {
+ res.setFromMatrix(m00, m01, m02, m10, m11, m12, m20, m21, m22);
+ return res;
+ }
+
+ /**
+ * Set this matrix to orthogonal projection.
+ *
+ Ortho matrix (Column Order):
+ 2/dx 0 0 0
+ 0 2/dy 0 0
+ 0 0 2/dz 0
+ tx ty tz 1
+ *
+ * @param left
+ * @param right
+ * @param bottom
+ * @param top
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ */
+ public Matrix4f setToOrtho(final float left, final float right,
+ final float bottom, final float top,
+ final float zNear, final float zFar) {
+ {
+ // m00 = m11 = m22 = m33 = 1f;
+ m10 = m20 = m30 = 0f;
+ m01 = m21 = m31 = 0f;
+ m02 = m12 = m32 = 0f;
+ // m03 = m13 = m23 = 0f;
+ }
+ final float dx=right-left;
+ final float dy=top-bottom;
+ final float dz=zFar-zNear;
+ final float tx=-1.0f*(right+left)/dx;
+ final float ty=-1.0f*(top+bottom)/dy;
+ final float tz=-1.0f*(zFar+zNear)/dz;
+
+ m00 = 2.0f/dx;
+ m11 = 2.0f/dy;
+ m22 = -2.0f/dz;
+
+ m03 = tx;
+ m13 = ty;
+ m23 = tz;
+ m33 = 1f;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to frustum.
+ *
+ Frustum matrix (Column Order):
+ 2*zNear/dx 0 0 0
+ 0 2*zNear/dy 0 0
+ A B C -1
+ 0 0 D 0
+ *
+ * @param left
+ * @param right
+ * @param bottom
+ * @param top
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}
+ * or {@code left == right}, or {@code bottom == top}.
+ */
+ public Matrix4f setToFrustum(final float left, final float right,
+ final float bottom, final float top,
+ final float zNear, final float zFar) throws IllegalArgumentException {
+ if( zNear <= 0.0f || zFar <= zNear ) {
+ throw new IllegalArgumentException("Requirements zNear > 0 and zFar > zNear, but zNear "+zNear+", zFar "+zFar);
+ }
+ if( left == right || top == bottom) {
+ throw new IllegalArgumentException("GL_INVALID_VALUE: top,bottom and left,right must not be equal");
+ }
+ {
+ // m00 = m11 = m22 = m33 = 1f;
+ m10 = m20 = m30 = 0f;
+ m01 = m21 = m31 = 0f;
+ m03 = m13 = 0f;
+ }
+ final float zNear2 = 2.0f*zNear;
+ final float dx=right-left;
+ final float dy=top-bottom;
+ final float dz=zFar-zNear;
+ final float A=(right+left)/dx;
+ final float B=(top+bottom)/dy;
+ final float C=-1.0f*(zFar+zNear)/dz;
+ final float D=-2.0f*(zFar*zNear)/dz;
+
+ m00 = zNear2/dx;
+ m11 = zNear2/dy;
+
+ m02 = A;
+ m12 = B;
+ m22 = C;
+ m32 = -1.0f;
+
+ m23 = D;
+ m33 = 0f;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to perspective {@link #setToFrustum(float, float, float, float, float, float) frustum} projection.
+ *
+ * @param fovy_rad angle in radians
+ * @param aspect aspect ratio width / height
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}
+ * @see #setToFrustum(float, float, float, float, float, float)
+ */
+ public Matrix4f setToPerspective(final float fovy_rad, final float aspect, final float zNear, final float zFar) throws IllegalArgumentException {
+ final float top = FloatUtil.tan(fovy_rad/2f) * zNear; // use tangent of half-fov !
+ final float bottom = -1.0f * top; // -1f * fovhvTan.top * zNear
+ final float left = aspect * bottom; // aspect * -1f * fovhvTan.top * zNear
+ final float right = aspect * top; // aspect * fovhvTan.top * zNear
+ return setToFrustum(left, right, bottom, top, zNear, zFar);
+ }
+
+ /**
+ * Set this matrix to perspective {@link #setToFrustum(float, float, float, float, float, float) frustum} projection.
+ *
+ * @param fovhv {@link FovHVHalves} field of view in both directions, may not be centered, either in radians or tangent
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}
+ * @see #setToFrustum(float, float, float, float, float, float)
+ * @see Frustum#updateByFovDesc(float[], int, boolean, Frustum.FovDesc)
+ */
+ public Matrix4f setToPerspective(final FovHVHalves fovhv, final float zNear, final float zFar) throws IllegalArgumentException {
+ final FovHVHalves fovhvTan = fovhv.toTangents(); // use tangent of half-fov !
+ final float top = fovhvTan.top * zNear;
+ final float bottom = -1.0f * fovhvTan.bottom * zNear;
+ final float left = -1.0f * fovhvTan.left * zNear;
+ final float right = fovhvTan.right * zNear;
+ return setToFrustum(left, right, bottom, top, zNear, zFar);
+ }
+
+ /**
+ * Calculate the frustum planes in world coordinates
+ * using the passed float[16] as premultiplied P*MV (column major order).
+ *
+ * Frustum plane's normals will point to the inside of the viewing frustum,
+ * as required by this class.
+ *
+ */
+ public void updateFrustumPlanes(final Frustum frustum) {
+ // Left: a = m41 + m11, b = m42 + m12, c = m43 + m13, d = m44 + m14 - [1..4] column-major
+ // Left: a = m30 + m00, b = m31 + m01, c = m32 + m02, d = m33 + m03 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.LEFT];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 + m00,
+ m31 + m01,
+ m32 + m02 );
+ p.d = m33 + m03;
+ }
+
+ // Right: a = m41 - m11, b = m42 - m12, c = m43 - m13, d = m44 - m14 - [1..4] column-major
+ // Right: a = m30 - m00, b = m31 - m01, c = m32 - m02, d = m33 - m03 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.RIGHT];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 - m00,
+ m31 - m01,
+ m32 - m02 );
+ p.d = m33 - m03;
+ }
+
+ // Bottom: a = m41m21, b = m42m22, c = m43m23, d = m44m24 - [1..4] column-major
+ // Bottom: a = m30m10, b = m31m11, c = m32m12, d = m33m13 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.BOTTOM];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 + m10,
+ m31 + m11,
+ m32 + m12 );
+ p.d = m33 + m13;
+ }
+
+ // Top: a = m41 - m21, b = m42 - m22, c = m43 - m23, d = m44 - m24 - [1..4] column-major
+ // Top: a = m30 - m10, b = m31 - m11, c = m32 - m12, d = m33 - m13 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.TOP];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 - m10,
+ m31 - m11,
+ m32 - m12 );
+ p.d = m33 - m13;
+ }
+
+ // Near: a = m41m31, b = m42m32, c = m43m33, d = m44m34 - [1..4] column-major
+ // Near: a = m30m20, b = m31m21, c = m32m22, d = m33m23 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.NEAR];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 + m20,
+ m31 + m21,
+ m32 + m22 );
+ p.d = m33 + m23;
+ }
+
+ // Far: a = m41 - m31, b = m42 - m32, c = m43 - m33, d = m44 - m34 - [1..4] column-major
+ // Far: a = m30 - m20, b = m31 - m21, c = m32m22, d = m33m23 - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.FAR];
+ final Vec3f p_n = p.n;
+ p_n.set( m30 - m20,
+ m31 - m21,
+ m32 - m22 );
+ p.d = m33 - m23;
+ }
+
+ // Normalize all planes
+ for (int i = 0; i < 6; ++i) {
+ final Plane p = frustum.getPlanes()[i];
+ final Vec3f p_n = p.n;
+ final float invLen = 1f / p_n.length();
+ p_n.scale(invLen);
+ p.d *= invLen;
+ }
+ }
+
+ /**
+ * Make given matrix the look-at matrix based on given parameters.
+ *
+ * Consist out of two matrix multiplications:
+ *
+ * R = L x T,
+ * with L for look-at matrix and
+ * T for eye translation.
+ *
+ * Result R can be utilized for projection or modelview multiplication, i.e.
+ * M = M x R,
+ * with M being the projection or modelview matrix.
+ *
+ *
+ * @param eye 3 component eye vector
+ * @param center 3 component center vector
+ * @param up 3 component up vector
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public Matrix4f setToLookAt(final Vec3f eye, final Vec3f center, final Vec3f up, final Matrix4f tmp) {
+ // normalized forward!
+ final Vec3f fwd = new Vec3f( center.x() - eye.x(),
+ center.y() - eye.y(),
+ center.z() - eye.z() ).normalize();
+
+ /* Side = forward x up, normalized */
+ final Vec3f side = fwd.cross(up).normalize();
+
+ /* Recompute up as: up = side x forward */
+ final Vec3f up2 = side.cross(fwd);
+
+ m00 = side.x();
+ m10 = up2.x();
+ m20 = -fwd.x();
+ m30 = 0;
+
+ m01 = side.y();
+ m11 = up2.y();
+ m21 = -fwd.y();
+ m31 = 0;
+
+ m02 = side.z();
+ m12 = up2.z();
+ m22 = -fwd.z();
+ m32 = 0;
+
+ m03 = 0;
+ m13 = 0;
+ m23 = 0;
+ m33 = 1;
+
+ return mul( tmp.setToTranslation( -eye.x(), -eye.y(), -eye.z() ) );
+ }
+
+ //
+ // Matrix affine operations using setTo..()
+ //
+
+ /**
+ * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(float, float, float, float) axis-rotation matrix}.
+ * @see Matrix-FAQ Q38
+ * @param angrad angle in radians
+ * @param x x of rotation axis
+ * @param y y of rotation axis
+ * @param z z of rotation axis
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f rotate(final float ang_rad, final float x, final float y, final float z, final Matrix4f tmp) {
+ return mul( tmp.setToRotationAxis(ang_rad, x, y, z) );
+ }
+
+ /**
+ * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(float, Vec3f) axis-rotation matrix}.
+ * @see Matrix-FAQ Q38
+ * @param angrad angle in radians
+ * @param axis rotation axis
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f rotate(final float ang_rad, final Vec3f axis, final Matrix4f tmp) {
+ return mul( tmp.setToRotationAxis(ang_rad, axis) );
+ }
+
+ /**
+ * Rotate this matrix with the given {@link Quaternion}, i.e. multiply by {@link #setToRotation(Quaternion) Quaternion's rotation matrix}.
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f rotate(final Quaternion quat, final Matrix4f tmp) {
+ return mul( tmp.setToRotation(quat) );
+ }
+
+ /**
+ * Translate this matrix, i.e. multiply by {@link #setToTranslation(float, float, float) translation matrix}.
+ * @param x x translation
+ * @param y y translation
+ * @param z z translation
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f translate(final float x, final float y, final float z, final Matrix4f tmp) {
+ return mul( tmp.setToTranslation(x, y, z) );
+ }
+
+ /**
+ * Translate this matrix, i.e. multiply by {@link #setToTranslation(Vec3f) translation matrix}.
+ * @param t translation Vec3f
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f translate(final Vec3f t, final Matrix4f tmp) {
+ return mul( tmp.setToTranslation(t) );
+ }
+
+ /**
+ * Scale this matrix, i.e. multiply by {@link #setToScale(float, float, float) scale matrix}.
+ * @param x x scale
+ * @param y y scale
+ * @param z z scale
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f scale(final float x, final float y, final float z, final Matrix4f tmp) {
+ return mul( tmp.setToScale(x, y, z) );
+ }
+
+ /**
+ * Scale this matrix, i.e. multiply by {@link #setToScale(float, float, float) scale matrix}.
+ * @param s scale for x-, y- and z-axis
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4f scale(final float s, final Matrix4f tmp) {
+ return mul( tmp.setToScale(s, s, s) );
+ }
+
+ //
+ // Matrix Stack
+ //
+
+ /**
+ * Push the matrix to it's stack, while preserving this matrix values.
+ * @see #pop()
+ */
+ public final void push() {
+ stack.push(this);
+ }
+
+ /**
+ * Pop the current matrix from it's stack, replacing this matrix values.
+ * @see #push()
+ */
+ public final void pop() {
+ stack.pop(this);
+ }
+
+ //
+ // equals
+ //
+
+ /**
+ * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ *
+ * Implementation considers following corner cases:
+ *
+ * - NaN == NaN
+ * - +Inf == +Inf
+ * - -Inf == -Inf
+ *
+ * @param o comparison value
+ * @param epsilon consider using {@link FloatUtil#EPSILON}
+ * @return true if all components differ less than {@code epsilon}, otherwise false.
+ */
+ public boolean isEqual(final Matrix4f o, final float epsilon) {
+ if( this == o ) {
+ return true;
+ } else {
+ return FloatUtil.isEqual(m00, o.m00, epsilon) &&
+ FloatUtil.isEqual(m01, o.m01, epsilon) &&
+ FloatUtil.isEqual(m02, o.m02, epsilon) &&
+ FloatUtil.isEqual(m03, o.m03, epsilon) &&
+ FloatUtil.isEqual(m10, o.m10, epsilon) &&
+ FloatUtil.isEqual(m11, o.m11, epsilon) &&
+ FloatUtil.isEqual(m12, o.m12, epsilon) &&
+ FloatUtil.isEqual(m13, o.m13, epsilon) &&
+ FloatUtil.isEqual(m20, o.m20, epsilon) &&
+ FloatUtil.isEqual(m21, o.m21, epsilon) &&
+ FloatUtil.isEqual(m22, o.m22, epsilon) &&
+ FloatUtil.isEqual(m23, o.m23, epsilon) &&
+ FloatUtil.isEqual(m30, o.m30, epsilon) &&
+ FloatUtil.isEqual(m31, o.m31, epsilon) &&
+ FloatUtil.isEqual(m32, o.m32, epsilon) &&
+ FloatUtil.isEqual(m33, o.m33, epsilon);
+ }
+ }
+
+ /**
+ * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ *
+ * Implementation considers following corner cases:
+ *
+ * - NaN == NaN
+ * - +Inf == +Inf
+ * - -Inf == -Inf
+ *
+ * @param o comparison value
+ * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false.
+ */
+ public boolean isEqual(final Matrix4f o) {
+ return isEqual(o, FloatUtil.EPSILON);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Matrix4f ) {
+ return isEqual((Matrix4f)o, FloatUtil.EPSILON);
+ } else {
+ return false;
+ }
+ }
+
+ //
+ // Static multi Matrix ops
+ //
+
+ /**
+ * Map object coordinates to window coordinates.
+ *
+ * Traditional gluProject
implementation.
+ *
+ *
+ * @param obj object position, 3 component vector
+ * @param mMv modelview matrix
+ * @param mP projection matrix
+ * @param viewport 4 component viewport vector
+ * @param winPos 3 component window coordinate, the result
+ * @return true if successful, otherwise false (z is 1)
+ */
+ public static boolean mapObjToWin(final Vec3f obj, final Matrix4f mMv, final Matrix4f mP,
+ final int[] viewport, final float[] winPos)
+ {
+ final Vec4f vec4Tmp1 = new Vec4f(obj, 1f);
+
+ // vec4Tmp2 = Mv * o
+ // rawWinPos = P * vec4Tmp2
+ // rawWinPos = P * ( Mv * o )
+ // rawWinPos = P * Mv * o
+ final Vec4f vec4Tmp2 = mMv.mulVec4f(vec4Tmp1, new Vec4f());
+ final Vec4f rawWinPos = mP.mulVec4f(vec4Tmp2, vec4Tmp1);
+
+ if (rawWinPos.w() == 0.0f) {
+ return false;
+ }
+
+ final float s = ( 1.0f / rawWinPos.w() ) * 0.5f;
+
+ // Map x, y and z to range 0-1 (w is ignored)
+ rawWinPos.scale(s).add(0.5f, 0.5f, 0.5f, 0f);
+
+ // Map x,y to viewport
+ winPos[0] = rawWinPos.x() * viewport[2] + viewport[0];
+ winPos[1] = rawWinPos.y() * viewport[3] + viewport[1];
+ winPos[2] = rawWinPos.z();
+
+ return true;
+ }
+
+ /**
+ * Map object coordinates to window coordinates.
+ *
+ * Traditional gluProject
implementation.
+ *
+ *
+ * @param obj object position, 3 component vector
+ * @param mPMv [projection] x [modelview] matrix, i.e. P x Mv
+ * @param viewport 4 component viewport vector
+ * @param winPos 3 component window coordinate, the result
+ * @return true if successful, otherwise false (z is 1)
+ */
+ public static boolean mapObjToWin(final Vec3f obj, final Matrix4f mPMv,
+ final int[] viewport, final float[] winPos)
+ {
+ final Vec4f vec4Tmp2 = new Vec4f(obj, 1f);
+
+ // rawWinPos = P * Mv * o
+ final Vec4f rawWinPos = mPMv.mulVec4f(vec4Tmp2, new Vec4f());
+
+ if (rawWinPos.w() == 0.0f) {
+ return false;
+ }
+
+ final float s = ( 1.0f / rawWinPos.w() ) * 0.5f;
+
+ // Map x, y and z to range 0-1 (w is ignored)
+ rawWinPos.scale(s).add(0.5f, 0.5f, 0.5f, 0f);
+
+ // Map x,y to viewport
+ winPos[0] = rawWinPos.x() * viewport[2] + viewport[0];
+ winPos[1] = rawWinPos.y() * viewport[3] + viewport[1];
+ winPos[2] = rawWinPos.z();
+
+ return true;
+ }
+
+ /**
+ * Map window coordinates to object coordinates.
+ *
+ * Traditional gluUnProject
implementation.
+ *
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param mMv 4x4 modelview matrix
+ * @param mP 4x4 projection matrix
+ * @param viewport 4 component viewport vector
+ * @param objPos 3 component object coordinate, the result
+ * @param mat4Tmp 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz,
+ final Matrix4f mMv, final Matrix4f mP,
+ final int[] viewport,
+ final Vec3f objPos,
+ final Matrix4f mat4Tmp)
+ {
+ // invPMv = Inv(P x Mv)
+ final Matrix4f invPMv = mat4Tmp.mul(mP, mMv);
+ if( !invPMv.invert() ) {
+ return false;
+ }
+
+ final Vec4f winPos = new Vec4f(winx, winy, winz, 1f);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport[0], -viewport[1], 0f, 0f).scale(1f/viewport[2], 1f/viewport[3], 1f, 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // rawObjPos = Inv(P x Mv) * winPos
+ final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f());
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ return true;
+ }
+
+ /**
+ * Map window coordinates to object coordinates.
+ *
+ * Traditional gluUnProject
implementation.
+ *
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv)
+ * @param viewport 4 component viewport vector
+ * @param objPos 3 component object coordinate, the result
+ * @param mat4Tmp 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz,
+ final Matrix4f invPMv,
+ final int[] viewport,
+ final Vec3f objPos,
+ final Matrix4f mat4Tmp)
+ {
+ final Vec4f winPos = new Vec4f(winx, winy, winz, 1f);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport[0], -viewport[1], 0f, 0f).scale(1f/viewport[2], 1f/viewport[3], 1f, 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // rawObjPos = Inv(P x Mv) * winPos
+ final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f());
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ return true;
+ }
+
+ /**
+ * Map two window coordinates to two object coordinates,
+ * distinguished by their z component.
+ *
+ * Traditional gluUnProject
implementation.
+ *
+ *
+ * @param winx
+ * @param winy
+ * @param winz1
+ * @param winz2
+ * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv)
+ * @param viewport 4 component viewport vector
+ * @param objPos1 3 component object coordinate, the result
+ * @param mat4Tmp 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz1, final float winz2,
+ final Matrix4f invPMv,
+ final int[] viewport,
+ final Vec3f objPos1, final Vec3f objPos2,
+ final Matrix4f mat4Tmp)
+ {
+ final Vec4f winPos = new Vec4f(winx, winy, winz1, 1f);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport[0], -viewport[1], 0f, 0f).scale(1f/viewport[2], 1f/viewport[3], 1f, 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // rawObjPos = Inv(P x Mv) * winPos1
+ final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f());
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos1.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ //
+ // winz2
+ //
+ // Map Z to range -1 to 1
+ winPos.setZ( winz2 * 2f - 1f );
+
+ // rawObjPos = Inv(P x Mv) * winPos2
+ invPMv.mulVec4f(winPos, rawObjPos);
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos2.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ return true;
+ }
+
+ /**
+ * Map window coordinates to object coordinates.
+ *
+ * Traditional gluUnProject4
implementation.
+ *
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param clipw
+ * @param mMv 4x4 modelview matrix
+ * @param mP 4x4 projection matrix
+ * @param viewport 4 component viewport vector
+ * @param near
+ * @param far
+ * @param obj_pos 4 component object coordinate, the result
+ * @param mat4Tmp 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj4(final float winx, final float winy, final float winz, final float clipw,
+ final Matrix4f mMv, final Matrix4f mP,
+ final int[] viewport,
+ final float near, final float far,
+ final Vec4f objPos,
+ final Matrix4f mat4Tmp)
+ {
+ // invPMv = Inv(P x Mv)
+ final Matrix4f invPMv = mat4Tmp.mul(mP, mMv);
+ if( !invPMv.invert() ) {
+ return false;
+ }
+
+ final Vec4f winPos = new Vec4f(winx, winy, winz, clipw);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport[0], -viewport[1], -near, 0f).scale(1f/viewport[2], 1f/viewport[3], 1f/(far-near), 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // objPos = Inv(P x Mv) * winPos
+ invPMv.mulVec4f(winPos, objPos);
+
+ if ( objPos.w() == 0.0f ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Map two window coordinates w/ shared X/Y and distinctive Z
+ * to a {@link Ray}. The resulting {@link Ray} maybe used for picking
+ * using a {@link AABBox#getRayIntersection(Ray, float[]) bounding box}.
+ *
+ * Notes for picking winz0 and winz1:
+ *
+ * - see {@link FloatUtil#getZBufferEpsilon(int, float, float)}
+ * - see {@link FloatUtil#getZBufferValue(int, float, float, float)}
+ * - see {@link FloatUtil#getOrthoWinZ(float, float, float)}
+ *
+ *
+ * @param winx
+ * @param winy
+ * @param winz0
+ * @param winz1
+ * @param mMv 4x4 modelview matrix
+ * @param mP 4x4 projection matrix
+ * @param viewport 4 component viewport vector
+ * @param ray storage for the resulting {@link Ray}
+ * @param mat4Tmp1 16 component matrix for temp storage
+ * @param mat4Tmp2 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes z is infinity)
+ */
+ public static boolean mapWinToRay(final float winx, final float winy, final float winz0, final float winz1,
+ final Matrix4f mMv,
+ final Matrix4f mP,
+ final int[] viewport,
+ final Ray ray,
+ final Matrix4f mat4Tmp1, final Matrix4f mat4Tmp2) {
+ // invPMv = Inv(P x Mv)
+ final Matrix4f invPMv = mat4Tmp1.mul(mP, mMv);
+ if( !invPMv.invert() ) {
+ return false;
+ }
+
+ if( mapWinToObj(winx, winy, winz0, winz1, invPMv, viewport,
+ ray.orig, ray.dir, mat4Tmp2) ) {
+ ray.dir.sub(ray.orig).normalize();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ //
+ // String and internals
+ //
+
+ /**
+ * @param sb optional passed StringBuilder instance to be used
+ * @param rowPrefix optional prefix for each row
+ * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
+ * @return matrix string representation
+ */
+ public StringBuilder toString(final StringBuilder sb, final String rowPrefix, final String f) {
+ final float[] tmp = new float[16];
+ this.get(tmp);
+ return FloatUtil.matrixToString(sb, rowPrefix, f,tmp, 0, 4, 4, false /* rowMajorOrder */);
+ }
+
+ @Override
+ public String toString() {
+ return toString(null, null, "%10.5f").toString();
+ }
+
+ private float m00, m10, m20, m30;
+ private float m01, m11, m21, m31;
+ private float m02, m12, m22, m32;
+ private float m03, m13, m23, m33;
+
+ final Stack stack = new Stack(0, 16*16); // start w/ zero size, growSize is half GL-min size (32)
+
+ private static class Stack {
+ private int position;
+ private float[] buffer;
+ private final int growSize;
+
+ /**
+ * @param initialSize initial size
+ * @param growSize grow size if {@link #position()} is reached, maybe 0
+ * in which case an {@link IndexOutOfBoundsException} is thrown.
+ */
+ public Stack(final int initialSize, final int growSize) {
+ this.position = 0;
+ this.growSize = growSize;
+ this.buffer = new float[initialSize];
+ }
+
+ private final void growIfNecessary(final int length) throws IndexOutOfBoundsException {
+ if( position + length > buffer.length ) {
+ if( 0 >= growSize ) {
+ throw new IndexOutOfBoundsException("Out of fixed stack size: "+this);
+ }
+ final float[] newBuffer =
+ new float[buffer.length + growSize];
+ System.arraycopy(buffer, 0, newBuffer, 0, position);
+ buffer = newBuffer;
+ }
+ }
+
+ public final Matrix4f push(final Matrix4f src) throws IndexOutOfBoundsException {
+ growIfNecessary(16);
+ src.get(buffer, position);
+ position += 16;
+ return src;
+ }
+
+ public final Matrix4f pop(final Matrix4f dest) throws IndexOutOfBoundsException {
+ position -= 16;
+ dest.load(buffer, position);
+ return dest;
+ }
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java b/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java
index 849477f54..2bb0f96c6 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -99,7 +99,7 @@ public class Quaternion {
return FloatUtil.sqrt(magnitudeSQ);
}
- public final float getW() {
+ public final float w() {
return w;
}
@@ -107,7 +107,7 @@ public class Quaternion {
this.w = w;
}
- public final float getX() {
+ public final float x() {
return x;
}
@@ -115,7 +115,7 @@ public class Quaternion {
this.x = x;
}
- public final float getY() {
+ public final float y() {
return y;
}
@@ -123,7 +123,7 @@ public class Quaternion {
this.y = y;
}
- public final float getZ() {
+ public final float z() {
return z;
}
@@ -142,15 +142,15 @@ public class Quaternion {
* Returns the dot product of this quaternion with the given quaternion
*/
public final float dot(final Quaternion quat) {
- return dot(quat.getX(), quat.getY(), quat.getZ(), quat.getW());
+ return dot(quat.x(), quat.y(), quat.z(), quat.w());
}
/**
* Returns true
if this quaternion has identity.
*
* Implementation uses {@link FloatUtil#EPSILON epsilon} to compare
- * {@link #getW() W} {@link FloatUtil#isEqual(float, float, float) against 1f} and
- * {@link #getX() X}, {@link #getY() Y} and {@link #getZ() Z}
+ * {@link #w() W} {@link FloatUtil#isEqual(float, float, float) against 1f} and
+ * {@link #x() X}, {@link #y() Y} and {@link #z() Z}
* {@link FloatUtil#isZero(float, float) against zero}.
*
*/
@@ -404,12 +404,12 @@ public class Quaternion {
*
*
* For details see {@link #rotateByEuler(float, float, float)}.
- * @param angradXYZ euler angel array in radians
+ * @param angradXYZ euler angle array in radians
* @return this quaternion for chaining.
* @see #rotateByEuler(float, float, float)
*/
- public final Quaternion rotateByEuler(final float[] angradXYZ) {
- return rotateByEuler(angradXYZ[0], angradXYZ[1], angradXYZ[2]);
+ public final Quaternion rotateByEuler(final Vec3f angradXYZ) {
+ return rotateByEuler(angradXYZ.x(), angradXYZ.y(), angradXYZ.z());
}
/**
@@ -450,48 +450,42 @@ public class Quaternion {
/***
* Rotate the given vector by this quaternion
+ * @param vecIn vector to be rotated
+ * @param vecOut result storage for rotated vector, maybe equal to vecIn for in-place rotation
*
- * @param vecOut result float[3] storage for rotated vector, maybe equal to vecIn for in-place rotation
- * @param vecOutOffset offset in result storage
- * @param vecIn float[3] vector to be rotated
- * @param vecInOffset offset in vecIn
* @return the given vecOut store for chaining
* @see Matrix-FAQ Q63
*/
- public final float[] rotateVector(final float[] vecOut, final int vecOutOffset, final float[] vecIn, final int vecInOffset) {
- if ( VectorUtil.isVec3Zero(vecIn, vecInOffset, FloatUtil.EPSILON) ) {
- vecOut[0+vecOutOffset] = 0f;
- vecOut[1+vecOutOffset] = 0f;
- vecOut[2+vecOutOffset] = 0f;
+ public final Vec3f rotateVector(final Vec3f vecIn, final Vec3f vecOut) {
+ if( vecIn.isZero() ) {
+ vecOut.set(0, 0, 0);
} else {
- final float vecX = vecIn[0+vecInOffset];
- final float vecY = vecIn[1+vecInOffset];
- final float vecZ = vecIn[2+vecInOffset];
+ final float vecX = vecIn.x();
+ final float vecY = vecIn.y();
+ final float vecZ = vecIn.z();
final float x_x = x*x;
final float y_y = y*y;
final float z_z = z*z;
final float w_w = w*w;
- vecOut[0+vecOutOffset] = w_w * vecX
- + x_x * vecX
- - z_z * vecX
- - y_y * vecX
- + 2f * ( y*w*vecZ - z*w*vecY + y*x*vecY + z*x*vecZ );
+ vecOut.setX( w_w * vecX
+ + x_x * vecX
+ - z_z * vecX
+ - y_y * vecX
+ + 2f * ( y*w*vecZ - z*w*vecY + y*x*vecY + z*x*vecZ ) );
;
- vecOut[1+vecOutOffset] = y_y * vecY
- - z_z * vecY
- + w_w * vecY
- - x_x * vecY
- + 2f * ( x*y*vecX + z*y*vecZ + w*z*vecX - x*w*vecZ );
- ;
-
- vecOut[2+vecOutOffset] = z_z * vecZ
- - y_y * vecZ
- - x_x * vecZ
- + w_w * vecZ
- + 2f * ( x*z*vecX + y*z*vecY - w*y*vecX + w*x*vecY );
- ;
+ vecOut.setY( y_y * vecY
+ - z_z * vecY
+ + w_w * vecY
+ - x_x * vecY
+ + 2f * ( x*y*vecX + z*y*vecZ + w*z*vecX - x*w*vecZ ) );;
+
+ vecOut.setZ( z_z * vecZ
+ - y_y * vecZ
+ - x_x * vecZ
+ + w_w * vecZ
+ + 2f * ( x*z*vecX + y*z*vecY - w*y*vecX + w*x*vecY ) );
}
return vecOut;
}
@@ -593,21 +587,19 @@ public class Quaternion {
* @return this quaternion for chaining.
* @see euclideanspace.com-LookUp
*/
- public Quaternion setLookAt(final float[] directionIn, final float[] upIn,
- final float[] xAxisOut, final float[] yAxisOut, final float[] zAxisOut) {
+ public Quaternion setLookAt(final Vec3f directionIn, final Vec3f upIn,
+ final Vec3f xAxisOut, final Vec3f yAxisOut, final Vec3f zAxisOut) {
// Z = norm(dir)
- VectorUtil.normalizeVec3(zAxisOut, directionIn);
+ zAxisOut.set(directionIn).normalize();
// X = upIn x Z
// (borrow yAxisOut for upNorm)
- VectorUtil.normalizeVec3(yAxisOut, upIn);
- VectorUtil.crossVec3(xAxisOut, yAxisOut, zAxisOut);
- VectorUtil.normalizeVec3(xAxisOut);
+ yAxisOut.set(upIn).normalize();
+ xAxisOut.cross(yAxisOut, zAxisOut).normalize();
// Y = Z x X
//
- VectorUtil.crossVec3(yAxisOut, zAxisOut, xAxisOut);
- VectorUtil.normalizeVec3(yAxisOut);
+ yAxisOut.cross(zAxisOut, xAxisOut).normalize();
/**
final float m00 = xAxisOut[0];
@@ -642,42 +634,42 @@ public class Quaternion {
*
* @param v1 not normalized
* @param v2 not normalized
- * @param tmpPivotVec float[3] temp storage for cross product
- * @param tmpNormalVec float[3] temp storage to normalize vector
+ * @param tmpPivotVec temp storage for cross product
+ * @param tmpNormalVec temp storage to normalize vector
* @return this quaternion for chaining.
*/
- public final Quaternion setFromVectors(final float[] v1, final float[] v2, final float[] tmpPivotVec, final float[] tmpNormalVec) {
- final float factor = VectorUtil.normVec3(v1) * VectorUtil.normVec3(v2);
+ public final Quaternion setFromVectors(final Vec3f v1, final Vec3f v2, final Vec3f tmpPivotVec, final Vec3f tmpNormalVec) {
+ final float factor = v1.length() * v2.length();
if ( FloatUtil.isZero(factor, FloatUtil.EPSILON ) ) {
return setIdentity();
} else {
- final float dot = VectorUtil.dotVec3(v1, v2) / factor; // normalize
+ final float dot = v1.dot(v2) / factor; // normalize
final float theta = FloatUtil.acos(Math.max(-1.0f, Math.min(dot, 1.0f))); // clipping [-1..1]
- VectorUtil.crossVec3(tmpPivotVec, v1, v2);
+ tmpPivotVec.cross(v1, v2);
- if ( dot < 0.0f && FloatUtil.isZero( VectorUtil.normVec3(tmpPivotVec), FloatUtil.EPSILON ) ) {
+ if ( dot < 0.0f && FloatUtil.isZero( tmpPivotVec.length(), FloatUtil.EPSILON ) ) {
// Vectors parallel and opposite direction, therefore a rotation of 180 degrees about any vector
// perpendicular to this vector will rotate vector a onto vector b.
//
// The following guarantees the dot-product will be 0.0.
int dominantIndex;
- if (Math.abs(v1[0]) > Math.abs(v1[1])) {
- if (Math.abs(v1[0]) > Math.abs(v1[2])) {
+ if (Math.abs(v1.x()) > Math.abs(v1.y())) {
+ if (Math.abs(v1.x()) > Math.abs(v1.z())) {
dominantIndex = 0;
} else {
dominantIndex = 2;
}
} else {
- if (Math.abs(v1[1]) > Math.abs(v1[2])) {
+ if (Math.abs(v1.y()) > Math.abs(v1.z())) {
dominantIndex = 1;
} else {
dominantIndex = 2;
}
}
- tmpPivotVec[dominantIndex] = -v1[(dominantIndex + 1) % 3];
- tmpPivotVec[(dominantIndex + 1) % 3] = v1[dominantIndex];
- tmpPivotVec[(dominantIndex + 2) % 3] = 0f;
+ tmpPivotVec.set( dominantIndex, -v1.get( (dominantIndex + 1) % 3 ) );
+ tmpPivotVec.set( (dominantIndex + 1) % 3, v1.get( dominantIndex ) );
+ tmpPivotVec.set( (dominantIndex + 2) % 3, 0f );
}
return setFromAngleAxis(theta, tmpPivotVec, tmpNormalVec);
}
@@ -698,41 +690,41 @@ public class Quaternion {
*
* @param v1 normalized
* @param v2 normalized
- * @param tmpPivotVec float[3] temp storage for cross product
+ * @param tmpPivotVec temp storage for cross product
* @return this quaternion for chaining.
*/
- public final Quaternion setFromNormalVectors(final float[] v1, final float[] v2, final float[] tmpPivotVec) {
- final float factor = VectorUtil.normVec3(v1) * VectorUtil.normVec3(v2);
+ public final Quaternion setFromNormalVectors(final Vec3f v1, final Vec3f v2, final Vec3f tmpPivotVec) {
+ final float factor = v1.length() * v2.length();
if ( FloatUtil.isZero(factor, FloatUtil.EPSILON ) ) {
return setIdentity();
} else {
- final float dot = VectorUtil.dotVec3(v1, v2) / factor; // normalize
+ final float dot = v1.dot(v2) / factor; // normalize
final float theta = FloatUtil.acos(Math.max(-1.0f, Math.min(dot, 1.0f))); // clipping [-1..1]
- VectorUtil.crossVec3(tmpPivotVec, v1, v2);
+ tmpPivotVec.cross(v1, v2);
- if ( dot < 0.0f && FloatUtil.isZero( VectorUtil.normVec3(tmpPivotVec), FloatUtil.EPSILON ) ) {
+ if ( dot < 0.0f && FloatUtil.isZero( tmpPivotVec.length(), FloatUtil.EPSILON ) ) {
// Vectors parallel and opposite direction, therefore a rotation of 180 degrees about any vector
// perpendicular to this vector will rotate vector a onto vector b.
//
// The following guarantees the dot-product will be 0.0.
int dominantIndex;
- if (Math.abs(v1[0]) > Math.abs(v1[1])) {
- if (Math.abs(v1[0]) > Math.abs(v1[2])) {
+ if (Math.abs(v1.x()) > Math.abs(v1.y())) {
+ if (Math.abs(v1.x()) > Math.abs(v1.z())) {
dominantIndex = 0;
} else {
dominantIndex = 2;
}
} else {
- if (Math.abs(v1[1]) > Math.abs(v1[2])) {
+ if (Math.abs(v1.y()) > Math.abs(v1.z())) {
dominantIndex = 1;
} else {
dominantIndex = 2;
}
}
- tmpPivotVec[dominantIndex] = -v1[(dominantIndex + 1) % 3];
- tmpPivotVec[(dominantIndex + 1) % 3] = v1[dominantIndex];
- tmpPivotVec[(dominantIndex + 2) % 3] = 0f;
+ tmpPivotVec.set( dominantIndex, -v1.get( (dominantIndex + 1) % 3 ) );
+ tmpPivotVec.set( (dominantIndex + 1) % 3, v1.get( dominantIndex ) );
+ tmpPivotVec.set( (dominantIndex + 2) % 3, 0f );
}
return setFromAngleNormalAxis(theta, tmpPivotVec);
}
@@ -748,14 +740,14 @@ public class Quaternion {
*
* @param angle rotation angle (rads)
* @param vector axis vector not normalized
- * @param tmpV3f float[3] temp storage to normalize vector
+ * @param tmpV3f temp storage to normalize vector
* @return this quaternion for chaining.
*
* @see Matrix-FAQ Q56
- * @see #toAngleAxis(float[])
+ * @see #toAngleAxis(Vec3f)
*/
- public final Quaternion setFromAngleAxis(final float angle, final float[] vector, final float[] tmpV3f) {
- VectorUtil.normalizeVec3(tmpV3f, vector);
+ public final Quaternion setFromAngleAxis(final float angle, final Vec3f vector, final Vec3f tmpV3f) {
+ tmpV3f.set(vector).normalize();
return setFromAngleNormalAxis(angle, tmpV3f);
}
@@ -772,17 +764,17 @@ public class Quaternion {
* @return this quaternion for chaining.
*
* @see Matrix-FAQ Q56
- * @see #toAngleAxis(float[])
+ * @see #toAngleAxis(Vec3f)
*/
- public final Quaternion setFromAngleNormalAxis(final float angle, final float[] vector) {
- if ( VectorUtil.isVec3Zero(vector, 0, FloatUtil.EPSILON) ) {
+ public final Quaternion setFromAngleNormalAxis(final float angle, final Vec3f vector) {
+ if( vector.isZero() ) {
setIdentity();
} else {
final float halfangle = angle * 0.5f;
final float sin = FloatUtil.sin(halfangle);
- x = vector[0] * sin;
- y = vector[1] * sin;
- z = vector[2] * sin;
+ x = vector.x() * sin;
+ y = vector.y() * sin;
+ z = vector.z() * sin;
w = FloatUtil.cos(halfangle);
}
return this;
@@ -791,24 +783,22 @@ public class Quaternion {
/**
* Transform the rotational quaternion to axis based rotation angles
*
- * @param axis float[3] storage for computed axis
+ * @param axis storage for computed axis
* @return the rotation angle in radians
- * @see #setFromAngleAxis(float, float[], float[])
+ * @see #setFromAngleAxis(float, Vec3f, Vec3f)
*/
- public final float toAngleAxis(final float[] axis) {
+ public final float toAngleAxis(final Vec3f axis) {
final float sqrLength = x*x + y*y + z*z;
float angle;
if ( FloatUtil.isZero(sqrLength, FloatUtil.EPSILON) ) { // length is ~0
angle = 0.0f;
- axis[0] = 1.0f;
- axis[1] = 0.0f;
- axis[2] = 0.0f;
+ axis.set( 1.0f, 0.0f, 0.0f );
} else {
angle = FloatUtil.acos(w) * 2.0f;
final float invLength = 1.0f / FloatUtil.sqrt(sqrLength);
- axis[0] = x * invLength;
- axis[1] = y * invLength;
- axis[2] = z * invLength;
+ axis.set( x * invLength,
+ y * invLength,
+ z * invLength );
}
return angle;
}
@@ -816,7 +806,7 @@ public class Quaternion {
/**
* Initializes this quaternion from the given Euler rotation array angradXYZ
in radians.
*
- * The angradXYZ
array is laid out in natural order:
+ * The angradXYZ
vector is laid out in natural order:
*
* - x - bank
* - y - heading
@@ -824,12 +814,12 @@ public class Quaternion {
*
*
* For details see {@link #setFromEuler(float, float, float)}.
- * @param angradXYZ euler angel array in radians
+ * @param angradXYZ euler angle vector in radians holding x-bank, y-heading and z-attitude
* @return this quaternion for chaining.
* @see #setFromEuler(float, float, float)
*/
- public final Quaternion setFromEuler(final float[] angradXYZ) {
- return setFromEuler(angradXYZ[0], angradXYZ[1], angradXYZ[2]);
+ public final Quaternion setFromEuler(final Vec3f angradXYZ) {
+ return setFromEuler(angradXYZ.x(), angradXYZ.y(), angradXYZ.z());
}
/**
@@ -857,7 +847,7 @@ public class Quaternion {
* @see Matrix-FAQ Q60
* @see Gems
* @see euclideanspace.com-eulerToQuaternion
- * @see #toEuler(float[])
+ * @see #toEuler(Vec3f)
*/
public final Quaternion setFromEuler(final float bankX, final float headingY, final float attitudeZ) {
if ( VectorUtil.isZero(bankX, headingY, attitudeZ, FloatUtil.EPSILON) ) {
@@ -889,57 +879,44 @@ public class Quaternion {
/**
* Transform this quaternion to Euler rotation angles in radians (pitchX, yawY and rollZ).
+ *
+ * The result
array is laid out in natural order:
+ *
+ * - x - bank
+ * - y - heading
+ * - z - attitude
+ *
+ *
*
- * @param result the float[] array storing the computed angles.
- * @return the double[] array, filled with heading, attitude and bank in that order..
+ * @param result euler angle result vector for radians x-bank, y-heading and z-attitude
+ * @return the Vec3f `result` filled with x-bank, y-heading and z-attitude
* @see euclideanspace.com-quaternionToEuler
* @see #setFromEuler(float, float, float)
*/
- public float[] toEuler(final float[] result) {
+ public Vec3f toEuler(final Vec3f result) {
final float sqw = w*w;
final float sqx = x*x;
final float sqy = y*y;
final float sqz = z*z;
- final float unit = sqx + sqy + sqz + sqw; // if normalized is one, otherwise
- // is correction factor
+ final float unit = sqx + sqy + sqz + sqw; // if normalized is one, otherwise, is correction factor
final float test = x*y + z*w;
if (test > 0.499f * unit) { // singularity at north pole
- result[0] = 0f;
- result[1] = 2f * FloatUtil.atan2(x, w);
- result[2] = FloatUtil.HALF_PI;
+ result.set( 0f, // x-bank
+ 2f * FloatUtil.atan2(x, w), // y-heading
+ FloatUtil.HALF_PI ); // z-attitude
} else if (test < -0.499f * unit) { // singularity at south pole
- result[0] = 0f;
- result[1] = -2 * FloatUtil.atan2(x, w);
- result[2] = -FloatUtil.HALF_PI;
+ result.set( 0f, // x-bank
+ -2 * FloatUtil.atan2(x, w), // y-heading
+ -FloatUtil.HALF_PI ); // z-attitude
} else {
- result[0] = FloatUtil.atan2(2f * x * w - 2 * y * z, -sqx + sqy - sqz + sqw);
- result[1] = FloatUtil.atan2(2f * y * w - 2 * x * z, sqx - sqy - sqz + sqw);
- result[2] = FloatUtil.asin( 2f * test / unit);
+ result.set( FloatUtil.atan2(2f * x * w - 2 * y * z, -sqx + sqy - sqz + sqw), // x-bank
+ FloatUtil.atan2(2f * y * w - 2 * x * z, sqx - sqy - sqz + sqw), // y-heading
+ FloatUtil.asin( 2f * test / unit) ); // z-attitude
}
return result;
}
- /**
- * Initializes this quaternion from a 4x4 column rotation matrix
- *
- * See Graphics Gems Code,
- * MatrixTrace.
- *
- *
- * Buggy Matrix-FAQ Q55
- *
- *
- * @param m 4x4 column matrix
- * @return this quaternion for chaining.
- * @see #toMatrix(float[], int)
- */
- public final Quaternion setFromMatrix(final float[] m, final int m_off) {
- return setFromMatrix(m[0+0*4+m_off], m[0+1*4+m_off], m[0+2*4+m_off],
- m[1+0*4+m_off], m[1+1*4+m_off], m[1+2*4+m_off],
- m[2+0*4+m_off], m[2+1*4+m_off], m[2+2*4+m_off]);
- }
-
/**
* Compute the quaternion from a 3x3 column rotation matrix
*
@@ -951,7 +928,7 @@ public class Quaternion {
*
*
* @return this quaternion for chaining.
- * @see #toMatrix(float[], int)
+ * @see #setFromMatrix(Matrix4f)
*/
public Quaternion setFromMatrix(final float m00, final float m01, final float m02,
final float m10, final float m11, final float m12,
@@ -995,6 +972,24 @@ public class Quaternion {
return this;
}
+ /**
+ * Compute the quaternion from a 3x3 column rotation matrix
+ *
+ * See Graphics Gems Code,
+ * MatrixTrace.
+ *
+ *
+ * Buggy Matrix-FAQ Q55
+ *
+ *
+ * @return this quaternion for chaining.
+ * @see Matrix4f#getRotation(Quaternion)
+ * @see #setFromMatrix(float, float, float, float, float, float, float, float, float)
+ */
+ public Quaternion setFromMatrix(final Matrix4f m) {
+ return m.getRotation(this);
+ }
+
/**
* Transform this quaternion to a normalized 4x4 column matrix representing the rotation.
*
@@ -1008,7 +1003,8 @@ public class Quaternion {
* @param mat_offset
* @return the given matrix store
* @see Matrix-FAQ Q54
- * @see #setFromMatrix(float[], int)
+ * @see #setFromMatrix(Matrix4f)
+ * @see #setFromMatrix(float, float, float, float, float, float, float, float, float)
*/
public final float[] toMatrix(final float[] matrix, final int mat_offset) {
// pre-multiply scaled-reciprocal-magnitude to reduce multiplications
@@ -1061,58 +1057,22 @@ public class Quaternion {
}
/**
- * @param index the 3x3 rotation matrix column to retrieve from this quaternion (normalized). Must be between 0 and 2.
- * @param result the vector object to store the result in.
- * @return the result column-vector for chaining.
+ * Transform this quaternion to a normalized 4x4 column matrix representing the rotation.
+ *
+ * Implementation Details:
+ *
+ * - makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
+ *
+ *
+ *
+ * @param matrix store for the resulting normalized column matrix 4x4
+ * @return the given matrix store
+ * @see Matrix-FAQ Q54
+ * @see #setFromMatrix(float, float, float, float, float, float, float, float, float)
+ * @see Matrix4f#setToRotation(Quaternion)
*/
- public float[] copyMatrixColumn(final int index, final float[] result, final int resultOffset) {
- // pre-multipliy scaled-reciprocal-magnitude to reduce multiplications
- final float norm = magnitudeSquared();
- final float srecip;
- if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) {
- srecip= 0f;
- } else if ( FloatUtil.isEqual(1f, norm, FloatUtil.EPSILON) ) {
- srecip= 2f;
- } else {
- srecip= 2.0f / norm;
- }
-
- // compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs
- // will be used 2-4 times each.
- final float xs = x * srecip;
- final float ys = y * srecip;
- final float zs = z * srecip;
- final float xx = x * xs;
- final float xy = x * ys;
- final float xz = x * zs;
- final float xw = w * xs;
- final float yy = y * ys;
- final float yz = y * zs;
- final float yw = w * ys;
- final float zz = z * zs;
- final float zw = w * zs;
-
- // using s=2/norm (instead of 1/norm) saves 3 multiplications by 2 here
- switch (index) {
- case 0:
- result[0+resultOffset] = 1.0f - (yy + zz);
- result[1+resultOffset] = xy + zw;
- result[2+resultOffset] = xz - yw;
- break;
- case 1:
- result[0+resultOffset] = xy - zw;
- result[1+resultOffset] = 1.0f - (xx + zz);
- result[2+resultOffset] = yz + xw;
- break;
- case 2:
- result[0+resultOffset] = xz + yw;
- result[1+resultOffset] = yz - xw;
- result[2+resultOffset] = 1.0f - (xx + yy);
- break;
- default:
- throw new IllegalArgumentException("Invalid column index. " + index);
- }
- return result;
+ public final Matrix4f toMatrix(final Matrix4f matrix) {
+ return matrix.setToRotation(this);
}
/**
@@ -1126,10 +1086,10 @@ public class Quaternion {
* @param zAxis vector representing the orthogonal z-axis of the coordinate system.
* @return this quaternion for chaining.
*/
- public final Quaternion setFromAxes(final float[] xAxis, final float[] yAxis, final float[] zAxis) {
- return setFromMatrix(xAxis[0], yAxis[0], zAxis[0],
- xAxis[1], yAxis[1], zAxis[1],
- xAxis[2], yAxis[2], zAxis[2]);
+ public final Quaternion setFromAxes(final Vec3f xAxis, final Vec3f yAxis, final Vec3f zAxis) {
+ return setFromMatrix(xAxis.x(), yAxis.x(), zAxis.x(),
+ xAxis.y(), yAxis.y(), zAxis.y(),
+ xAxis.z(), yAxis.z(), zAxis.z());
}
/**
@@ -1140,11 +1100,11 @@ public class Quaternion {
* @param zAxis vector representing the orthogonal z-axis of the coordinate system.
* @param tmpMat4 temporary float[4] matrix, used to transform this quaternion to a matrix.
*/
- public void toAxes(final float[] xAxis, final float[] yAxis, final float[] zAxis, final float[] tmpMat4) {
- toMatrix(tmpMat4, 0);
- FloatUtil.copyMatrixColumn(tmpMat4, 0, 2, zAxis, 0);
- FloatUtil.copyMatrixColumn(tmpMat4, 0, 1, yAxis, 0);
- FloatUtil.copyMatrixColumn(tmpMat4, 0, 0, xAxis, 0);
+ public void toAxes(final Vec3f xAxis, final Vec3f yAxis, final Vec3f zAxis, final Matrix4f tmpMat4) {
+ tmpMat4.setToRotation(this);
+ tmpMat4.getColumn(2, zAxis);
+ tmpMat4.getColumn(1, yAxis);
+ tmpMat4.getColumn(0, xAxis);
}
/**
@@ -1154,6 +1114,7 @@ public class Quaternion {
* @param m 3x3 column matrix
* @return true if representing a rotational matrix, false otherwise
*/
+ @Deprecated
public final boolean isRotationMatrix3f(final float[] m) {
final float epsilon = 0.01f; // margin to allow for rounding errors
if (FloatUtil.abs(m[0] * m[3] + m[3] * m[4] + m[6] * m[7]) > epsilon)
@@ -1171,6 +1132,7 @@ public class Quaternion {
return (FloatUtil.abs(determinant3f(m) - 1) < epsilon);
}
+ @Deprecated
private final float determinant3f(final float[] m) {
return m[0] * m[4] * m[8] + m[3] * m[7] * m[2] + m[6] * m[1] * m[5]
- m[0] * m[7] * m[5] - m[3] * m[1] * m[8] - m[6] * m[4] * m[2];
@@ -1193,10 +1155,10 @@ public class Quaternion {
return false;
}
final Quaternion comp = (Quaternion) o;
- return Math.abs(x - comp.getX()) <= ALLOWED_DEVIANCE &&
- Math.abs(y - comp.getY()) <= ALLOWED_DEVIANCE &&
- Math.abs(z - comp.getZ()) <= ALLOWED_DEVIANCE &&
- Math.abs(w - comp.getW()) <= ALLOWED_DEVIANCE;
+ return Math.abs(x - comp.x()) <= ALLOWED_DEVIANCE &&
+ Math.abs(y - comp.y()) <= ALLOWED_DEVIANCE &&
+ Math.abs(z - comp.z()) <= ALLOWED_DEVIANCE &&
+ Math.abs(w - comp.w()) <= ALLOWED_DEVIANCE;
}
@Override
public final int hashCode() {
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Ray.java b/src/jogl/classes/com/jogamp/opengl/math/Ray.java
index a528f0763..25a7d9a70 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/Ray.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/Ray.java
@@ -47,14 +47,14 @@ import com.jogamp.opengl.math.geom.AABBox;
*
*/
public class Ray {
- /** Origin of Ray, float[3]. */
- public final float[] orig = new float[3];
+ /** Origin of Ray. */
+ public final Vec3f orig = new Vec3f();
- /** Normalized direction vector of ray, float[3]. */
- public final float[] dir = new float[3];
+ /** Normalized direction vector of ray. */
+ public final Vec3f dir = new Vec3f();
@Override
public String toString() {
- return "Ray[orig["+orig[0]+", "+orig[1]+", "+orig[2]+"], dir["+dir[0]+", "+dir[1]+", "+dir[2]+"]]";
+ return "Ray[orig["+orig+"], dir["+dir+"]]";
}
}
\ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec2f.java b/src/jogl/classes/com/jogamp/opengl/math/Vec2f.java
index 0b67102fb..0c7854216 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/Vec2f.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/Vec2f.java
@@ -48,6 +48,11 @@ public final class Vec2f {
set(o);
}
+ /** Creating new Vec2f using Vec3f, dropping z. */
+ public Vec2f(final Vec3f o) {
+ set(o);
+ }
+
public Vec2f copy() {
return new Vec2f(this);
}
@@ -66,6 +71,12 @@ public final class Vec2f {
this.y = o.y;
}
+ /** this = o while dropping z, returns this. */
+ public void set(final Vec3f o) {
+ this.x = o.x();
+ this.y = o.y();
+ }
+
/** this = { x, y }, returns this. */
public void set(final float x, final float y) {
this.x = x;
@@ -88,6 +99,13 @@ public final class Vec2f {
}
}
+ /** xy = this, returns xy. */
+ public float[] get(final float[/*2*/] xy) {
+ xy[0] = this.x;
+ xy[1] = this.y;
+ return xy;
+ }
+
/** Gets the ith component, 0 <= i < 2 */
public float get(final int i) {
switch (i) {
@@ -108,10 +126,17 @@ public final class Vec2f {
return new Vec2f(this).scale(val);
}
- /** this = this * val, returns this. */
- public Vec2f scale(final float val) {
- x *= val;
- y *= val;
+ /** this = this * s, returns this. */
+ public Vec2f scale(final float s) {
+ x *= s;
+ y *= s;
+ return this;
+ }
+
+ /** this = this * { sx, sy }, returns this. */
+ public Vec2f scale(final float sx, final float sy) {
+ x *= sx;
+ y *= sy;
return this;
}
@@ -158,6 +183,7 @@ public final class Vec2f {
return this;
}
+ /** Return true if all components are zero, i.e. it's absolute value < {@link #EPSILON}. */
public boolean isZero() {
return FloatUtil.isZero(x) && FloatUtil.isZero(y);
}
@@ -282,6 +308,53 @@ public final class Vec2f {
return true;
}
+ /**
+ * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ *
+ * Implementation considers following corner cases:
+ *
+ * - NaN == NaN
+ * - +Inf == +Inf
+ * - -Inf == -Inf
+ *
+ * @param o comparison value
+ * @param epsilon consider using {@link FloatUtil#EPSILON}
+ * @return true if all components differ less than {@code epsilon}, otherwise false.
+ */
+ public boolean isEqual(final Vec2f o, final float epsilon) {
+ if( this == o ) {
+ return true;
+ } else {
+ return FloatUtil.isEqual(x, o.x, epsilon) &&
+ FloatUtil.isEqual(y, o.y, epsilon);
+ }
+ }
+
+ /**
+ * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ *
+ * Implementation considers following corner cases:
+ *
+ * - NaN == NaN
+ * - +Inf == +Inf
+ * - -Inf == -Inf
+ *
+ * @param o comparison value
+ * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false.
+ */
+ public boolean isEqual(final Vec2f o) {
+ return isEqual(o, FloatUtil.EPSILON);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Vec2f ) {
+ return isEqual((Vec2f)o, FloatUtil.EPSILON);
+ } else {
+ return false;
+ }
+ }
+
@Override
public String toString() {
return x + " / " + y;
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec3f.java b/src/jogl/classes/com/jogamp/opengl/math/Vec3f.java
index 9cead54c2..d5c725ad7 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/Vec3f.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/Vec3f.java
@@ -35,6 +35,12 @@ package com.jogamp.opengl.math;
* and its data layout from JOAL's Vec3f.
*/
public final class Vec3f {
+ public static final Vec3f ONE = new Vec3f(VectorUtil.VEC3_ONE);
+ public static final Vec3f UNIT_Y = new Vec3f(VectorUtil.VEC3_UNIT_Y);
+ public static final Vec3f UNIT_Y_NEG = new Vec3f(VectorUtil.VEC3_UNIT_Y_NEG);
+ public static final Vec3f UNIT_Z = new Vec3f(VectorUtil.VEC3_UNIT_Z);
+ public static final Vec3f UNIT_Z_NEG = new Vec3f(VectorUtil.VEC3_UNIT_Z_NEG);
+
private float x;
private float y;
private float z;
@@ -45,6 +51,16 @@ public final class Vec3f {
set(o);
}
+ /** Creating new Vec3f using Vec4f, dropping w. */
+ public Vec3f(final Vec4f o) {
+ set(o);
+ }
+
+ /** Creating new Vec3f using { Vec2f, z}. */
+ public Vec3f(final Vec2f o, final float z) {
+ set(o, z);
+ }
+
public Vec3f copy() {
return new Vec3f(this);
}
@@ -65,6 +81,22 @@ public final class Vec3f {
return this;
}
+ /** this = { o, z }, returns this. */
+ public Vec3f set(final Vec2f o, final float z) {
+ this.x = o.x();
+ this.y = o.y();
+ this.z = z;
+ return this;
+ }
+
+ /** this = o while dropping w, returns this. */
+ public Vec3f set(final Vec4f o) {
+ this.x = o.x();
+ this.y = o.y();
+ this.z = o.z();
+ return this;
+ }
+
/** this = { x, y, z }, returns this. */
public Vec3f set(final float x, final float y, final float z) {
this.x = x;
@@ -91,6 +123,14 @@ public final class Vec3f {
}
}
+ /** xyz = this, returns xyz. */
+ public float[] get(final float[/*3*/] xyz) {
+ xyz[0] = this.x;
+ xyz[1] = this.y;
+ xyz[2] = this.z;
+ return xyz;
+ }
+
/** Gets the ith component, 0 <= i < 3 */
public float get(final int i) {
switch (i) {
@@ -114,11 +154,19 @@ public final class Vec3f {
return new Vec3f(this).scale(val);
}
- /** this = this * val, returns this. */
- public Vec3f scale(final float val) {
- x *= val;
- y *= val;
- z *= val;
+ /** this = this * s, returns this. */
+ public Vec3f scale(final float s) {
+ x *= s;
+ y *= s;
+ z *= s;
+ return this;
+ }
+
+ /** this = this * { sx, sy, sz }, returns this. */
+ public Vec3f scale(final float sx, final float sy, final float sz) {
+ x *= sx;
+ y *= sy;
+ z *= sz;
return this;
}
@@ -169,7 +217,8 @@ public final class Vec3f {
return this;
}
- public boolean is_zero() {
+ /** Return true if all components are zero, i.e. it's absolute value < {@link #EPSILON}. */
+ public boolean isZero() {
return FloatUtil.isZero(x) && FloatUtil.isZero(y) && FloatUtil.isZero(z);
}
@@ -266,8 +315,57 @@ public final class Vec3f {
public boolean intersects(final Vec3f o) {
if( Math.abs(x-o.x) >= FloatUtil.EPSILON || Math.abs(y-o.y) >= FloatUtil.EPSILON || Math.abs(z-o.z) >= FloatUtil.EPSILON ) {
return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ *
+ * Implementation considers following corner cases:
+ *
+ * - NaN == NaN
+ * - +Inf == +Inf
+ * - -Inf == -Inf
+ *
+ * @param o comparison value
+ * @param epsilon consider using {@link FloatUtil#EPSILON}
+ * @return true if all components differ less than {@code epsilon}, otherwise false.
+ */
+ public boolean isEqual(final Vec3f o, final float epsilon) {
+ if( this == o ) {
+ return true;
+ } else {
+ return FloatUtil.isEqual(x, o.x, epsilon) &&
+ FloatUtil.isEqual(y, o.y, epsilon) &&
+ FloatUtil.isEqual(z, o.z, epsilon);
+ }
+ }
+
+ /**
+ * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ *
+ * Implementation considers following corner cases:
+ *
+ * - NaN == NaN
+ * - +Inf == +Inf
+ * - -Inf == -Inf
+ *
+ * @param o comparison value
+ * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false.
+ */
+ public boolean isEqual(final Vec3f o) {
+ return isEqual(o, FloatUtil.EPSILON);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Vec3f ) {
+ return isEqual((Vec3f)o, FloatUtil.EPSILON);
+ } else {
+ return false;
}
- return true;
}
@Override
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec4f.java b/src/jogl/classes/com/jogamp/opengl/math/Vec4f.java
new file mode 100644
index 000000000..1a20015a9
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/math/Vec4f.java
@@ -0,0 +1,348 @@
+/**
+ * Copyright 2022-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.math;
+
+/**
+ * 4D Vector based upon four float components.
+ *
+ * Implementation borrowed from [gfxbox2](https://jausoft.com/cgit/cs_class/gfxbox2.git/tree/include/pixel/pixel3f.hpp#n29)
+ * and its data layout from JOAL's Vec3f.
+ */
+public final class Vec4f {
+ private float x;
+ private float y;
+ private float z;
+ private float w;
+
+ public Vec4f() {}
+
+ public Vec4f(final Vec4f o) {
+ set(o);
+ }
+
+ /** Creating new Vec4f using { o, w }. */
+ public Vec4f(final Vec3f o, final float w) {
+ set(o, w);
+ }
+
+ public Vec4f copy() {
+ return new Vec4f(this);
+ }
+
+ public Vec4f(final float[/*4*/] xyzw) {
+ set(xyzw);
+ }
+
+ public Vec4f(final float x, final float y, final float z, final float w) {
+ set(x, y, z, w);
+ }
+
+ /** this = o, returns this. */
+ public Vec4f set(final Vec4f o) {
+ this.x = o.x;
+ this.y = o.y;
+ this.z = o.z;
+ this.w = o.w;
+ return this;
+ }
+
+ /** this = { o, w }, returns this. */
+ public Vec4f set(final Vec3f o, final float w) {
+ this.x = o.x();
+ this.y = o.y();
+ this.z = o.z();
+ this.w = w;
+ return this;
+ }
+
+ /** this = { x, y, z, w }, returns this. */
+ public Vec4f set(final float x, final float y, final float z, final float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /** this = xyzw, returns this. */
+ public Vec4f set(final float[/*4*/] xyzw) {
+ this.x = xyzw[0];
+ this.y = xyzw[1];
+ this.z = xyzw[2];
+ this.w = xyzw[3];
+ return this;
+ }
+
+ /** Sets the ith component, 0 <= i < 4 */
+ public void set(final int i, final float val) {
+ switch (i) {
+ case 0: x = val; break;
+ case 1: y = val; break;
+ case 2: z = val; break;
+ case 3: w = val; break;
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /** xyzw = this, returns xyzw. */
+ public float[] get(final float[/*4*/] xyzw) {
+ xyzw[0] = this.x;
+ xyzw[1] = this.y;
+ xyzw[2] = this.z;
+ xyzw[3] = this.w;
+ return xyzw;
+ }
+
+ /** Gets the ith component, 0 <= i < 4 */
+ public float get(final int i) {
+ switch (i) {
+ case 0: return x;
+ case 1: return y;
+ case 2: return z;
+ case 3: return w;
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public float x() { return x; }
+ public float y() { return y; }
+ public float z() { return z; }
+ public float w() { return w; }
+
+ public void setX(final float x) { this.x = x; }
+ public void setY(final float y) { this.y = y; }
+ public void setZ(final float z) { this.z = z; }
+ public void setW(final float w) { this.w = w; }
+
+ /** Returns this * val; creates new vector */
+ public Vec4f mul(final float val) {
+ return new Vec4f(this).scale(val);
+ }
+
+ /** this = this * s, returns this. */
+ public Vec4f scale(final float s) {
+ x *= s;
+ y *= s;
+ z *= s;
+ w *= s;
+ return this;
+ }
+
+ /** this = this * { sx, sy, sz, sw }, returns this. */
+ public Vec4f scale(final float sx, final float sy, final float sz, final float sw) {
+ x *= sx;
+ y *= sy;
+ z *= sz;
+ w *= sw;
+ return this;
+ }
+
+ /** Returns this + arg; creates new vector */
+ public Vec4f plus(final Vec4f arg) {
+ return new Vec4f(this).add(arg);
+ }
+
+ /** this = this + { dx, dy, dz, dw }, returns this. */
+ public Vec4f add(final float dx, final float dy, final float dz, final float dw) {
+ x += dx;
+ y += dy;
+ z += dz;
+ w += dw;
+ return this;
+ }
+
+ /** this = this + b, returns this. */
+ public Vec4f add(final Vec4f b) {
+ x += b.x;
+ y += b.y;
+ z += b.z;
+ w += b.w;
+ return this;
+ }
+
+ /** Returns this - arg; creates new vector */
+ public Vec4f minus(final Vec4f arg) {
+ return new Vec4f(this).sub(arg);
+ }
+
+ /** this = this - b, returns this. */
+ public Vec4f sub(final Vec4f b) {
+ x -= b.x;
+ y -= b.y;
+ z -= b.z;
+ w -= b.w;
+ return this;
+ }
+
+ /** Return true if all components are zero, i.e. it's absolute value < {@link #EPSILON}. */
+ public boolean isZero() {
+ return FloatUtil.isZero(x) && FloatUtil.isZero(y) && FloatUtil.isZero(z) && FloatUtil.isZero(w);
+ }
+
+ /**
+ * Return the length of this vector, a.k.a the norm or magnitude
+ */
+ public float length() {
+ return (float) Math.sqrt(lengthSq());
+ }
+
+ /**
+ * Return the squared length of this vector, a.k.a the squared norm or squared magnitude
+ */
+ public float lengthSq() {
+ return x*x + y*y + z*z + w*w;
+ }
+
+ /**
+ * Normalize this vector in place
+ */
+ public Vec4f normalize() {
+ final float lengthSq = lengthSq();
+ if ( FloatUtil.isZero( lengthSq ) ) {
+ x = 0.0f;
+ y = 0.0f;
+ z = 0.0f;
+ w = 0.0f;
+ } else {
+ final float invSqr = 1.0f / (float)Math.sqrt(lengthSq);
+ x *= invSqr;
+ y *= invSqr;
+ z *= invSqr;
+ w *= invSqr;
+ }
+ return this;
+ }
+
+ /**
+ * Return the squared distance between this vector and the given one.
+ *
+ * When comparing the relative distance between two points it is usually sufficient to compare the squared
+ * distances, thus avoiding an expensive square root operation.
+ *
+ */
+ public float distSq(final Vec4f o) {
+ final float dx = x - o.x;
+ final float dy = y - o.y;
+ final float dz = z - o.z;
+ final float dw = w - o.w;
+ return dx*dx + dy*dy + dz*dz + dw*dw;
+ }
+
+ /**
+ * Return the distance between this vector and the given one.
+ */
+ public float dist(final Vec4f o) {
+ return (float)Math.sqrt(distSq(o));
+ }
+
+
+ /**
+ * Return the dot product of this vector and the given one
+ * @return the dot product as float
+ */
+ public float dot(final Vec4f o) {
+ return x*o.x + y*o.y + z*o.z + w*o.w;
+ }
+
+ /**
+ * Return the cosines of the angle between two vectors
+ */
+ public float cosAngle(final Vec4f o) {
+ return dot(o) / ( length() * o.length() ) ;
+ }
+
+ /**
+ * Return the angle between two vectors in radians
+ */
+ public float angle(final Vec4f o) {
+ return (float) Math.acos( cosAngle(o) );
+ }
+
+ public boolean intersects(final Vec4f o) {
+ if( Math.abs(x-o.x) >= FloatUtil.EPSILON || Math.abs(y-o.y) >= FloatUtil.EPSILON || Math.abs(z-o.z) >= FloatUtil.EPSILON ||
+ Math.abs(w-o.w) >= FloatUtil.EPSILON) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ *
+ * Implementation considers following corner cases:
+ *
+ * - NaN == NaN
+ * - +Inf == +Inf
+ * - -Inf == -Inf
+ *
+ * @param o comparison value
+ * @param epsilon consider using {@link FloatUtil#EPSILON}
+ * @return true if all components differ less than {@code epsilon}, otherwise false.
+ */
+ public boolean isEqual(final Vec4f o, final float epsilon) {
+ if( this == o ) {
+ return true;
+ } else {
+ return FloatUtil.isEqual(x, o.x, epsilon) &&
+ FloatUtil.isEqual(y, o.y, epsilon) &&
+ FloatUtil.isEqual(z, o.z, epsilon) &&
+ FloatUtil.isEqual(w, o.w, epsilon);
+ }
+ }
+
+ /**
+ * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ *
+ * Implementation considers following corner cases:
+ *
+ * - NaN == NaN
+ * - +Inf == +Inf
+ * - -Inf == -Inf
+ *
+ * @param o comparison value
+ * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false.
+ */
+ public boolean isEqual(final Vec4f o) {
+ return isEqual(o, FloatUtil.EPSILON);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Vec4f ) {
+ return isEqual((Vec4f)o, FloatUtil.EPSILON);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return x + " / " + y + " / " + z + " / " + w;
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java
index a07153155..8edbd0cd7 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -34,7 +34,6 @@ import com.jogamp.graph.geom.plane.Winding;
public final class VectorUtil {
public static final float[] VEC3_ONE = { 1f, 1f, 1f };
- public static final float[] VEC3_ZERO = { 0f, 0f, 0f };
public static final float[] VEC3_UNIT_Y = { 0f, 1f, 0f };
public static final float[] VEC3_UNIT_Y_NEG = { 0f, -1f, 0f };
public static final float[] VEC3_UNIT_Z = { 0f, 0f, 1f };
@@ -1025,14 +1024,15 @@ public final class VectorUtil {
* @param epsilon
* @return resulting intersecting if exists, otherwise null
*/
- public static float[] line2PlaneIntersection(final float[] result, final Ray ray, final float[/*4*/] plane, final float epsilon) {
- final float tmp = dotVec3(ray.dir, plane) ;
+ public static Vec3f line2PlaneIntersection(final Vec3f result, final Ray ray, final Vec4f plane, final float epsilon) {
+ final Vec3f plane3 = new Vec3f(plane);
+ final float tmp = ray.dir.dot(plane3);
if ( Math.abs(tmp) < epsilon ) {
return null; // ray is parallel to plane
}
- scaleVec3 ( result, ray.dir, -( dotVec3(ray.orig, plane) + plane[3] ) / tmp ) ;
- return addVec3(result, result, ray.orig);
+ result.set( ray.dir );
+ return result.scale( -( ray.orig.dot(plane3) + plane.w() ) / tmp ).add(ray.orig);
}
/** Compute intersection between two segments
diff --git a/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java b/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java
index f858b1c0d..9e8edfbf0 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -29,9 +29,11 @@ package com.jogamp.opengl.math.geom;
import com.jogamp.graph.geom.plane.AffineTransform;
import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.Quaternion;
import com.jogamp.opengl.math.Ray;
-import com.jogamp.opengl.math.VectorUtil;
+import com.jogamp.opengl.math.Vec3f;
+import com.jogamp.opengl.util.PMVMatrix;
/**
@@ -51,9 +53,9 @@ import com.jogamp.opengl.math.VectorUtil;
*/
public class AABBox {
private static final boolean DEBUG = FloatUtil.DEBUG;
- private final float[] low = new float[3];
- private final float[] high = new float[3];
- private final float[] center = new float[3];
+ private final Vec3f low = new Vec3f();
+ private final Vec3f high = new Vec3f();
+ private final Vec3f center = new Vec3f();
/**
* Create an Axis Aligned bounding box (AABBox) with the
@@ -109,42 +111,34 @@ public class AABBox {
public final AABBox reset() {
setLow(Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE);
setHigh(-1*Float.MAX_VALUE,-1*Float.MAX_VALUE,-1*Float.MAX_VALUE);
- center[0] = 0f;
- center[1] = 0f;
- center[2] = 0f;
+ center.set( 0f, 0f, 0f);
return this;
}
/** Get the max xyz-coordinates
- * @return a float array containing the max xyz coordinates
+ * @return max xyz coordinates
*/
- public final float[] getHigh() {
+ public final Vec3f getHigh() {
return high;
}
private final void setHigh(final float hx, final float hy, final float hz) {
- this.high[0] = hx;
- this.high[1] = hy;
- this.high[2] = hz;
+ this.high.set(hx, hy, hz);
}
/** Get the min xyz-coordinates
- * @return a float array containing the min xyz coordinates
+ * @return min xyz coordinates
*/
- public final float[] getLow() {
+ public final Vec3f getLow() {
return low;
}
private final void setLow(final float lx, final float ly, final float lz) {
- this.low[0] = lx;
- this.low[1] = ly;
- this.low[2] = lz;
+ this.low.set(lx, ly, lz);
}
private final void computeCenter() {
- center[0] = (high[0] + low[0])/2f;
- center[1] = (high[1] + low[1])/2f;
- center[2] = (high[2] + low[2])/2f;
+ center.set(high).add(low).scale(1f/2f);
}
/**
@@ -154,9 +148,9 @@ public class AABBox {
* @return this AABBox for chaining
*/
public final AABBox copy(final AABBox src) {
- System.arraycopy(src.low, 0, low, 0, 3);
- System.arraycopy(src.high, 0, high, 0, 3);
- System.arraycopy(src.center, 0, center, 0, 3);
+ low.set(src.low);
+ high.set(src.high);
+ center.set(src.center);
return this;
}
@@ -186,12 +180,23 @@ public class AABBox {
*/
public final AABBox setSize(final float lx, final float ly, final float lz,
final float hx, final float hy, final float hz) {
- this.low[0] = lx;
- this.low[1] = ly;
- this.low[2] = lz;
- this.high[0] = hx;
- this.high[1] = hy;
- this.high[2] = hz;
+ this.low.set(lx, ly, lz);
+ this.high.set(hx, hy, hz);
+ computeCenter();
+ return this;
+ }
+
+ /**
+ * Set size of the AABBox specifying the coordinates
+ * of the low and high.
+ *
+ * @param low min xyz-coordinates
+ * @param high max xyz-coordinates
+ * @return this AABBox for chaining
+ */
+ public final AABBox setSize(final Vec3f low, final Vec3f high) {
+ this.low.set(low);
+ this.high.set(high);
computeCenter();
return this;
}
@@ -202,25 +207,30 @@ public class AABBox {
* @return this AABBox for chaining
*/
public final AABBox resize(final AABBox newBox) {
- final float[] newLow = newBox.getLow();
- final float[] newHigh = newBox.getHigh();
+ final Vec3f newLow = newBox.getLow();
+ final Vec3f newHigh = newBox.getHigh();
/** test low */
- if (newLow[0] < low[0])
- low[0] = newLow[0];
- if (newLow[1] < low[1])
- low[1] = newLow[1];
- if (newLow[2] < low[2])
- low[2] = newLow[2];
+ if (newLow.x() < low.x()) {
+ low.setX( newLow.x() );
+ }
+ if (newLow.y() < low.y()) {
+ low.setY( newLow.y() );
+ }
+ if (newLow.z() < low.z()) {
+ low.setZ( newLow.z() );
+ }
/** test high */
- if (newHigh[0] > high[0])
- high[0] = newHigh[0];
- if (newHigh[1] > high[1])
- high[1] = newHigh[1];
- if (newHigh[2] > high[2])
- high[2] = newHigh[2];
-
+ if (newHigh.x() > high.x()) {
+ high.setX( newHigh.x() );
+ }
+ if (newHigh.y() > high.y()) {
+ high.setY( newHigh.y() );
+ }
+ if (newHigh.z() > high.z()) {
+ high.setZ( newHigh.z() );
+ }
computeCenter();
return this;
}
@@ -229,34 +239,32 @@ public class AABBox {
* Resize the AABBox to encapsulate another AABox, which will be transformed on the fly first.
* @param newBox AABBox to be encapsulated in
* @param t the {@link AffineTransform} applied on newBox on the fly
- * @param tmpV3 temp float[3] storage
+ * @param tmpV3 temporary storage
* @return this AABBox for chaining
*/
- public final AABBox resize(final AABBox newBox, final AffineTransform t, final float[] tmpV3) {
+ public final AABBox resize(final AABBox newBox, final AffineTransform t, final Vec3f tmpV3) {
/** test low */
{
- final float[] newBoxLow = newBox.getLow();
+ final Vec3f newBoxLow = newBox.getLow();
t.transform(newBoxLow, tmpV3);
- tmpV3[2] = newBoxLow[2];
- if (tmpV3[0] < low[0])
- low[0] = tmpV3[0];
- if (tmpV3[1] < low[1])
- low[1] = tmpV3[1];
- if (tmpV3[2] < low[2])
- low[2] = tmpV3[2];
+ if (tmpV3.x() < low.x())
+ low.setX( tmpV3.x() );
+ if (tmpV3.y() < low.y())
+ low.setY( tmpV3.y() );
+ if (tmpV3.z() < low.z())
+ low.setZ( tmpV3.z() );
}
/** test high */
{
- final float[] newBoxHigh = newBox.getHigh();
+ final Vec3f newBoxHigh = newBox.getHigh();
t.transform(newBoxHigh, tmpV3);
- tmpV3[2] = newBoxHigh[2];
- if (tmpV3[0] > high[0])
- high[0] = tmpV3[0];
- if (tmpV3[1] > high[1])
- high[1] = tmpV3[1];
- if (tmpV3[2] > high[2])
- high[2] = tmpV3[2];
+ if (tmpV3.x() > high.x())
+ high.setX( tmpV3.x() );
+ if (tmpV3.y() > high.y())
+ high.setY( tmpV3.y() );
+ if (tmpV3.z() > high.z())
+ high.setZ( tmpV3.z() );
}
computeCenter();
@@ -273,25 +281,25 @@ public class AABBox {
*/
public final AABBox resize(final float x, final float y, final float z) {
/** test low */
- if (x < low[0]) {
- low[0] = x;
+ if (x < low.x()) {
+ low.setX( x );
}
- if (y < low[1]) {
- low[1] = y;
+ if (y < low.y()) {
+ low.setY( y );
}
- if (z < low[2]) {
- low[2] = z;
+ if (z < low.z()) {
+ low.setZ( z );
}
/** test high */
- if (x > high[0]) {
- high[0] = x;
+ if (x > high.x()) {
+ high.setX( x );
}
- if (y > high[1]) {
- high[1] = y;
+ if (y > high.y()) {
+ high.setY( y );
}
- if (z > high[2]) {
- high[2] = z;
+ if (z > high.z()) {
+ high.setZ( z );
}
computeCenter();
@@ -319,6 +327,16 @@ public class AABBox {
return resize(xyz[0], xyz[1], xyz[2]);
}
+ /**
+ * Resize the AABBox to encapsulate the passed
+ * xyz-coordinates.
+ * @param xyz xyz-axis coordinate values
+ * @return this AABBox for chaining
+ */
+ public final AABBox resize(final Vec3f xyz) {
+ return resize(xyz.x(), xyz.y(), xyz.z());
+ }
+
/**
* Check if the x & y coordinates are bounded/contained
* by this AABBox
@@ -328,10 +346,10 @@ public class AABBox {
* y belong to (low.y, high.y)
*/
public final boolean contains(final float x, final float y) {
- if(xhigh[0]){
+ if(xhigh.x()){
return false;
}
- if(yhigh[1]){
+ if(yhigh.y()){
return false;
}
return true;
@@ -347,13 +365,13 @@ public class AABBox {
* y belong to (low.y, high.y) and z belong to (low.z, high.z)
*/
public final boolean contains(final float x, final float y, final float z) {
- if(xhigh[0]){
+ if(xhigh.x()){
return false;
}
- if(yhigh[1]){
+ if(yhigh.y()){
return false;
}
- if(zhigh[2]){
+ if(zhigh.z()){
return false;
}
return true;
@@ -390,13 +408,13 @@ public class AABBox {
/**
* Check if {@link Ray} intersects this bounding box.
*
- * Versions uses the SAT[1], testing 6 axes.
+ * Versions uses the SAT.y(), testing 6 axes.
* Original code for OBBs from MAGIC.
- * Rewritten for AABBs and reorganized for early exits[2].
+ * Rewritten for AABBs and reorganized for early exits.z().
*
*
- * [1] SAT = Separating Axis Theorem
- * [2] http://www.codercorner.com/RayAABB.cpp
+ * .y() SAT = Separating Axis Theorem
+ * .z() http://www.codercorner.com/RayAABB.cpp
*
* @param ray
* @return
@@ -405,19 +423,19 @@ public class AABBox {
// diff[XYZ] -> VectorUtil.subVec3(diff, ray.orig, center);
// ext[XYZ] -> extend VectorUtil.subVec3(ext, high, center);
- final float dirX = ray.dir[0];
- final float diffX = ray.orig[0] - center[0];
- final float extX = high[0] - center[0];
+ final float dirX = ray.dir.x();
+ final float diffX = ray.orig.x() - center.x();
+ final float extX = high.x() - center.x();
if( Math.abs(diffX) > extX && diffX*dirX >= 0f ) return false;
- final float dirY = ray.dir[1];
- final float diffY = ray.orig[1] - center[1];
- final float extY = high[1] - center[1];
+ final float dirY = ray.dir.y();
+ final float diffY = ray.orig.y() - center.y();
+ final float extY = high.y() - center.y();
if( Math.abs(diffY) > extY && diffY*dirY >= 0f ) return false;
- final float dirZ = ray.dir[2];
- final float diffZ = ray.orig[2] - center[2];
- final float extZ = high[2] - center[2];
+ final float dirZ = ray.dir.z();
+ final float diffZ = ray.orig.z() - center.z();
+ final float extZ = high.z() - center.z();
if( Math.abs(diffZ) > extZ && diffZ*dirZ >= 0f ) return false;
final float absDirY = Math.abs(dirY);
@@ -442,7 +460,7 @@ public class AABBox {
* or null if none exist.
*
*
- * - Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 [2]
+ * - Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 .z()
* - Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500)
* - Epsilon value added by Klaus Hartmann.
*
@@ -458,8 +476,8 @@ public class AABBox {
* Report bugs: p.terdiman@codercorner.com (original author)
*
*
- * [1] http://www.codercorner.com/RayAABB.cpp
- * [2] http://tog.acm.org/resources/GraphicsGems/gems/RayBox.c
+ * .y() http://www.codercorner.com/RayAABB.cpp
+ * .z() http://tog.acm.org/resources/GraphicsGems/gems/RayBox.c
*
* @param result vec3
* @param ray
@@ -467,45 +485,45 @@ public class AABBox {
* @param assumeIntersection if true, method assumes an intersection, i.e. by pre-checking via {@link #intersectsRay(Ray)}.
* In this case method will not validate a possible non-intersection and just computes
* coordinates.
- * @param tmp1V3 temp vec3
- * @param tmp2V3 temp vec3
- * @param tmp3V3 temp vec3
* @return float[3] result of intersection coordinates, or null if none exists
*/
- public final float[] getRayIntersection(final float[] result, final Ray ray, final float epsilon,
- final boolean assumeIntersection,
- final float[] tmp1V3, final float[] tmp2V3, final float[] tmp3V3) {
+ public final Vec3f getRayIntersection(final Vec3f result, final Ray ray, final float epsilon,
+ final boolean assumeIntersection) {
final float[] maxT = { -1f, -1f, -1f };
- final float[] origin = ray.orig;
- final float[] dir = ray.dir;
+ final Vec3f origin = ray.orig;
+ final Vec3f dir = ray.dir;
boolean inside = true;
// Find candidate planes.
for(int i=0; i<3; i++) {
- if(origin[i] < low[i]) {
- result[i] = low[i];
+ final float origin_i = origin.get(i);
+ final float dir_i = dir.get(i);
+ final float low_i = low.get(i);
+ final float high_i = high.get(i);
+ if(origin_i < low_i) {
+ result.set(i, low_i);
inside = false;
// Calculate T distances to candidate planes
- if( 0 != Float.floatToIntBits(dir[i]) ) {
- maxT[i] = (low[i] - origin[i]) / dir[i];
+ if( 0 != Float.floatToIntBits(dir_i) ) {
+ maxT[i] = (low_i - origin_i) / dir_i;
}
- } else if(origin[i] > high[i]) {
- result[i] = high[i];
+ } else if(origin_i > high_i) {
+ result.set(i, high_i);
inside = false;
// Calculate T distances to candidate planes
- if( 0 != Float.floatToIntBits(dir[i]) ) {
- maxT[i] = (high[i] - origin[i]) / dir[i];
+ if( 0 != Float.floatToIntBits(dir_i) ) {
+ maxT[i] = (high_i - origin_i) / dir_i;
}
}
}
// Ray origin inside bounding box
if(inside) {
- System.arraycopy(origin, 0, result, 0, 3);
+ result.set(origin);
return result;
}
@@ -530,22 +548,22 @@ public class AABBox {
} */
switch( whichPlane ) {
case 0:
- result[1] = origin[1] + maxT[whichPlane] * dir[1];
- if(result[1] < low[1] - epsilon || result[1] > high[1] + epsilon) { return null; }
- result[2] = origin[2] + maxT[whichPlane] * dir[2];
- if(result[2] < low[2] - epsilon || result[2] > high[2] + epsilon) { return null; }
+ result.setY( origin.y() + maxT[whichPlane] * dir.y() );
+ if(result.y() < low.y() - epsilon || result.y() > high.y() + epsilon) { return null; }
+ result.setZ( origin.z() + maxT[whichPlane] * dir.z() );
+ if(result.z() < low.z() - epsilon || result.z() > high.z() + epsilon) { return null; }
break;
case 1:
- result[0] = origin[0] + maxT[whichPlane] * dir[0];
- if(result[0] < low[0] - epsilon || result[0] > high[0] + epsilon) { return null; }
- result[2] = origin[2] + maxT[whichPlane] * dir[2];
- if(result[2] < low[2] - epsilon || result[2] > high[2] + epsilon) { return null; }
+ result.setX( origin.x() + maxT[whichPlane] * dir.x() );
+ if(result.x() < low.x() - epsilon || result.x() > high.x() + epsilon) { return null; }
+ result.setZ( origin.z() + maxT[whichPlane] * dir.z() );
+ if(result.z() < low.z() - epsilon || result.z() > high.z() + epsilon) { return null; }
break;
case 2:
- result[0] = origin[0] + maxT[whichPlane] * dir[0];
- if(result[0] < low[0] - epsilon || result[0] > high[0] + epsilon) { return null; }
- result[1] = origin[1] + maxT[whichPlane] * dir[1];
- if(result[1] < low[1] - epsilon || result[1] > high[1] + epsilon) { return null; }
+ result.setX( origin.x() + maxT[whichPlane] * dir.x() );
+ if(result.x() < low.x() - epsilon || result.x() > high.x() + epsilon) { return null; }
+ result.setY( origin.y() + maxT[whichPlane] * dir.y() );
+ if(result.y() < low.y() - epsilon || result.y() > high.y() + epsilon) { return null; }
break;
default:
throw new InternalError("XXX");
@@ -553,16 +571,16 @@ public class AABBox {
} else {
switch( whichPlane ) {
case 0:
- result[1] = origin[1] + maxT[whichPlane] * dir[1];
- result[2] = origin[2] + maxT[whichPlane] * dir[2];
+ result.setY( origin.y() + maxT[whichPlane] * dir.y() );
+ result.setZ( origin.z() + maxT[whichPlane] * dir.z() );
break;
case 1:
- result[0] = origin[0] + maxT[whichPlane] * dir[0];
- result[2] = origin[2] + maxT[whichPlane] * dir[2];
+ result.setX( origin.x() + maxT[whichPlane] * dir.x() );
+ result.setZ( origin.z() + maxT[whichPlane] * dir.z() );
break;
case 2:
- result[0] = origin[0] + maxT[whichPlane] * dir[0];
- result[1] = origin[1] + maxT[whichPlane] * dir[1];
+ result.setX( origin.x() + maxT[whichPlane] * dir.x() );
+ result.setY( origin.y() + maxT[whichPlane] * dir.y() );
break;
default:
throw new InternalError("XXX");
@@ -577,14 +595,14 @@ public class AABBox {
* @return a float representing the size of the AABBox
*/
public final float getSize() {
- return VectorUtil.distVec3(low, high);
+ return low.dist(high);
}
/**
* Get the Center of this AABBox
* @return the xyz-coordinates of the center of the AABBox
*/
- public final float[] getCenter() {
+ public final Vec3f getCenter() {
return center;
}
@@ -594,24 +612,17 @@ public class AABBox {
* high and low is recomputed by scaling its distance to fixed center.
*
* @param size a constant float value
- * @param tmpV3 caller provided temporary 3-component vector
* @return this AABBox for chaining
* @see #scale2(float, float[])
*/
- public final AABBox scale(final float size, final float[] tmpV3) {
- tmpV3[0] = high[0] - center[0];
- tmpV3[1] = high[1] - center[1];
- tmpV3[2] = high[2] - center[2];
-
- VectorUtil.scaleVec3(tmpV3, tmpV3, size); // in-place scale
- VectorUtil.addVec3(high, center, tmpV3);
+ public final AABBox scale(final float size) {
+ final Vec3f tmp = new Vec3f();
+ tmp.set(high).sub(center).scale(size);
+ high.set(center).add(tmp);
- tmpV3[0] = low[0] - center[0];
- tmpV3[1] = low[1] - center[1];
- tmpV3[2] = low[2] - center[2];
+ tmp.set(low).sub(center).scale(size);
+ low.set(center).add(tmp);
- VectorUtil.scaleVec3(tmpV3, tmpV3, size); // in-place scale
- VectorUtil.addVec3(low, center, tmpV3);
return this;
}
@@ -621,13 +632,12 @@ public class AABBox {
* high and low is scaled and center recomputed.
*
* @param size a constant float value
- * @param tmpV3 caller provided temporary 3-component vector
* @return this AABBox for chaining
* @see #scale(float, float[])
*/
- public final AABBox scale2(final float size, final float[] tmpV3) {
- VectorUtil.scaleVec3(high, high, size); // in-place scale
- VectorUtil.scaleVec3(low, low, size); // in-place scale
+ public final AABBox scale2(final float size) {
+ high.scale(size);
+ low.scale(size);
computeCenter();
return this;
}
@@ -637,9 +647,9 @@ public class AABBox {
* @param t the float[3] translation vector
* @return this AABBox for chaining
*/
- public final AABBox translate(final float[] t) {
- VectorUtil.addVec3(low, low, t); // in-place translate
- VectorUtil.addVec3(high, high, t); // in-place translate
+ public final AABBox translate(final Vec3f t) {
+ low.add(t);
+ high.add(t);
computeCenter();
return this;
}
@@ -650,46 +660,46 @@ public class AABBox {
* @return this AABBox for chaining
*/
public final AABBox rotate(final Quaternion quat) {
- quat.rotateVector(low, 0, low, 0);
- quat.rotateVector(high, 0, high, 0);
+ quat.rotateVector(low, low);
+ quat.rotateVector(high, high);
computeCenter();
return this;
}
public final float getMinX() {
- return low[0];
+ return low.x();
}
public final float getMinY() {
- return low[1];
+ return low.y();
}
public final float getMinZ() {
- return low[2];
+ return low.z();
}
public final float getMaxX() {
- return high[0];
+ return high.x();
}
public final float getMaxY() {
- return high[1];
+ return high.y();
}
public final float getMaxZ() {
- return high[2];
+ return high.z();
}
public final float getWidth(){
- return high[0] - low[0];
+ return high.x() - low.x();
}
public final float getHeight() {
- return high[1] - low[1];
+ return high.y() - low.y();
}
public final float getDepth() {
- return high[2] - low[2];
+ return high.z() - low.z();
}
@Override
@@ -701,29 +711,65 @@ public class AABBox {
return false;
}
final AABBox other = (AABBox) obj;
- return VectorUtil.isVec2Equal(low, 0, other.low, 0, FloatUtil.EPSILON) &&
- VectorUtil.isVec3Equal(high, 0, other.high, 0, FloatUtil.EPSILON) ;
+ return low.isEqual(other.low) && high.isEqual(other.high);
}
@Override
public final int hashCode() {
throw new InternalError("hashCode not designed");
}
+ public AABBox transform(final AABBox result, final float[/*16*/] mat4, final int mat4_off,
+ final float[] vec3Tmp0, final float[] vec3Tmp1) {
+ result.reset();
+ FloatUtil.multMatrixVec3(mat4, mat4_off, low.get(vec3Tmp0), vec3Tmp1);
+ result.resize(vec3Tmp1);
+
+ FloatUtil.multMatrixVec3(mat4, mat4_off, high.get(vec3Tmp0), vec3Tmp1);
+ result.resize(vec3Tmp1);
+
+ result.computeCenter();
+ return result;
+ }
+
+ public AABBox transformMv(final AABBox result, final PMVMatrix pmv,
+ final float[] vec3Tmp0, final float[] vec3Tmp1) {
+ result.reset();
+ pmv.multMvMatVec3f(low.get(vec3Tmp0), vec3Tmp1);
+ result.resize(vec3Tmp1);
+
+ pmv.multMvMatVec3f(high.get(vec3Tmp0), vec3Tmp1);
+ result.resize(vec3Tmp1);
+
+ result.computeCenter();
+ return result;
+ }
+
+ public AABBox transform(final AABBox result, final Matrix4f mat,
+ final Vec3f vec3Tmp) {
+ result.reset();
+ result.resize( mat.mulVec3f(low, vec3Tmp) );
+
+ result.resize( mat.mulVec3f(high, vec3Tmp) );
+
+ result.computeCenter();
+ return result;
+ }
+
/**
* Assume this bounding box as being in object space and
* compute the window bounding box.
*
* If useCenterZ
is true
,
- * only 4 {@link FloatUtil#mapObjToWinCoords(float, float, float, float[], int[], int, float[], int, float[], float[]) mapObjToWinCoords}
+ * only 4 {@link FloatUtil#mapObjToWin(float, float, float, float[], int[], float[], float[], float[]) mapObjToWinCoords}
* operations are made on points [1..4] using {@link #getCenter()}'s z-value.
- * Otherwise 8 {@link FloatUtil#mapObjToWinCoords(float, float, float, float[], int[], int, float[], int, float[], float[]) mapObjToWinCoords}
+ * Otherwise 8 {@link FloatUtil#mapObjToWin(float, float, float, float[], int[], float[], float[], float[]) mapObjToWinCoords}
* operation on all 8 points are performed.
*
*
- * [2] ------ [4]
+ * .z() ------ [4]
* | |
* | |
- * [1] ------ [3]
+ * .y() ------ [3]
*
* @param mat4PMv P x Mv matrix
* @param view
@@ -736,42 +782,42 @@ public class AABBox {
public AABBox mapToWindow(final AABBox result, final float[/*16*/] mat4PMv, final int[] view, final boolean useCenterZ,
final float[] vec3Tmp0, final float[] vec4Tmp1, final float[] vec4Tmp2) {
{
- // System.err.printf("AABBox.mapToWindow.0: view[%d, %d, %d, %d], this %s%n", view[0], view[1], view[2], view[3], toString());
- final float objZ = useCenterZ ? center[2] : getMinZ();
- FloatUtil.mapObjToWinCoords(getMinX(), getMinY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- // System.err.printf("AABBox.mapToWindow.p1: %f, %f, %f -> %f, %f, %f%n", getMinX(), getMinY(), objZ, vec3Tmp0[0], vec3Tmp0[1], vec3Tmp0[2]);
+ // System.err.printf("AABBox.mapToWindow.0: view[%d, %d, %d, %d], this %s%n", view.x(), view.y(), view.z(), view[3], toString());
+ final float objZ = useCenterZ ? center.z() : getMinZ();
+ FloatUtil.mapObjToWin(getMinX(), getMinY(), objZ, mat4PMv, view, vec3Tmp0, vec4Tmp1, vec4Tmp2);
+ // System.err.printf("AABBox.mapToWindow.p1: %f, %f, %f -> %f, %f, %f%n", getMinX(), getMinY(), objZ, vec3Tmp0.x(), vec3Tmp0.y(), vec3Tmp0.z());
// System.err.println("AABBox.mapToWindow.p1:");
// System.err.println(FloatUtil.matrixToString(null, " mat4PMv", "%10.5f", mat4PMv, 0, 4, 4, false /* rowMajorOrder */));
result.reset();
- result.resize(vec3Tmp0, 0);
+ result.resize(vec3Tmp0);
- FloatUtil.mapObjToWinCoords(getMinX(), getMaxY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- // System.err.printf("AABBox.mapToWindow.p2: %f, %f, %f -> %f, %f, %f%n", getMinX(), getMaxY(), objZ, vec3Tmp0[0], vec3Tmp0[1], vec3Tmp0[2]);
- result.resize(vec3Tmp0, 0);
+ FloatUtil.mapObjToWin(getMinX(), getMaxY(), objZ, mat4PMv, view, vec3Tmp0, vec4Tmp1, vec4Tmp2);
+ // System.err.printf("AABBox.mapToWindow.p2: %f, %f, %f -> %f, %f, %f%n", getMinX(), getMaxY(), objZ, vec3Tmp0.x(), vec3Tmp0.y(), vec3Tmp0.z());
+ result.resize(vec3Tmp0);
- FloatUtil.mapObjToWinCoords(getMaxX(), getMinY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- // System.err.printf("AABBox.mapToWindow.p3: %f, %f, %f -> %f, %f, %f%n", getMaxX(), getMinY(), objZ, vec3Tmp0[0], vec3Tmp0[1], vec3Tmp0[2]);
- result.resize(vec3Tmp0, 0);
+ FloatUtil.mapObjToWin(getMaxX(), getMinY(), objZ, mat4PMv, view, vec3Tmp0, vec4Tmp1, vec4Tmp2);
+ // System.err.printf("AABBox.mapToWindow.p3: %f, %f, %f -> %f, %f, %f%n", getMaxX(), getMinY(), objZ, vec3Tmp0.x(), vec3Tmp0.y(), vec3Tmp0.z());
+ result.resize(vec3Tmp0);
- FloatUtil.mapObjToWinCoords(getMaxX(), getMaxY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- // System.err.printf("AABBox.mapToWindow.p4: %f, %f, %f -> %f, %f, %f%n", getMaxX(), getMaxY(), objZ, vec3Tmp0[0], vec3Tmp0[1], vec3Tmp0[2]);
- result.resize(vec3Tmp0, 0);
+ FloatUtil.mapObjToWin(getMaxX(), getMaxY(), objZ, mat4PMv, view, vec3Tmp0, vec4Tmp1, vec4Tmp2);
+ // System.err.printf("AABBox.mapToWindow.p4: %f, %f, %f -> %f, %f, %f%n", getMaxX(), getMaxY(), objZ, vec3Tmp0.x(), vec3Tmp0.y(), vec3Tmp0.z());
+ result.resize(vec3Tmp0);
}
if( !useCenterZ ) {
final float objZ = getMaxZ();
- FloatUtil.mapObjToWinCoords(getMinX(), getMinY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- result.resize(vec3Tmp0, 0);
+ FloatUtil.mapObjToWin(getMinX(), getMinY(), objZ, mat4PMv, view, vec3Tmp0, vec4Tmp1, vec4Tmp2);
+ result.resize(vec3Tmp0);
- FloatUtil.mapObjToWinCoords(getMinX(), getMaxY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- result.resize(vec3Tmp0, 0);
+ FloatUtil.mapObjToWin(getMinX(), getMaxY(), objZ, mat4PMv, view, vec3Tmp0, vec4Tmp1, vec4Tmp2);
+ result.resize(vec3Tmp0);
- FloatUtil.mapObjToWinCoords(getMaxX(), getMinY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- result.resize(vec3Tmp0, 0);
+ FloatUtil.mapObjToWin(getMaxX(), getMinY(), objZ, mat4PMv, view, vec3Tmp0, vec4Tmp1, vec4Tmp2);
+ result.resize(vec3Tmp0);
- FloatUtil.mapObjToWinCoords(getMaxX(), getMaxY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2);
- result.resize(vec3Tmp0, 0);
+ FloatUtil.mapObjToWin(getMaxX(), getMaxY(), objZ, mat4PMv, view, vec3Tmp0, vec4Tmp1, vec4Tmp2);
+ result.resize(vec3Tmp0);
}
if( DEBUG ) {
System.err.printf("AABBox.mapToWindow: view[%d, %d], this %s -> %s%n", view[0], view[1], toString(), result.toString());
@@ -782,7 +828,6 @@ public class AABBox {
@Override
public final String toString() {
return "[ dim "+getWidth()+" x "+getHeight()+" x "+getDepth()+
- ", box "+low[0]+" / "+low[1]+" / "+low[2]+" .. "+high[0]+" / "+high[1]+" / "+high[2]+
- ", ctr "+center[0]+" / "+center[1]+" / "+center[2]+" ]";
+ ", box "+low+" .. "+high+", ctr "+center+" ]";
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java b/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java
index 8b0fa559e..4d098cb72 100644
--- a/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java
+++ b/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -29,9 +29,11 @@ package com.jogamp.opengl.math.geom;
import jogamp.common.os.PlatformPropsImpl;
-import com.jogamp.common.os.Platform;
import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Matrix4f;
+import com.jogamp.opengl.math.Vec3f;
+import com.jogamp.opengl.math.geom.Frustum.FovDesc;
/**
* Providing frustum {@link #getPlanes() planes} derived by different inputs
@@ -103,6 +105,7 @@ public class Frustum {
this.zNear = zNear;
this.zFar = zFar;
}
+ @Override
public final String toString() {
return "FrustumFovDesc["+fovhv.toStringInDegrees()+", Z["+zNear+" - "+zFar+"]]";
}
@@ -134,7 +137,7 @@ public class Frustum {
*/
public static class Plane {
/** Normal of the plane */
- public final float[] n = new float[3];
+ public final Vec3f n = new Vec3f();
/** Distance to origin */
public float d;
@@ -155,17 +158,22 @@ public class Frustum {
*
**/
public final float distanceTo(final float x, final float y, final float z) {
- return n[0] * x + n[1] * y + n[2] * z + d;
+ return n.x() * x + n.y() * y + n.z() * z + d;
}
/** Return distance of plane to given point, see {@link #distanceTo(float, float, float)}. */
public final float distanceTo(final float[] p) {
- return n[0] * p[0] + n[1] * p[1] + n[2] * p[2] + d;
+ return n.x() * p[0] + n.y() * p[1] + n.z() * p[2] + d;
+ }
+
+ /** Return distance of plane to given point, see {@link #distanceTo(float, float, float)}. */
+ public final float distanceTo(final Vec3f p) {
+ return n.x() * p.x() + n.y() * p.y() + n.z() * p.z() + d;
}
@Override
public String toString() {
- return "Plane[ [ " + n[0] + ", " + n[1] + ", " + n[2] + " ], " + d + "]";
+ return "Plane[ [ " + n + " ], " + d + "]";
}
}
@@ -221,9 +229,9 @@ public class Frustum {
* Operation Details:
*
* - The given {@link FovDesc} will be transformed
- * into the given float[16] as a perspective matrix (column major order) first,
- * see {@link FloatUtil#makePerspective(float[], int, boolean, FovHVHalves, float, float)}.
- * - Then the float[16] perspective matrix is used to {@link #updateByPMV(float[], int)} this instance.
+ * into the given perspective matrix (column major order) first,
+ * see {@link Matrix4f#setToPerspective(FovHVHalves, float, float)}.
+ * - Then the perspective matrix is used to {@link Matrix4f#updateFrustumPlanes(Frustum)} this instance.
*
*
*
@@ -232,17 +240,15 @@ public class Frustum {
*
*
* @param m 4x4 matrix in column-major order (also result)
- * @param m_offset offset in given array m, i.e. start of the 4x4 matrix
- * @param initM if true, given matrix will be initialized w/ identity matrix,
- * otherwise only the frustum fields are set.
* @param fovDesc {@link Frustum} {@link FovDesc}
* @return given matrix for chaining
- * @see FloatUtil#makePerspective(float[], int, boolean, FovHVHalves, float, float)
+ * @see Matrix4f#setToPerspective(FovHVHalves, float, float)
+ * @see Matrix4f#updateFrustumPlanes(Frustum)
+ * @see Matrix4f#getFrustum(Frustum, FovDesc)
*/
- public float[] updateByFovDesc(final float[] m, final int m_offset, final boolean initM,
- final FovDesc fovDesc) {
- FloatUtil.makePerspective(m, m_offset, initM, fovDesc.fovhv, fovDesc.zNear, fovDesc.zFar);
- updateByPMV(m, 0);
+ public Matrix4f updateByFovDesc(final Matrix4f m, final FovDesc fovDesc) {
+ m.setToPerspective(fovDesc.fovhv, fovDesc.zNear, fovDesc.zFar);
+ m.updateFrustumPlanes(this);
return m;
}
@@ -259,10 +265,10 @@ public class Frustum {
// Left: a = m30 + m00, b = m31 + m01, c = m32 + m02, d = m33 + m03 - [0..3] column-major
{
final Plane p = planes[LEFT];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 0 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 0 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 0 + 2 * 4 ];
+ final Vec3f p_n = p.n;
+ p_n.set( pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 0 + 0 * 4 ],
+ pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 0 + 1 * 4 ],
+ pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 0 + 2 * 4 ] );
p.d = pmv[ pmv_off + 3 + 3 * 4 ] + pmv[ pmv_off + 0 + 3 * 4 ];
}
@@ -270,10 +276,10 @@ public class Frustum {
// Right: a = m30 - m00, b = m31 - m01, c = m32 - m02, d = m33 - m03 - [0..3] column-major
{
final Plane p = planes[RIGHT];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 0 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 0 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 0 + 2 * 4 ];
+ final Vec3f p_n = p.n;
+ p_n.set( pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 0 + 0 * 4 ],
+ pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 0 + 1 * 4 ],
+ pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 0 + 2 * 4 ] );
p.d = pmv[ pmv_off + 3 + 3 * 4 ] - pmv[ pmv_off + 0 + 3 * 4 ];
}
@@ -281,10 +287,10 @@ public class Frustum {
// Bottom: a = m30 + m10, b = m31 + m11, c = m32 + m12, d = m33 + m13 - [0..3] column-major
{
final Plane p = planes[BOTTOM];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 1 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 1 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 1 + 2 * 4 ];
+ final Vec3f p_n = p.n;
+ p_n.set( pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 1 + 0 * 4 ],
+ pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 1 + 1 * 4 ],
+ pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 1 + 2 * 4 ] );
p.d = pmv[ pmv_off + 3 + 3 * 4 ] + pmv[ pmv_off + 1 + 3 * 4 ];
}
@@ -292,10 +298,10 @@ public class Frustum {
// Top: a = m30 - m10, b = m31 - m11, c = m32 - m12, d = m33 - m13 - [0..3] column-major
{
final Plane p = planes[TOP];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 1 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 1 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 1 + 2 * 4 ];
+ final Vec3f p_n = p.n;
+ p_n.set( pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 1 + 0 * 4 ],
+ pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 1 + 1 * 4 ],
+ pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 1 + 2 * 4 ] );
p.d = pmv[ pmv_off + 3 + 3 * 4 ] - pmv[ pmv_off + 1 + 3 * 4 ];
}
@@ -303,10 +309,10 @@ public class Frustum {
// Near: a = m30 + m20, b = m31 + m21, c = m32 + m22, d = m33 + m23 - [0..3] column-major
{
final Plane p = planes[NEAR];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 2 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 2 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 2 + 2 * 4 ];
+ final Vec3f p_n = p.n;
+ p_n.set( pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 2 + 0 * 4 ],
+ pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 2 + 1 * 4 ],
+ pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 2 + 2 * 4 ] );
p.d = pmv[ pmv_off + 3 + 3 * 4 ] + pmv[ pmv_off + 2 + 3 * 4 ];
}
@@ -314,38 +320,35 @@ public class Frustum {
// Far: a = m30 - m20, b = m31 - m21, c = m32 + m22, d = m33 + m23 - [0..3] column-major
{
final Plane p = planes[FAR];
- final float[] p_n = p.n;
- p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 2 + 0 * 4 ];
- p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 2 + 1 * 4 ];
- p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 2 + 2 * 4 ];
+ final Vec3f p_n = p.n;
+ p_n.set( pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 2 + 0 * 4 ],
+ pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 2 + 1 * 4 ],
+ pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 2 + 2 * 4 ] );
p.d = pmv[ pmv_off + 3 + 3 * 4 ] - pmv[ pmv_off + 2 + 3 * 4 ];
}
// Normalize all planes
for (int i = 0; i < 6; ++i) {
final Plane p = planes[i];
- final float[] p_n = p.n;
- final double invl = Math.sqrt(p_n[0] * p_n[0] + p_n[1] * p_n[1] + p_n[2] * p_n[2]);
-
- p_n[0] /= invl;
- p_n[1] /= invl;
- p_n[2] /= invl;
- p.d /= invl;
+ final Vec3f p_n = p.n;
+ final float invLen = 1f / p_n.length();
+ p_n.scale(invLen);
+ p.d *= invLen;
}
}
private static final boolean isOutsideImpl(final Plane p, final AABBox box) {
- final float[] low = box.getLow();
- final float[] high = box.getHigh();
-
- if ( p.distanceTo(low[0], low[1], low[2]) > 0.0f ||
- p.distanceTo(high[0], low[1], low[2]) > 0.0f ||
- p.distanceTo(low[0], high[1], low[2]) > 0.0f ||
- p.distanceTo(high[0], high[1], low[2]) > 0.0f ||
- p.distanceTo(low[0], low[1], high[2]) > 0.0f ||
- p.distanceTo(high[0], low[1], high[2]) > 0.0f ||
- p.distanceTo(low[0], high[1], high[2]) > 0.0f ||
- p.distanceTo(high[0], high[1], high[2]) > 0.0f ) {
+ final Vec3f lo = box.getLow();
+ final Vec3f hi = box.getHigh();
+
+ if ( p.distanceTo(lo.x(), lo.y(), lo.z()) > 0.0f ||
+ p.distanceTo(hi.x(), lo.y(), lo.z()) > 0.0f ||
+ p.distanceTo(lo.x(), hi.y(), lo.z()) > 0.0f ||
+ p.distanceTo(hi.x(), hi.y(), lo.z()) > 0.0f ||
+ p.distanceTo(lo.x(), lo.y(), hi.z()) > 0.0f ||
+ p.distanceTo(hi.x(), lo.y(), hi.z()) > 0.0f ||
+ p.distanceTo(lo.x(), hi.y(), hi.z()) > 0.0f ||
+ p.distanceTo(hi.x(), hi.y(), hi.z()) > 0.0f ) {
return false;
}
return true;
diff --git a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java
index f8f1d3930..1aa305c2e 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java
@@ -46,6 +46,7 @@ import jogamp.common.os.PlatformPropsImpl;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.util.FloatStack;
import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.Quaternion;
import com.jogamp.opengl.math.Ray;
import com.jogamp.opengl.math.geom.AABBox;
@@ -208,9 +209,9 @@ public final class PMVMatrix implements GLMatrixFunc {
// Mvit Modelview-Inverse-Transpose
matrixArray = new float[5*16];
- mP_offset = 0*16;
- mMv_offset = 1*16;
- mTex_offset = 4*16;
+ // mP_offset = 0*16;
+ // mMv_offset = 1*16;
+ // mTex_offset = 4*16;
matrixPMvMvit = Buffers.slice2Float(matrixArray, 0*16, 4*16); // P + Mv + Mvi + Mvit
matrixPMvMvi = Buffers.slice2Float(matrixArray, 0*16, 3*16); // P + Mv + Mvi
@@ -241,6 +242,8 @@ public final class PMVMatrix implements GLMatrixFunc {
* Issues {@link #glLoadIdentity()} on all matrices,
* i.e. {@link GLMatrixFunc#GL_MODELVIEW GL_MODELVIEW}, {@link GLMatrixFunc#GL_PROJECTION GL_PROJECTION} or {@link GL#GL_TEXTURE GL_TEXTURE}
* and resets all internal states.
+ *
+ * Leaves {@link GLMatrixFunc#GL_MODELVIEW GL_MODELVIEW} the active matrix mode.
*/
public final void reset() {
FloatUtil.makeIdentity(matrixArray, mMv_offset);
@@ -403,7 +406,6 @@ public final class PMVMatrix implements GLMatrixFunc {
}
}
-
/**
* Multiplies the {@link #glGetPMatrixf() P} and {@link #glGetMvMatrixf() Mv} matrix, i.e.
*
@@ -432,6 +434,71 @@ public final class PMVMatrix implements GLMatrixFunc {
return mat4MvP;
}
+ /**
+ * v_out = Mv * v_in
+ * @param v_in float[4] input vector
+ * @param v_out float[4] output vector
+ */
+ public final void multMvMatVec4f(final float[/*4*/] v_in, final float[/*4*/] v_out) {
+ FloatUtil.multMatrixVec(matrixArray, mMv_offset, v_in, v_out);
+ }
+
+ /**
+ * v_out = Mv * v_in
+ *
+ * Affine 3f-vector transformation by 4x4 matrix, see {@link FloatUtil#multMatrixVec3(float[], int, float[], float[])}.
+ *
+ * @param v_in float[3] input vector
+ * @param v_out float[3] output vector
+ */
+ public final void multMvMatVec3f(final float[/*3*/] v_in, final float[/*3*/] v_out) {
+ FloatUtil.multMatrixVec3(matrixArray, mMv_offset, v_in, v_out);
+ }
+
+ /**
+ * v_out = P * v_in
+ * @param v_in float[4] input vector
+ * @param v_out float[4] output vector
+ */
+ public final void multPMatVec4f(final float[/*4*/] v_in, final float[/*4*/] v_out) {
+ FloatUtil.multMatrixVec(matrixArray, v_in, v_out); // mP_offset := 0
+ }
+
+ /**
+ * v_out = P * v_in
+ *
+ * Affine 3f-vector transformation by 4x4 matrix, see {@link FloatUtil#multMatrixVec3(float[], int, float[], float[])}.
+ *
+ * @param v_in float[3] input vector
+ * @param v_out float[3] output vector
+ */
+ public final void multPMatVec3f(final float[/*3*/] v_in, final float[/*3*/] v_out) {
+ FloatUtil.multMatrixVec3(matrixArray, v_in, v_out); // mP_offset := 0
+ }
+
+ /**
+ * v_out = P * Mv * v_in
+ * @param v_in float[4] input vector
+ * @param v_out float[4] output vector
+ */
+ public final void multPMvMatVec4f(final float[/*4*/] v_in, final float[/*4*/] v_out) {
+ FloatUtil.multMatrixVec(matrixArray, mMv_offset, v_in, mat4Tmp1);
+ FloatUtil.multMatrixVec(matrixArray, mat4Tmp1, v_out); // mP_offset := 0
+ }
+
+ /**
+ * v_out = P * Mv * v_in
+ *
+ * Affine 3f-vector transformation by 4x4 matrix, see {@link FloatUtil#multMatrixVec3(float[], int, float[], float[])}.
+ *
+ * @param v_in float[3] input vector
+ * @param v_out float[3] output vector
+ */
+ public final void multPMvMatVec3f(final float[/*3*/] v_in, final float[/*3*/] v_out) {
+ FloatUtil.multMatrixVec3(matrixArray, mMv_offset, v_in, mat4Tmp1);
+ FloatUtil.multMatrixVec3(matrixArray, mat4Tmp1, v_out); // mP_offset := 0
+ }
+
//
// GLMatrixFunc implementation
//
@@ -533,6 +600,24 @@ public final class PMVMatrix implements GLMatrixFunc {
m.position(spos);
}
+ /**
+ * Load the current matrix with the values of the given {@link Matrix4f}.
+ */
+ public final void glLoadMatrixf(final Matrix4f m) {
+ if(matrixMode==GL_MODELVIEW) {
+ m.get(matrixArray, mMv_offset);
+ dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ;
+ modifiedBits |= MODIFIED_MODELVIEW;
+ } else if(matrixMode==GL_PROJECTION) {
+ m.get(matrixArray, mP_offset);
+ dirtyBits |= DIRTY_FRUSTUM ;
+ modifiedBits |= MODIFIED_PROJECTION;
+ } else if(matrixMode==GL.GL_TEXTURE) {
+ m.get(matrixArray, mTex_offset);
+ modifiedBits |= MODIFIED_TEXTURE;
+ }
+ }
+
/**
* Load the current matrix with the values of the given {@link Quaternion}'s rotation {@link Quaternion#toMatrix(float[], int) matrix representation}.
*/
@@ -633,6 +718,21 @@ public final class PMVMatrix implements GLMatrixFunc {
}
}
+ public final void glMultMatrixf(final Matrix4f m) {
+ if(matrixMode==GL_MODELVIEW) {
+ new Matrix4f(matrixArray, mMv_offset).mul(m).get(matrixArray, mMv_offset);
+ dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ;
+ modifiedBits |= MODIFIED_MODELVIEW;
+ } else if(matrixMode==GL_PROJECTION) {
+ new Matrix4f(matrixArray, mP_offset).mul(m).get(matrixArray, mP_offset);
+ dirtyBits |= DIRTY_FRUSTUM ;
+ modifiedBits |= MODIFIED_PROJECTION;
+ } else if(matrixMode==GL.GL_TEXTURE) {
+ new Matrix4f(matrixArray, mTex_offset).mul(m).get(matrixArray, mTex_offset);
+ modifiedBits |= MODIFIED_TEXTURE;
+ }
+ }
+
@Override
public final void glTranslatef(final float x, final float y, final float z) {
glMultMatrixf(FloatUtil.makeTranslation(matrixTxSx, false, x, y, z), 0);
@@ -645,7 +745,7 @@ public final class PMVMatrix implements GLMatrixFunc {
@Override
public final void glRotatef(final float ang_deg, final float x, final float y, final float z) {
- glMultMatrixf(FloatUtil.makeRotationAxis(mat4Tmp1, 0, ang_deg * FloatUtil.PI / 180.0f, x, y, z, mat4Tmp2), 0);
+ glMultMatrixf(FloatUtil.makeRotationAxis(mat4Tmp1, 0, FloatUtil.adegToRad(ang_deg), x, y, z, mat4Tmp2), 0);
}
/**
@@ -728,7 +828,7 @@ public final class PMVMatrix implements GLMatrixFunc {
public final boolean gluProject(final float objx, final float objy, final float objz,
final int[] viewport, final int viewport_offset,
final float[] win_pos, final int win_pos_offset ) {
- return FloatUtil.mapObjToWinCoords(objx, objy, objz,
+ return FloatUtil.mapObjToWin(objx, objy, objz,
matrixArray, mMv_offset,
matrixArray, mP_offset,
viewport, viewport_offset,
@@ -754,7 +854,7 @@ public final class PMVMatrix implements GLMatrixFunc {
public final boolean gluUnProject(final float winx, final float winy, final float winz,
final int[] viewport, final int viewport_offset,
final float[] obj_pos, final int obj_pos_offset) {
- return FloatUtil.mapWinToObjCoords(winx, winy, winz,
+ return FloatUtil.mapWinToObj(winx, winy, winz,
matrixArray, mMv_offset,
matrixArray, mP_offset,
viewport, viewport_offset,
@@ -788,7 +888,7 @@ public final class PMVMatrix implements GLMatrixFunc {
final int[] viewport, final int viewport_offset,
final float near, final float far,
final float[] obj_pos, final int obj_pos_offset ) {
- return FloatUtil.mapWinToObjCoords(winx, winy, winz, clipw,
+ return FloatUtil.mapWinToObj4(winx, winy, winz, clipw,
matrixArray, mMv_offset,
matrixArray, mP_offset,
viewport, viewport_offset,
@@ -842,14 +942,12 @@ public final class PMVMatrix implements GLMatrixFunc {
* @return true if successful, otherwise false (failed to invert matrix, or becomes z is infinity)
*/
public final boolean gluUnProjectRay(final float winx, final float winy, final float winz0, final float winz1,
- final int[] viewport, final int viewport_offset,
+ final int[] viewport,
final Ray ray) {
return FloatUtil.mapWinToRay(winx, winy, winz0, winz1,
matrixArray, mMv_offset,
- matrixArray, mP_offset,
- viewport, viewport_offset,
- ray,
- mat4Tmp1, mat4Tmp2, mat4Tmp3);
+ matrixArray, mP_offset, viewport,
+ ray, mat4Tmp1, mat4Tmp2, mat4Tmp3);
}
public StringBuilder toString(StringBuilder sb, final String f) {
@@ -1066,8 +1164,10 @@ public final class PMVMatrix implements GLMatrixFunc {
return res;
}
+ private static final int mP_offset = 0*16;
+ private static final int mMv_offset = 1*16;
+ private static final int mTex_offset = 4*16;
private final float[] matrixArray;
- private final int mP_offset, mMv_offset, mTex_offset;
private final FloatBuffer matrixPMvMvit, matrixPMvMvi, matrixPMv, matrixP, matrixTex, matrixMv, matrixMvi, matrixMvit;
private final float[] matrixTxSx;
private final float[] mat4Tmp1, mat4Tmp2, mat4Tmp3;
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java
index 43a6cfc58..e0f465da7 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/EyeParameter.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -28,6 +28,7 @@
package com.jogamp.opengl.util.stereo;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Vec3f;
/**
* Constant single eye parameter of the viewer, relative to its {@link ViewerPose}.
@@ -36,8 +37,8 @@ public final class EyeParameter {
/** Eye number, 0
for the left eye and 1
for the right eye. */
public final int number;
- /** float[3] eye position vector used to define eye height in meter relative to actor. */
- public final float[] positionOffset;
+ /** eye position vector used to define eye height in meter relative to actor. */
+ public final Vec3f positionOffset;
/** Field of view in both directions, may not be centered, either {@link FovHVHalves#inTangents} or radians. */
public final FovHVHalves fovhv;
@@ -51,18 +52,18 @@ public final class EyeParameter {
/** Z-axis eye relief in meter. */
public final float eyeReliefZ;
- public EyeParameter(final int number, final float[] positionOffset, final FovHVHalves fovhv,
+ public EyeParameter(final int number, final Vec3f positionOffset, final FovHVHalves fovhv,
final float distNoseToPupil, final float verticalDelta, final float eyeRelief) {
this.number = number;
- this.positionOffset = new float[3];
- System.arraycopy(positionOffset, 0, this.positionOffset, 0, 3);
+ this.positionOffset = new Vec3f(positionOffset);
this.fovhv = fovhv;
this.distNoseToPupilX = distNoseToPupil;
this.distMiddleToPupilY = verticalDelta;
this.eyeReliefZ = eyeRelief;
}
+ @Override
public final String toString() {
- return "EyeParam[num "+number+", posOff["+positionOffset[0]+", "+positionOffset[1]+", "+positionOffset[2]+"], "+fovhv+
- ", distPupil[noseX "+distNoseToPupilX+", middleY "+distMiddleToPupilY+", reliefZ "+eyeReliefZ+"]]";
+ return "EyeParam[num "+number+", posOff["+positionOffset+"], "+fovhv+
+ ", distPupil[noseX "+distNoseToPupilX+", middleY "+distMiddleToPupilY+", reliefZ "+eyeReliefZ+"]]";
}
}
\ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java
index b795927cd..6294adee1 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/LocationSensorParameter.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2015 JogAmp Community. All rights reserved.
+ * Copyright 2015-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -27,6 +27,7 @@
*/
package com.jogamp.opengl.util.stereo;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.geom.Frustum;
/**
@@ -38,13 +39,15 @@ public final class LocationSensorParameter {
/** The {@link Frustum}'s {@link Frustum.FovDesc} description of the location sensor. */
public final Frustum.FovDesc frustumDesc;
/** The {@link Frustum}'s float[16] projection matrix of the location sensor. */
- public final float[] frustumProjMat;
+ public final Matrix4f frustumProjMat;
public LocationSensorParameter(final Frustum.FovDesc fovDesc) {
this.frustumDesc = fovDesc;
this.frustum = new Frustum();
- this.frustumProjMat = frustum.updateByFovDesc(new float[16], 0, true, fovDesc);
+ this.frustumProjMat = frustum.updateByFovDesc(new Matrix4f(), fovDesc);
}
+
+ @Override
public final String toString() {
return "LocationSensor["+frustumDesc+"]";
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
index b6112650a..85e752302 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -33,6 +33,7 @@ import com.jogamp.nativewindow.util.PointImmutable;
import jogamp.opengl.Debug;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Vec3f;
/**
* Interface describing a native stereoscopic device
@@ -94,7 +95,7 @@ public interface StereoDevice {
public int getRequiredRotation();
/**
- * Return the device default eye position offset for {@link #createRenderer(int, int, float[], FovHVHalves[], float)}.
+ * Return the device default eye position offset for {@link #createRenderer(int, int, Vec3f, FovHVHalves[], float)}.
*
* Result is an array of float values for
*
@@ -105,7 +106,7 @@ public interface StereoDevice {
*
* @return
*/
- public float[] getDefaultEyePositionOffset();
+ public Vec3f getDefaultEyePositionOffset();
/**
* Returns the device default {@link FovHVHalves} for all supported eyes
@@ -198,7 +199,7 @@ public interface StereoDevice {
* Returns the supported distortion compensation of the {@link StereoDeviceRenderer},
* e.g. {@link StereoDeviceRenderer#DISTORTION_BARREL}, {@link StereoDeviceRenderer#DISTORTION_CHROMATIC}, etc.
* @see StereoDeviceRenderer#getDistortionBits()
- * @see #createRenderer(int, int, float[], FovHVHalves[], float, int)
+ * @see #createRenderer(int, int, Vec3f, FovHVHalves[], float, int)
* @see #getRecommendedDistortionBits()
* @see #getMinimumDistortionBits()
*/
@@ -212,7 +213,7 @@ public interface StereoDevice {
* User shall use the recommended distortion compensation to achieve a distortion free view.
*
* @see StereoDeviceRenderer#getDistortionBits()
- * @see #createRenderer(int, int, float[], FovHVHalves[], float, int)
+ * @see #createRenderer(int, int, Vec3f, FovHVHalves[], float, int)
* @see #getSupportedDistortionBits()
* @see #getMinimumDistortionBits()
*/
@@ -227,7 +228,7 @@ public interface StereoDevice {
* @see #getSupportedDistortionBits()
* @see #getRecommendedDistortionBits()
* @see StereoDeviceRenderer#getDistortionBits()
- * @see #createRenderer(int, int, float[], FovHVHalves[], float, int)
+ * @see #createRenderer(int, int, Vec3f, FovHVHalves[], float, int)
*/
public int getMinimumDistortionBits();
@@ -245,6 +246,6 @@ public interface StereoDevice {
* @return
*/
public StereoDeviceRenderer createRenderer(final int distortionBits,
- final int textureCount, final float[] eyePositionOffset,
+ final int textureCount, final Vec3f eyePositionOffset,
final FovHVHalves[] eyeFov, final float pixelsPerDisplayPixel, final int textureUnit);
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java
index b6f76a343..63cb3e1e7 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -27,9 +27,9 @@
*/
package com.jogamp.opengl.util.stereo;
-import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.Quaternion;
-import com.jogamp.opengl.math.VectorUtil;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.util.CustomGLEventListener;
import com.jogamp.opengl.util.stereo.StereoDeviceRenderer.Eye;
@@ -137,24 +137,24 @@ public class StereoUtil {
* @param eye
* @param zNear frustum near value
* @param zFar frustum far value
- * @param mat4Projection float[16] projection matrix result
- * @param mat4Modelview float[16] modelview matrix result
+ * @param mat4Projection projection matrix result
+ * @param mat4Modelview modelview matrix result
*/
public static void getSBSUpstreamPMV(final ViewerPose viewerPose, final Eye eye,
final float zNear, final float zFar,
- final float[] mat4Projection, final float[] mat4Modelview) {
- final float[] mat4Tmp1 = new float[16];
- final float[] mat4Tmp2 = new float[16];
- final float[] vec3Tmp1 = new float[3];
- final float[] vec3Tmp2 = new float[3];
- final float[] vec3Tmp3 = new float[3];
+ final Matrix4f mat4Projection, final Matrix4f mat4Modelview) {
+ final Matrix4f mat4Tmp1 = new Matrix4f();
+ final Matrix4f mat4Tmp2 = new Matrix4f();
+ final Vec3f vec3Tmp1 = new Vec3f();
+ final Vec3f vec3Tmp2 = new Vec3f();
+ final Vec3f vec3Tmp3 = new Vec3f();
final EyeParameter eyeParam = eye.getEyeParameter();
//
// Projection
//
- FloatUtil.makePerspective(mat4Projection, 0, true, eyeParam.fovhv, zNear, zFar);
+ mat4Projection.setToPerspective(eyeParam.fovhv, zNear, zFar);
//
// Modelview
@@ -162,21 +162,17 @@ public class StereoUtil {
final Quaternion rollPitchYaw = new Quaternion();
// private final float eyeYaw = FloatUtil.PI; // 180 degrees in radians
// rollPitchYaw.rotateByAngleY(eyeYaw);
- final float[] shiftedEyePos = rollPitchYaw.rotateVector(vec3Tmp1, 0, viewerPose.position, 0);
- VectorUtil.addVec3(shiftedEyePos, shiftedEyePos, eyeParam.positionOffset);
+ final Vec3f shiftedEyePos = rollPitchYaw.rotateVector(viewerPose.position, vec3Tmp1).add(eyeParam.positionOffset);
rollPitchYaw.mult(viewerPose.orientation);
- final float[] up = rollPitchYaw.rotateVector(vec3Tmp2, 0, VectorUtil.VEC3_UNIT_Y, 0);
- final float[] forward = rollPitchYaw.rotateVector(vec3Tmp3, 0, VectorUtil.VEC3_UNIT_Z_NEG, 0);
- final float[] center = VectorUtil.addVec3(forward, shiftedEyePos, forward);
+ final Vec3f up = rollPitchYaw.rotateVector(Vec3f.UNIT_Y, vec3Tmp2);
+ final Vec3f forward = rollPitchYaw.rotateVector(Vec3f.UNIT_Z_NEG, vec3Tmp3); // -> center
+ final Vec3f center = forward.add(shiftedEyePos);
- final float[] mLookAt = FloatUtil.makeLookAt(mat4Tmp2, 0, shiftedEyePos, 0, center, 0, up, 0, mat4Tmp1);
- final float[] mViewAdjust = FloatUtil.makeTranslation(mat4Modelview, true,
- eyeParam.distNoseToPupilX,
- eyeParam.distMiddleToPupilY,
- eyeParam.eyeReliefZ);
-
- /* mat4Modelview = */ FloatUtil.multMatrix(mViewAdjust, mLookAt);
+ final Matrix4f mLookAt = mat4Tmp2.setToLookAt(shiftedEyePos, center, up, mat4Tmp1);
+ mat4Modelview.mul( mat4Tmp1.setToTranslation( eyeParam.distNoseToPupilX,
+ eyeParam.distMiddleToPupilY,
+ eyeParam.eyeReliefZ ), mLookAt);
}
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java
index 10ee4c994..5d2cf925c 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/ViewerPose.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -28,13 +28,14 @@
package com.jogamp.opengl.util.stereo;
import com.jogamp.opengl.math.Quaternion;
+import com.jogamp.opengl.math.Vec3f;
/**
* {@link #position} and {@link #orientation} of viewer.
*/
public final class ViewerPose {
/**
- * float[3] position of viewer in meter.
+ * position of viewer in meter.
*
* Apply the following to resolve the actual eye position:
*
@@ -43,13 +44,13 @@ public final class ViewerPose {
*
*
*/
- public final float[] position;
+ public final Vec3f position;
/** Orientation of viewer. */
public final Quaternion orientation;
public ViewerPose() {
- this.position = new float[3];
+ this.position = new Vec3f();
this.orientation = new Quaternion();
}
public ViewerPose(final float[] position, final Quaternion orientation) {
@@ -64,11 +65,14 @@ public final class ViewerPose {
}
/** Set position and orientation of this instance. */
public final void setPosition(final float posX, final float posY, final float posZ) {
- position[0] = posX;
- position[1] = posY;
- position[2] = posZ;
+ position.set( posX, posY, posZ );
}
+ /** Set position and orientation of this instance. */
+ public final void setPosition(final Vec3f pos) {
+ position.set( pos );
+ }
+ @Override
public final String toString() {
- return "ViewerPose[pos["+position[0]+", "+position[1]+", "+position[2]+"], "+orientation+"]";
+ return "ViewerPose[pos["+position+"], "+orientation+"]";
}
}
\ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
index 957758e78..0cdef8770 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
@@ -35,6 +35,7 @@ import com.jogamp.nativewindow.util.Dimension;
import com.jogamp.nativewindow.util.DimensionImmutable;
import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.util.stereo.EyeParameter;
import com.jogamp.opengl.util.stereo.StereoDevice;
import com.jogamp.opengl.util.stereo.StereoDeviceConfig;
@@ -53,7 +54,7 @@ public class GenericStereoDeviceFactory extends StereoDeviceFactory {
*/
public static GenericStereoDeviceConfig createMono(final String name,
final DimensionImmutable surfaceSizeInPixel, final float[] screenSizeInMeters,
- final float[] defaultEyePositionOffset) {
+ final Vec3f defaultEyePositionOffset) {
final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f;
final float d2r = FloatUtil.PI / 180.0f;
return new GenericStereoDeviceConfig(
@@ -90,7 +91,7 @@ public class GenericStereoDeviceFactory extends StereoDeviceFactory {
public static GenericStereoDeviceConfig createStereoSBS(final String name,
final DimensionImmutable surfaceSizeInPixel, final float[] screenSizeInMeters,
final float interpupillaryDistanceInMeters, final float fovy,
- final float[] defaultEyePositionOffset) {
+ final Vec3f defaultEyePositionOffset) {
final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f;
final float d2r = FloatUtil.PI / 180.0f;
@@ -138,7 +139,7 @@ public class GenericStereoDeviceFactory extends StereoDeviceFactory {
final DimensionImmutable surfaceSizeInPixel, final float[] screenSizeInMeters,
final float interpupillaryDistanceInMeters, final float fovy,
final DimensionImmutable eyeTextureSize,
- final float[] defaultEyePositionOffset) {
+ final Vec3f defaultEyePositionOffset) {
DistortionMesh.Producer lenseDistMeshProduce = null;
try {
lenseDistMeshProduce =
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java
index 1bc0fe0f4..cc0aece27 100644
--- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java
@@ -250,7 +250,7 @@ class TypecastFont implements Font {
@Override
public AABBox getMetricBounds(final CharSequence string) {
- return getMetricBoundsFU(string).scale2(1.0f/metrics.getUnitsPerEM(), new float[3]);
+ return getMetricBoundsFU(string).scale2(1.0f/metrics.getUnitsPerEM());
}
@Override
@@ -290,7 +290,7 @@ class TypecastFont implements Font {
}
@Override
public AABBox getGlyphBounds(final CharSequence string, final AffineTransform tmp1, final AffineTransform tmp2) {
- return getGlyphBoundsFU(string, tmp1, tmp2).scale2(1.0f/metrics.getUnitsPerEM(), new float[3]);
+ return getGlyphBoundsFU(string, tmp1, tmp2).scale2(1.0f/metrics.getUnitsPerEM());
}
@Override
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java
index 6747cca82..560d0902b 100644
--- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java
@@ -148,14 +148,14 @@ public final class TypecastGlyph implements Font.Glyph {
public final AABBox getBoundsFU(final AABBox dest) { return dest.copy(bbox); }
@Override
- public final AABBox getBounds(final AABBox dest, final float[] tmpV3) {
- return dest.copy(bbox).scale2(1.0f/font.getMetrics().getUnitsPerEM(), tmpV3);
+ public final AABBox getBounds(final AABBox dest) {
+ return dest.copy(bbox).scale2(1.0f/font.getMetrics().getUnitsPerEM());
}
@Override
public final AABBox getBounds() {
- final AABBox dest = new AABBox();
- return dest.copy(bbox).scale2(1.0f/font.getMetrics().getUnitsPerEM(), new float[2]);
+ final AABBox dest = new AABBox(bbox);
+ return dest.scale2(1.0f/font.getMetrics().getUnitsPerEM());
}
@Override
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java
index 5e56d1932..11f1ce7c7 100644
--- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java
@@ -119,7 +119,7 @@ final class TypecastHMetrics implements Metrics {
}
@Override
- public AABBox getBounds(final AABBox dest, final float[] tmpV3) {
- return dest.setSize(bbox.getLow(), bbox.getHigh()).scale2(unitsPerEM_inv, tmpV3);
+ public AABBox getBounds(final AABBox dest) {
+ return dest.copy(bbox).scale2(unitsPerEM_inv);
}
}
diff --git a/src/jogl/classes/jogamp/opengl/ProjectFloat.java b/src/jogl/classes/jogamp/opengl/ProjectFloat.java
index 5ec5a8e3f..3fcc75f3d 100644
--- a/src/jogl/classes/jogamp/opengl/ProjectFloat.java
+++ b/src/jogl/classes/jogamp/opengl/ProjectFloat.java
@@ -227,7 +227,7 @@ public class ProjectFloat {
final float[] projMatrix, final int projMatrix_offset,
final int[] viewport, final int viewport_offset,
final float[] win_pos, final int win_pos_offset ) {
- return FloatUtil.mapObjToWinCoords(objx, objy, objz,
+ return FloatUtil.mapObjToWin(objx, objy, objz,
modelMatrix, modelMatrix_offset,
projMatrix, projMatrix_offset,
viewport, viewport_offset,
@@ -347,7 +347,7 @@ public class ProjectFloat {
final float[] projMatrix, final int projMatrix_offset,
final int[] viewport, final int viewport_offset,
final float[] obj_pos, final int obj_pos_offset) {
- return FloatUtil.mapWinToObjCoords(winx, winy, winz,
+ return FloatUtil.mapWinToObj(winx, winy, winz,
modelMatrix, modelMatrix_offset,
projMatrix, projMatrix_offset,
viewport, viewport_offset,
@@ -505,7 +505,7 @@ public class ProjectFloat {
final int[] viewport, final int viewport_offset,
final float near, final float far,
final float[] obj_pos, final int obj_pos_offset ) {
- return FloatUtil.mapWinToObjCoords(winx, winy, winz, clipw,
+ return FloatUtil.mapWinToObj4(winx, winy, winz, clipw,
modelMatrix, modelMatrix_offset,
projMatrix, projMatrix_offset,
viewport, viewport_offset,
diff --git a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java
index bfe93b59c..60adc7d74 100644
--- a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java
+++ b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java
@@ -34,6 +34,7 @@ import com.jogamp.nativewindow.util.PointImmutable;
import com.jogamp.nativewindow.util.Rectangle;
import com.jogamp.nativewindow.util.RectangleImmutable;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.util.stereo.StereoDeviceConfig;
import com.jogamp.opengl.util.stereo.EyeParameter;
import com.jogamp.opengl.util.stereo.LocationSensorParameter;
@@ -63,9 +64,9 @@ public class GenericStereoDevice implements StereoDevice {
private static final GenericStereoDeviceConfig[] configs;
static {
- final float[] DEFAULT_EYE_POSITION_OFFSET_STEREO_LENSES = { 0.0f, 1.6f, -5.0f }; // 1.6 up, 5 forward
- final float[] DEFAULT_EYE_POSITION_OFFSET_STEREO = { 0.0f, 0.3f, 3.0f }; // 0.3 up, 3 back
- final float[] DEFAULT_EYE_POSITION_OFFSET_MONO = { 0.0f, 0.0f, 3.0f }; // 3 back
+ final Vec3f DEFAULT_EYE_POSITION_OFFSET_STEREO_LENSES = new Vec3f( 0.0f, 1.6f, -5.0f ); // 1.6 up, 5 forward
+ final Vec3f DEFAULT_EYE_POSITION_OFFSET_STEREO = new Vec3f( 0.0f, 0.3f, 3.0f ); // 0.3 up, 3 back
+ final Vec3f DEFAULT_EYE_POSITION_OFFSET_MONO = new Vec3f( 0.0f, 0.0f, 3.0f ); // 3 back
final DimensionImmutable surfaceSizeInPixelDK1 = new Dimension(1280, 800);
final float[] screenSizeInMetersDK1 = new float[] { 0.14976f, 0.0936f };
@@ -175,7 +176,7 @@ public class GenericStereoDevice implements StereoDevice {
public int getRequiredRotation() { return 0; }
@Override
- public float[] getDefaultEyePositionOffset() { return config.defaultEyeParam[0].positionOffset; }
+ public Vec3f getDefaultEyePositionOffset() { return config.defaultEyeParam[0].positionOffset; }
@Override
public final FovHVHalves[] getDefaultFOV() { return defaultEyeFov; }
@@ -264,7 +265,7 @@ public class GenericStereoDevice implements StereoDevice {
@Override
public final StereoDeviceRenderer createRenderer(final int distortionBits,
- final int textureCount, final float[] eyePositionOffset,
+ final int textureCount, final Vec3f eyePositionOffset,
final FovHVHalves[] eyeFov, final float pixelsPerDisplayPixel,
final int textureUnit) {
final EyeParameter[] eyeParam = new EyeParameter[eyeFov.length];
diff --git a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceRenderer.java b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceRenderer.java
index 21567a0f1..3c6f5e37e 100644
--- a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceRenderer.java
+++ b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceRenderer.java
@@ -45,6 +45,7 @@ import jogamp.common.os.PlatformPropsImpl;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.os.Platform;
import com.jogamp.opengl.JoglVersion;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.util.GLArrayDataServer;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;
@@ -90,7 +91,7 @@ public class GenericStereoDeviceRenderer implements StereoDeviceRenderer {
public final EyeParameter getEyeParameter() { return eyeParameter; }
/* pp */ GenericEye(final GenericStereoDevice device, final int distortionBits,
- final float[] eyePositionOffset, final EyeParameter eyeParam,
+ final Vec3f eyePositionOffset, final EyeParameter eyeParam,
final DimensionImmutable textureSize, final RectangleImmutable eyeViewport) {
this.eyeName = eyeParam.number;
this.distortionBits = distortionBits;
@@ -387,7 +388,7 @@ public class GenericStereoDeviceRenderer implements StereoDeviceRenderer {
private static final DimensionImmutable zeroSize = new Dimension(0, 0);
/* pp */ GenericStereoDeviceRenderer(final GenericStereoDevice context, final int distortionBits,
- final int textureCount, final float[] eyePositionOffset,
+ final int textureCount, final Vec3f eyePositionOffset,
final EyeParameter[] eyeParam, final float pixelsPerDisplayPixel, final int textureUnit,
final DimensionImmutable[] eyeTextureSizes, final DimensionImmutable totalTextureSize,
final RectangleImmutable[] eyeViewports) {
diff --git a/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDevice.java b/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDevice.java
index 5025e80c5..335123bb9 100644
--- a/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDevice.java
+++ b/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDevice.java
@@ -40,6 +40,7 @@ import com.jogamp.oculusvr.ovrHmdDesc;
import com.jogamp.oculusvr.ovrSizei;
import com.jogamp.oculusvr.ovrTrackingState;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.math.geom.Frustum;
import com.jogamp.opengl.util.stereo.LocationSensorParameter;
import com.jogamp.opengl.util.stereo.StereoDevice;
@@ -49,7 +50,7 @@ import com.jogamp.opengl.util.stereo.StereoUtil;
public class OVRStereoDevice implements StereoDevice {
/** 1.6 up, 5 forward */
- private static final float[] DEFAULT_EYE_POSITION_OFFSET = { 0.0f, 1.6f, -5.0f };
+ private static final Vec3f DEFAULT_EYE_POSITION_OFFSET = new Vec3f( 0.0f, 1.6f, -5.0f );
private final StereoDeviceFactory factory;
public final int deviceIndex;
@@ -181,7 +182,7 @@ public class OVRStereoDevice implements StereoDevice {
public int getRequiredRotation() { return requiredRotation; }
@Override
- public float[] getDefaultEyePositionOffset() { return DEFAULT_EYE_POSITION_OFFSET; }
+ public Vec3f getDefaultEyePositionOffset() { return DEFAULT_EYE_POSITION_OFFSET; }
@Override
public final FovHVHalves[] getDefaultFOV() { return defaultEyeFov; }
@@ -300,7 +301,7 @@ public class OVRStereoDevice implements StereoDevice {
@Override
public final StereoDeviceRenderer createRenderer(final int distortionBits,
- final int textureCount, final float[] eyePositionOffset,
+ final int textureCount, final Vec3f eyePositionOffset,
final FovHVHalves[] eyeFov, final float pixelsPerDisplayPixel, final int textureUnit) {
final ovrFovPort ovrEyeFov0 = OVRUtil.getOVRFovPort(eyeFov[0]);
final ovrFovPort ovrEyeFov1 = OVRUtil.getOVRFovPort(eyeFov[1]);
diff --git a/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceRenderer.java b/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceRenderer.java
index 95565dd0f..1430a9c45 100644
--- a/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceRenderer.java
+++ b/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceRenderer.java
@@ -59,6 +59,7 @@ import com.jogamp.oculusvr.ovrVector2f;
import com.jogamp.oculusvr.ovrVector3f;
import com.jogamp.opengl.JoglVersion;
import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.util.GLArrayDataServer;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;
@@ -107,7 +108,7 @@ public class OVRStereoDeviceRenderer implements StereoDeviceRenderer {
public final EyeParameter getEyeParameter() { return eyeParameter; }
/* pp */ OVREye(final ovrHmdDesc hmdDesc, final int distortionBits,
- final float[] eyePositionOffset, final ovrEyeRenderDesc eyeDesc,
+ final Vec3f eyePositionOffset, final ovrEyeRenderDesc eyeDesc,
final ovrSizei ovrTextureSize, final RectangleImmutable eyeViewport) {
this.eyeName = eyeDesc.getEye();
this.distortionBits = distortionBits;
@@ -398,7 +399,7 @@ public class OVRStereoDeviceRenderer implements StereoDeviceRenderer {
}
/* pp */ OVRStereoDeviceRenderer(final OVRStereoDevice context, final int distortionBits,
- final int textureCount, final float[] eyePositionOffset,
+ final int textureCount, final Vec3f eyePositionOffset,
final ovrEyeRenderDesc[] eyeRenderDescs,
final DimensionImmutable[] eyeTextureSizes, final DimensionImmutable totalTextureSize,
final RectangleImmutable[] eyeViewports, final int textureUnit) {
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/GPUTextRendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/GPUTextRendererListenerBase01.java
index 90700e35a..9af3bd99b 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/GPUTextRendererListenerBase01.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/GPUTextRendererListenerBase01.java
@@ -491,7 +491,7 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB
System.err.println("Matrix: " + getXTran() + "/" + getYTran() + " x"+getZTran() + " @"+getAngle() +" fontSize "+fontSizeCenter);
if(bbox) {
System.err.println("bbox em: "+font.getMetricBounds(text2));
- System.err.println("bbox px: "+font.getMetricBounds(text2).scale(nearPlaneS * FontScale.toPixels(fontSizeCenter, dpiV), new float[3]));
+ System.err.println("bbox px: "+font.getMetricBounds(text2).scale(nearPlaneS * FontScale.toPixels(fontSizeCenter, dpiV)));
}
}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestFontsNEWT00.java b/src/test/com/jogamp/opengl/test/junit/graph/TestFontsNEWT00.java
index 25af3d910..afdecfaca 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/TestFontsNEWT00.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/TestFontsNEWT00.java
@@ -102,7 +102,7 @@ public class TestFontsNEWT00 extends UITestCase {
System.err.println(" px "+s0_px+", "+s1_px);
System.err.println(" AABBox");
System.err.println(" funits "+glyph.getBoundsFU());
- System.err.println(" em "+glyph.getBounds(new AABBox(), new float[3]));
+ System.err.println(" em "+glyph.getBounds(new AABBox()));
Assert.assertEquals(s0, s1);
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
index 3dc951829..88a3d7326 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java
@@ -32,9 +32,9 @@ import com.jogamp.newt.event.PinchToZoomGesture;
import com.jogamp.newt.event.GestureHandler.GestureEvent;
import com.jogamp.opengl.GLRendererQuirks;
import com.jogamp.opengl.JoglVersion;
-import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.Quaternion;
-import com.jogamp.opengl.math.VectorUtil;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.test.junit.jogl.demos.GearsObject;
import com.jogamp.opengl.util.CustomGLEventListener;
import com.jogamp.opengl.util.PMVMatrix;
@@ -405,49 +405,59 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
}
// private boolean useAndroidDebug = false;
- private final float[] mat4Tmp1 = new float[16];
- private final float[] mat4Tmp2 = new float[16];
- private final float[] vec3Tmp1 = new float[3];
- private final float[] vec3Tmp2 = new float[3];
- private final float[] vec3Tmp3 = new float[3];
+ private final Matrix4f mat4Tmp1 = new Matrix4f();
+ private final Matrix4f mat4Tmp2 = new Matrix4f();
+ private final Vec3f vec3Tmp1 = new Vec3f();
+ private final Vec3f vec3Tmp2 = new Vec3f();
+ private final Vec3f vec3Tmp3 = new Vec3f();
- private static final float[] vec3ScalePos = new float[] { 20f, 20f, 20f };
+ private static final float scalePos = 20f;
@Override
public void reshapeForEye(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height,
final EyeParameter eyeParam, final ViewerPose viewerPose) {
final GL2ES2 gl = drawable.getGL().getGL2ES2();
- pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
- final float[] mat4Projection = FloatUtil.makePerspective(mat4Tmp1, 0, true, eyeParam.fovhv, zNear, zFar);
- if( flipVerticalInGLOrientation && gl.getContext().getGLDrawable().isGLOriented() ) {
- pmvMatrix.glLoadIdentity();
- pmvMatrix.glScalef(1f, -1f, 1f);
- pmvMatrix.glMultMatrixf(mat4Projection, 0);
- } else {
- pmvMatrix.glLoadMatrixf(mat4Projection, 0);
- }
-
- pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
-
- final Quaternion rollPitchYaw = new Quaternion();
- // private final float eyeYaw = FloatUtil.PI; // 180 degrees in radians
- // rollPitchYaw.rotateByAngleY(eyeYaw);
- // final float[] shiftedEyePos = rollPitchYaw.rotateVector(vec3Tmp1, 0, viewerPose.position, 0);
- final float[] shiftedEyePos = VectorUtil.copyVec3(vec3Tmp1, 0, viewerPose.position, 0);
- VectorUtil.scaleVec3(shiftedEyePos, shiftedEyePos, vec3ScalePos); // amplify viewerPose position
- VectorUtil.addVec3(shiftedEyePos, shiftedEyePos, eyeParam.positionOffset);
-
- rollPitchYaw.mult(viewerPose.orientation);
- final float[] up = rollPitchYaw.rotateVector(vec3Tmp2, 0, VectorUtil.VEC3_UNIT_Y, 0);
- final float[] forward = rollPitchYaw.rotateVector(vec3Tmp3, 0, VectorUtil.VEC3_UNIT_Z_NEG, 0);
- final float[] center = VectorUtil.addVec3(forward, shiftedEyePos, forward);
- final float[] mLookAt = FloatUtil.makeLookAt(mat4Tmp1, 0, shiftedEyePos, 0, center, 0, up, 0, mat4Tmp2);
- final float[] mViewAdjust = FloatUtil.makeTranslation(mat4Tmp2, true, eyeParam.distNoseToPupilX, eyeParam.distMiddleToPupilY, eyeParam.eyeReliefZ);
- final float[] mat4Modelview = FloatUtil.multMatrix(mViewAdjust, mLookAt);
+ {
+ //
+ // Projection
+ //
+ final Matrix4f mat4 = new Matrix4f();
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ if( flipVerticalInGLOrientation && gl.getContext().getGLDrawable().isGLOriented() ) {
+ mat4Tmp1.setToScale(1f, -1f, 1f);
+ mat4Tmp2.setToPerspective(eyeParam.fovhv, zNear, zFar);
+ mat4.mul(mat4Tmp1, mat4Tmp2);
- pmvMatrix.glLoadMatrixf(mat4Modelview, 0);
- pmvMatrix.glTranslatef(0.0f, 0.0f, -zViewDist);
+ } else {
+ mat4.setToPerspective(eyeParam.fovhv, zNear, zFar);
+ }
+ pmvMatrix.glLoadMatrixf(mat4);
+
+ //
+ // Modelview
+ //
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ final Quaternion rollPitchYaw = new Quaternion();
+ // private final float eyeYaw = FloatUtil.PI; // 180 degrees in radians
+ // rollPitchYaw.rotateByAngleY(eyeYaw);
+ // final Vec3f shiftedEyePos = rollPitchYaw.rotateVector(viewerPose.position, vec3Tmp1);
+ final Vec3f shiftedEyePos = vec3Tmp1.set(viewerPose.position);
+ shiftedEyePos.scale(scalePos); // amplify viewerPose position
+ shiftedEyePos.add(eyeParam.positionOffset);
+
+ rollPitchYaw.mult(viewerPose.orientation);
+ final Vec3f up = rollPitchYaw.rotateVector(Vec3f.UNIT_Y, vec3Tmp2);
+ final Vec3f forward = rollPitchYaw.rotateVector(Vec3f.UNIT_Z_NEG, vec3Tmp3); // -> center
+ final Vec3f center = forward.add(shiftedEyePos);
+
+ final Matrix4f mLookAt = mat4Tmp2.setToLookAt(shiftedEyePos, center, up, mat4Tmp1);
+ mat4.mul( mat4Tmp1.setToTranslation( eyeParam.distNoseToPupilX,
+ eyeParam.distMiddleToPupilY,
+ eyeParam.eyeReliefZ ), mLookAt);
+ mat4.translate(0, 0, -zViewDist, mat4Tmp1);
+ pmvMatrix.glLoadMatrixf(mat4);
+ }
st.useProgram(gl, true);
st.uniform(gl, pmvMatrixUniform);
st.useProgram(gl, false);
@@ -592,6 +602,7 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
}
class GearsKeyAdapter extends KeyAdapter {
+ @Override
public void keyPressed(final KeyEvent e) {
final int kc = e.getKeyCode();
if(KeyEvent.VK_LEFT == kc) {
@@ -636,6 +647,7 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
}
}
+ @Override
public void mousePressed(final MouseEvent e) {
if( e.getPointerCount()==1 ) {
prevMouseX = e.getX();
@@ -648,9 +660,11 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
}
}
+ @Override
public void mouseReleased(final MouseEvent e) {
}
+ @Override
public void mouseMoved(final MouseEvent e) {
if( e.isConfined() ) {
navigate(e);
@@ -662,6 +676,7 @@ public class GearsES2 implements StereoGLEventListener, TileRendererBase.TileRen
}
}
+ @Override
public void mouseDragged(final MouseEvent e) {
navigate(e);
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl4/TriangleInstancedRendererWithShaderState.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl4/TriangleInstancedRendererWithShaderState.java
index 560e8aa23..841f2037c 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl4/TriangleInstancedRendererWithShaderState.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl4/TriangleInstancedRendererWithShaderState.java
@@ -9,7 +9,6 @@ import java.util.Random;
import com.jogamp.opengl.DebugGL4;
import com.jogamp.opengl.GL;
-import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GL4;
import com.jogamp.opengl.GLAutoDrawable;
@@ -17,8 +16,8 @@ import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLException;
import com.jogamp.opengl.GLUniformData;
import com.jogamp.opengl.TraceGL4;
-
-import com.jogamp.opengl.math.Matrix4;
+import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.util.GLArrayDataClient;
import com.jogamp.opengl.util.GLArrayDataServer;
import com.jogamp.opengl.util.PMVMatrix;
@@ -44,7 +43,7 @@ public class TriangleInstancedRendererWithShaderState implements GLEventListener
private static final int NO_OF_INSTANCE = 30;
private final FloatBuffer triangleTransform = FloatBuffer.allocate(16 * NO_OF_INSTANCE);
- private final Matrix4[] mat = new Matrix4[NO_OF_INSTANCE];
+ private final Matrix4f[] mat = new Matrix4f[NO_OF_INSTANCE];
private final float[] rotationSpeed = new float[NO_OF_INSTANCE];
private static final boolean useTraceGL = false;
@@ -53,13 +52,13 @@ public class TriangleInstancedRendererWithShaderState implements GLEventListener
private boolean isInitialized = false;
- public TriangleInstancedRendererWithShaderState(IInstancedRenderingView view) {
+ public TriangleInstancedRendererWithShaderState(final IInstancedRenderingView view) {
this.view = view;
if(useTraceGL) {
try {
stream = new PrintStream(new FileOutputStream(new File("instanced-with-st.txt")));
- } catch (IOException e1) {
+ } catch (final IOException e1) {
e1.printStackTrace();
}
}
@@ -68,23 +67,24 @@ public class TriangleInstancedRendererWithShaderState implements GLEventListener
}
private void initTransform() {
- Random rnd = new Random();
+ final Random rnd = new Random();
+ final Matrix4f tmp = new Matrix4f();
for(int i = 0; i < NO_OF_INSTANCE; i++) {
rotationSpeed[i] = 0.3f * rnd.nextFloat();
- mat[i] = new Matrix4();
+ mat[i] = new Matrix4f();
mat[i].loadIdentity();
- float scale = 1f + 4 * rnd.nextFloat();
- mat[i].scale(scale, scale, scale);
+ final float scale = 1f + 4 * rnd.nextFloat();
+ mat[i].scale(scale, tmp);
//setup initial position of each triangle
mat[i].translate(20f * rnd.nextFloat() - 10f,
10f * rnd.nextFloat() - 5f,
- 0f);
+ 0f, tmp);
}
}
@Override
- public void init(GLAutoDrawable drawable) {
- GL4 gl = drawable.getGL().getGL4();
+ public void init(final GLAutoDrawable drawable) {
+ final GL4 gl = drawable.getGL().getGL4();
drawable.setGL(new DebugGL4(gl));
if(useTraceGL) {
drawable.setGL(new TraceGL4(gl, stream));
@@ -96,9 +96,9 @@ public class TriangleInstancedRendererWithShaderState implements GLEventListener
System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
System.err.println("INIT GL IS: " + gl.getClass().getName());
- System.err.println("GL_VENDOR: " + gl.glGetString(GL4.GL_VENDOR));
- System.err.println("GL_RENDERER: " + gl.glGetString(GL4.GL_RENDERER));
- System.err.println("GL_VERSION: " + gl.glGetString(GL4.GL_VERSION));
+ System.err.println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR));
+ System.err.println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER));
+ System.err.println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION));
initShader(gl);
projectionMatrix = new PMVMatrix();
@@ -125,14 +125,14 @@ public class TriangleInstancedRendererWithShaderState implements GLEventListener
}
@Override
- public void display(GLAutoDrawable drawable) {
+ public void display(final GLAutoDrawable drawable) {
if(!isInitialized ) return;
- GL4 gl = drawable.getGL().getGL4();
- gl.glClear(GL4.GL_COLOR_BUFFER_BIT | GL4.GL_DEPTH_BUFFER_BIT);
+ final GL4 gl = drawable.getGL().getGL4();
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
st.useProgram(gl, true);
- projectionMatrix.glMatrixMode(GL2.GL_PROJECTION);
+ projectionMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
projectionMatrix.glPushMatrix();
float winScale = 0.1f;
@@ -151,7 +151,7 @@ public class TriangleInstancedRendererWithShaderState implements GLEventListener
colorsVBO.enableBuffer(gl, true);
}
//gl.glVertexAttribDivisor() is not required since each instance has the same attribute (color).
- gl.glDrawArraysInstanced(GL4.GL_TRIANGLES, 0, 3, NO_OF_INSTANCE);
+ gl.glDrawArraysInstanced(GL.GL_TRIANGLES, 0, 3, NO_OF_INSTANCE);
if(useInterleaved) {
interleavedVBO.enableBuffer(gl, false);
} else {
@@ -162,42 +162,43 @@ public class TriangleInstancedRendererWithShaderState implements GLEventListener
}
@Override
- public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
- GL4 gl3 = drawable.getGL().getGL4();
+ public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
+ final GL4 gl3 = drawable.getGL().getGL4();
gl3.glViewport(0, 0, width, height);
aspect = (float) width / (float) height;
- projectionMatrix.glMatrixMode(GL2.GL_PROJECTION);
+ projectionMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
projectionMatrix.glLoadIdentity();
projectionMatrix.gluPerspective(45, aspect, 0.001f, 20f);
projectionMatrix.gluLookAt(0, 0, -10, 0, 0, 0, 0, 1, 0);
}
@Override
- public void dispose(GLAutoDrawable drawable){
- GL4 gl = drawable.getGL().getGL4();
+ public void dispose(final GLAutoDrawable drawable){
+ final GL4 gl = drawable.getGL().getGL4();
st.destroy(gl);
}
private void generateTriangleTransform() {
triangleTransform.clear();
+ final Matrix4f tmp = new Matrix4f();
for(int i = 0; i < NO_OF_INSTANCE; i++) {
- mat[i].rotate(rotationSpeed[i], 0, 0, 1);
- triangleTransform.put(mat[i].getMatrix());
+ mat[i].rotate(rotationSpeed[i], 0, 0, 1, tmp);
+ mat[i].get(triangleTransform);
}
triangleTransform.rewind();
}
- private void initVBO_nonInterleaved(GL4 gl) {
- int VERTEX_COUNT = 3;
+ private void initVBO_nonInterleaved(final GL4 gl) {
+ final int VERTEX_COUNT = 3;
- verticesVBO = GLArrayDataClient.createGLSL("mgl_Vertex", 3, GL4.GL_FLOAT, false, VERTEX_COUNT);
- FloatBuffer verticeBuf = (FloatBuffer)verticesVBO.getBuffer();
+ verticesVBO = GLArrayDataClient.createGLSL("mgl_Vertex", 3, GL.GL_FLOAT, false, VERTEX_COUNT);
+ final FloatBuffer verticeBuf = (FloatBuffer)verticesVBO.getBuffer();
verticeBuf.put(vertices);
verticesVBO.seal(gl, true);
- colorsVBO = GLArrayDataClient.createGLSL("mgl_Color", 4, GL4.GL_FLOAT, false, VERTEX_COUNT);
- FloatBuffer colorBuf = (FloatBuffer)colorsVBO.getBuffer();
+ colorsVBO = GLArrayDataClient.createGLSL("mgl_Color", 4, GL.GL_FLOAT, false, VERTEX_COUNT);
+ final FloatBuffer colorBuf = (FloatBuffer)colorsVBO.getBuffer();
colorBuf.put(colors);
colorsVBO.seal(gl, true);
@@ -209,13 +210,13 @@ public class TriangleInstancedRendererWithShaderState implements GLEventListener
st.useProgram(gl, false);
}
- private void initVBO_interleaved(GL4 gl) {
- int VERTEX_COUNT = 3;
+ private void initVBO_interleaved(final GL4 gl) {
+ final int VERTEX_COUNT = 3;
interleavedVBO = GLArrayDataServer.createGLSLInterleaved(3 + 4, GL.GL_FLOAT, false, VERTEX_COUNT, GL.GL_STATIC_DRAW);
interleavedVBO.addGLSLSubArray("mgl_Vertex", 3, GL.GL_ARRAY_BUFFER);
interleavedVBO.addGLSLSubArray("mgl_Color", 4, GL.GL_ARRAY_BUFFER);
- FloatBuffer ib = (FloatBuffer)interleavedVBO.getBuffer();
+ final FloatBuffer ib = (FloatBuffer)interleavedVBO.getBuffer();
for(int i = 0; i < VERTEX_COUNT; i++) {
ib.put(vertices, i*3, 3);
@@ -227,11 +228,11 @@ public class TriangleInstancedRendererWithShaderState implements GLEventListener
st.useProgram(gl, false);
}
- private void initShader(GL4 gl) {
+ private void initShader(final GL4 gl) {
// Create & Compile the shader objects
- ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(),
+ final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(),
"shader", "shader/bin", shaderBasename, true);
- ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(),
+ final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(),
"shader", "shader/bin", shaderBasename, true);
vp0.replaceInShaderSource("NO_OF_INSTANCE", String.valueOf(NO_OF_INSTANCE));
@@ -241,7 +242,7 @@ public class TriangleInstancedRendererWithShaderState implements GLEventListener
//vp0.dumpShaderSource(System.out);
// Create & Link the shader program
- ShaderProgram sp = new ShaderProgram();
+ final ShaderProgram sp = new ShaderProgram();
sp.add(vp0);
sp.add(fp0);
if(!sp.link(gl, System.err)) {
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl4/TrianglesInstancedRendererHardcoded.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl4/TrianglesInstancedRendererHardcoded.java
index fb0a78832..a1f8ff5f6 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl4/TrianglesInstancedRendererHardcoded.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl4/TrianglesInstancedRendererHardcoded.java
@@ -8,14 +8,15 @@ import java.nio.FloatBuffer;
import java.util.Random;
import com.jogamp.opengl.DebugGL4;
-import com.jogamp.opengl.GL2;
+import com.jogamp.opengl.GL;
+import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GL4;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.TraceGL4;
-
+import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.common.nio.Buffers;
-import com.jogamp.opengl.math.Matrix4;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.util.PMVMatrix;
public class TrianglesInstancedRendererHardcoded implements GLEventListener {
@@ -32,7 +33,7 @@ public class TrianglesInstancedRendererHardcoded implements GLEventListener {
private static final int NO_OF_INSTANCE = 30;
private final FloatBuffer triangleTransform = FloatBuffer.allocate(16 * NO_OF_INSTANCE);
- private final Matrix4[] mat = new Matrix4[NO_OF_INSTANCE];
+ private final Matrix4f[] mat = new Matrix4f[NO_OF_INSTANCE];
private final float[] rotationSpeed = new float[NO_OF_INSTANCE];
private int[] vbo;
@@ -42,22 +43,22 @@ public class TrianglesInstancedRendererHardcoded implements GLEventListener {
private static final boolean useTraceGL = false;
- public TrianglesInstancedRendererHardcoded(IInstancedRenderingView view) {
+ public TrianglesInstancedRendererHardcoded(final IInstancedRenderingView view) {
this.view = view;
initTransform();
if(useTraceGL) {
try {
stream = new PrintStream(new FileOutputStream(new File("instanced.txt")));
- } catch (IOException e1) {
+ } catch (final IOException e1) {
e1.printStackTrace();
}
}
}
@Override
- public void init(GLAutoDrawable drawable) {
- GL4 gl = drawable.getGL().getGL4();
+ public void init(final GLAutoDrawable drawable) {
+ final GL4 gl = drawable.getGL().getGL4();
drawable.setGL(new DebugGL4(gl));
if(useTraceGL) {
drawable.setGL(new TraceGL4(gl, stream));
@@ -69,27 +70,27 @@ public class TrianglesInstancedRendererHardcoded implements GLEventListener {
System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
System.err.println("INIT GL IS: " + gl.getClass().getName());
- System.err.println("GL_VENDOR: " + gl.glGetString(GL4.GL_VENDOR));
- System.err.println("GL_RENDERER: " + gl.glGetString(GL4.GL_RENDERER));
- System.err.println("GL_VERSION: " + gl.glGetString(GL4.GL_VERSION));
+ System.err.println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR));
+ System.err.println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER));
+ System.err.println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION));
try {
initShaders(gl);
- } catch (IOException e) {
+ } catch (final IOException e) {
e.printStackTrace();
}
initVBO(gl);
}
@Override
- public void display(GLAutoDrawable drawable) {
+ public void display(final GLAutoDrawable drawable) {
- GL4 gl = drawable.getGL().getGL4();
- gl.glClear(GL4.GL_COLOR_BUFFER_BIT | GL4.GL_DEPTH_BUFFER_BIT);
+ final GL4 gl = drawable.getGL().getGL4();
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glUseProgram(shaderProgram);
- projectionMatrix.glMatrixMode(GL2.GL_PROJECTION);
+ projectionMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
projectionMatrix.glPushMatrix();
float winScale = 0.1f;
@@ -104,28 +105,28 @@ public class TrianglesInstancedRendererHardcoded implements GLEventListener {
gl.glUniformMatrix4fv(transformMatrixLocation, NO_OF_INSTANCE, false, triangleTransform);
gl.glBindVertexArray(vao[0]);
- gl.glDrawArraysInstanced(GL4.GL_TRIANGLES, 0, 3, NO_OF_INSTANCE);
+ gl.glDrawArraysInstanced(GL.GL_TRIANGLES, 0, 3, NO_OF_INSTANCE);
gl.glBindVertexArray(0);
gl.glUseProgram(0);
}
@Override
- public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
System.out.println("Window resized to width=" + width + " height=" + height);
- GL4 gl3 = drawable.getGL().getGL4();
+ final GL4 gl3 = drawable.getGL().getGL4();
gl3.glViewport(0, 0, width, height);
aspect = (float) width / (float) height;
projectionMatrix = new PMVMatrix();
- projectionMatrix.glMatrixMode(GL2.GL_PROJECTION);
+ projectionMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
projectionMatrix.glLoadIdentity();
projectionMatrix.gluPerspective(45, aspect, 0.001f, 20f);
projectionMatrix.gluLookAt(0, 0, -10, 0, 0, 0, 0, 1, 0);
}
@Override
- public void dispose(GLAutoDrawable drawable){
- GL4 gl = drawable.getGL().getGL4();
+ public void dispose(final GLAutoDrawable drawable){
+ final GL4 gl = drawable.getGL().getGL4();
gl.glUseProgram(0);
gl.glDeleteBuffers(2, vbo, 0);
gl.glDetachShader(shaderProgram, vertShader);
@@ -136,22 +137,23 @@ public class TrianglesInstancedRendererHardcoded implements GLEventListener {
}
private void initTransform() {
- Random rnd = new Random();
+ final Random rnd = new Random();
+ final Matrix4f tmp = new Matrix4f();
for(int i = 0; i < NO_OF_INSTANCE; i++) {
rotationSpeed[i] = 0.3f * rnd.nextFloat();
- mat[i] = new Matrix4();
+ mat[i] = new Matrix4f();
mat[i].loadIdentity();
- float scale = 1f + 4 * rnd.nextFloat();
- mat[i].scale(scale, scale, scale);
+ final float scale = 1f + 4 * rnd.nextFloat();
+ mat[i].scale(scale, tmp);
//setup initial position of each triangle
mat[i].translate(20f * rnd.nextFloat() - 10f,
10f * rnd.nextFloat() - 5f,
- 0f);
+ 0f, tmp);
}
}
- private void initVBO(GL4 gl) {
- FloatBuffer interleavedBuffer = Buffers.newDirectFloatBuffer(vertices.length + colors.length);
+ private void initVBO(final GL4 gl) {
+ final FloatBuffer interleavedBuffer = Buffers.newDirectFloatBuffer(vertices.length + colors.length);
for(int i = 0; i < vertices.length/3; i++) {
for(int j = 0; j < 3; j++) {
interleavedBuffer.put(vertices[i*3 + j]);
@@ -167,54 +169,54 @@ public class TrianglesInstancedRendererHardcoded implements GLEventListener {
gl.glBindVertexArray(vao[0]);
vbo = new int[1];
gl.glGenBuffers(1, vbo, 0);
- gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vbo[0]);
- gl.glBufferData(GL4.GL_ARRAY_BUFFER, interleavedBuffer.limit() * Buffers.SIZEOF_FLOAT, interleavedBuffer, GL4.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo[0]);
+ gl.glBufferData(GL.GL_ARRAY_BUFFER, interleavedBuffer.limit() * Buffers.SIZEOF_FLOAT, interleavedBuffer, GL.GL_STATIC_DRAW);
gl.glEnableVertexAttribArray(locPos);
gl.glEnableVertexAttribArray(locCol);
- int stride = Buffers.SIZEOF_FLOAT * (3+4);
- gl.glVertexAttribPointer( locPos, 3, GL4.GL_FLOAT, false, stride, 0);
- gl.glVertexAttribPointer( locCol, 4, GL4.GL_FLOAT, false, stride, Buffers.SIZEOF_FLOAT * 3);
+ final int stride = Buffers.SIZEOF_FLOAT * (3+4);
+ gl.glVertexAttribPointer( locPos, 3, GL.GL_FLOAT, false, stride, 0);
+ gl.glVertexAttribPointer( locCol, 4, GL.GL_FLOAT, false, stride, Buffers.SIZEOF_FLOAT * 3);
}
- private void initShaders(GL4 gl) throws IOException {
- vertShader = gl.glCreateShader(GL4.GL_VERTEX_SHADER);
- fragShader = gl.glCreateShader(GL4.GL_FRAGMENT_SHADER);
+ private void initShaders(final GL4 gl) throws IOException {
+ vertShader = gl.glCreateShader(GL2ES2.GL_VERTEX_SHADER);
+ fragShader = gl.glCreateShader(GL2ES2.GL_FRAGMENT_SHADER);
- String[] vlines = new String[] { vertexShaderString };
- int[] vlengths = new int[] { vlines[0].length() };
+ final String[] vlines = new String[] { vertexShaderString };
+ final int[] vlengths = new int[] { vlines[0].length() };
gl.glShaderSource(vertShader, vlines.length, vlines, vlengths, 0);
gl.glCompileShader(vertShader);
- int[] compiled = new int[1];
- gl.glGetShaderiv(vertShader, GL4.GL_COMPILE_STATUS, compiled, 0);
+ final int[] compiled = new int[1];
+ gl.glGetShaderiv(vertShader, GL2ES2.GL_COMPILE_STATUS, compiled, 0);
if(compiled[0] != 0) {
System.out.println("Vertex shader compiled");
} else {
- int[] logLength = new int[1];
- gl.glGetShaderiv(vertShader, GL4.GL_INFO_LOG_LENGTH, logLength, 0);
+ final int[] logLength = new int[1];
+ gl.glGetShaderiv(vertShader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);
- byte[] log = new byte[logLength[0]];
+ final byte[] log = new byte[logLength[0]];
gl.glGetShaderInfoLog(vertShader, logLength[0], (int[])null, 0, log, 0);
System.err.println("Error compiling the vertex shader: " + new String(log));
System.exit(1);
}
- String[] flines = new String[] { fragmentShaderString };
- int[] flengths = new int[] { flines[0].length() };
+ final String[] flines = new String[] { fragmentShaderString };
+ final int[] flengths = new int[] { flines[0].length() };
gl.glShaderSource(fragShader, flines.length, flines, flengths, 0);
gl.glCompileShader(fragShader);
- gl.glGetShaderiv(fragShader, GL4.GL_COMPILE_STATUS, compiled, 0);
+ gl.glGetShaderiv(fragShader, GL2ES2.GL_COMPILE_STATUS, compiled, 0);
if(compiled[0] != 0){
System.out.println("Fragment shader compiled.");
} else {
- int[] logLength = new int[1];
- gl.glGetShaderiv(fragShader, GL4.GL_INFO_LOG_LENGTH, logLength, 0);
+ final int[] logLength = new int[1];
+ gl.glGetShaderiv(fragShader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);
- byte[] log = new byte[logLength[0]];
+ final byte[] log = new byte[logLength[0]];
gl.glGetShaderInfoLog(fragShader, logLength[0], (int[])null, 0, log, 0);
System.err.println("Error compiling the fragment shader: " + new String(log));
@@ -238,11 +240,12 @@ public class TrianglesInstancedRendererHardcoded implements GLEventListener {
private void generateTriangleTransform() {
triangleTransform.clear();
+ final Matrix4f tmp = new Matrix4f();
for(int i = 0; i < NO_OF_INSTANCE; i++) {
// mat[i].translate(0.1f, 0.1f, 0);
- mat[i].rotate(rotationSpeed[i], 0, 0, 1);
+ mat[i].rotate(rotationSpeed[i], 0, 0, 1, tmp);
// mat[i].translate(-0.1f, -0.1f, 0);
- triangleTransform.put(mat[i].getMatrix());
+ mat[i].get(triangleTransform);
}
triangleTransform.flip();
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/math/Matrix4fb.java b/src/test/com/jogamp/opengl/test/junit/jogl/math/Matrix4fb.java
new file mode 100644
index 000000000..fb4c11b7c
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/math/Matrix4fb.java
@@ -0,0 +1,1784 @@
+/**
+ * Copyright 2014-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.math;
+
+import java.nio.FloatBuffer;
+
+import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.math.Quaternion;
+import com.jogamp.opengl.math.Ray;
+import com.jogamp.opengl.math.Vec3f;
+import com.jogamp.opengl.math.Vec4f;
+import com.jogamp.opengl.math.VectorUtil;
+import com.jogamp.opengl.math.geom.AABBox;
+import com.jogamp.opengl.math.geom.Frustum;
+import com.jogamp.opengl.math.geom.Frustum.Plane;
+
+/**
+ * Basic 4x4 float matrix implementation using fields for intensive use-cases (host operations).
+ *
+ * Implementation covers {@link FloatUtil} matrix functionality, exposed in an object oriented manner.
+ *
+ *
+ * Unlike {@link com.jogamp.opengl.util.PMVMatrix PMVMatrix}, this class only represents one single matrix
+ * without a complete {@link com.jogamp.opengl.fixedfunc.GLMatrixFunc GLMatrixFunc} implementation.
+ *
+ *
+ * For array operations the layout is expected in column-major order
+ * matching OpenGL's implementation, illustration:
+ *
+ Row-Major Column-Major (OpenGL):
+
+ | 0 1 2 tx |
+ | |
+ | 4 5 6 ty |
+ M = | |
+ | 8 9 10 tz |
+ | |
+ | 12 13 14 15 |
+
+ R C R C
+ m[0*4+3] = tx; m[0+4*3] = tx;
+ m[1*4+3] = ty; m[1+4*3] = ty;
+ m[2*4+3] = tz; m[2+4*3] = tz;
+
+ RC (std subscript order) RC (std subscript order)
+ m[0+3*4] = tx; m[0+3*4] = tx;
+ m[1+3*4] = ty; m[1+3*4] = ty;
+ m[2+3*4] = tz; m[2+3*4] = tz;
+
+ *
+ *
+ *
+ *
+ *
+ *
+ * Implementation utilizes unrolling of small vertices and matrices wherever possible
+ * while trying to access memory in a linear fashion for performance reasons, see:
+ *
+ *
+ * @see com.jogamp.opengl.util.PMVMatrix
+ * @see FloatUtil
+ */
+public class Matrix4fb {
+
+ /**
+ * Creates a new identity matrix.
+ */
+ public Matrix4fb() {
+ loadIdentity();
+ }
+
+ /**
+ * Creates a new matrix copying the values of the given {@code src} matrix.
+ */
+ public Matrix4fb(final Matrix4fb src) {
+ load(src);
+ }
+
+ /**
+ * Creates a new matrix based on given float[4*4] column major order.
+ * @param m 4x4 matrix in column-major order
+ */
+ public Matrix4fb(final float[] m) {
+ load(m);
+ }
+
+ /**
+ * Creates a new matrix based on given float[4*4] column major order.
+ * @param m 4x4 matrix in column-major order
+ * @param m_off offset for matrix {@code m}
+ */
+ public Matrix4fb(final float[] m, final int m_off) {
+ load(m, m_off);
+ }
+
+ //
+ // Write to Matrix via load(..)
+ //
+
+ /**
+ * Set this matrix to identity.
+ *
+ Translation matrix (Column Order):
+ 1 0 0 0
+ 0 1 0 0
+ 0 0 1 0
+ 0 0 0 1
+ *
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb loadIdentity() {
+ m[0+0*4] = m[1+1*4] = m[2+2*4] = m[3+3*4] = 1.0f;
+ m[0+1*4] = m[0+2*4] = m[0+3*4] =
+ m[1+0*4] = m[1+2*4] = m[1+3*4] =
+ m[2+0*4] = m[2+1*4] = m[2+3*4] =
+ m[3+0*4] = m[3+1*4] = m[3+2*4] = 0.0f;
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code b} to this matrix.
+ * @param src the source values
+ * @return this matrix for chaining
+ */
+ public Matrix4fb load(final Matrix4fb src) {
+ System.arraycopy(src.m, 0, m, 0, 16);
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code src} to this matrix.
+ * @param src 4x4 matrix float[16] in column-major order
+ * @return this matrix for chaining
+ */
+ public Matrix4fb load(final float[] src) {
+ System.arraycopy(src, 0, m, 0, 16);
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code src} to this matrix.
+ * @param src 4x4 matrix float[16] in column-major order
+ * @param src_off offset for matrix {@code src}
+ * @return this matrix for chaining
+ */
+ public Matrix4fb load(final float[] src, final int src_off) {
+ System.arraycopy(src, src_off, m, 0, 16);
+ return this;
+ }
+
+ /**
+ * Load the values of the given matrix {@code src} to this matrix.
+ *
+ * Implementation uses relative {@link FloatBuffer#get()},
+ * hence caller may want to issue {@link FloatBuffer#reset()} thereafter.
+ *
+ * @param src 4x4 matrix {@link FloatBuffer} in column-major order
+ * @return this matrix for chaining
+ */
+ public Matrix4fb load(final FloatBuffer src) {
+ src.get(m, 0, 16);
+ return this;
+ }
+
+ //
+ // Read out Matrix via get(..)
+ //
+
+ /** Gets the ith component, 0 <= i < 16 */
+ public float get(final int i) {
+ return m[i];
+ }
+
+ /**
+ * Get the named column of the given column-major matrix to v_out.
+ * @param column named column to copy
+ * @param v_out the column-vector storage
+ * @return given result vector v_out for chaining
+ */
+ public Vec4f getColumn(final int column, final Vec4f v_out) {
+ v_out.set( get(0+column*4),
+ get(1+column*4),
+ get(2+column*4),
+ get(3+column*4) );
+ return v_out;
+ }
+
+ /**
+ * Get the named column of the given column-major matrix to v_out.
+ * @param column named column to copy
+ * @param v_out the column-vector storage
+ * @return given result vector v_out for chaining
+ */
+ public Vec3f getColumn(final int column, final Vec3f v_out) {
+ v_out.set( get(0+column*4),
+ get(1+column*4),
+ get(2+column*4) );
+ return v_out;
+ }
+
+ /**
+ * Get the named row of the given column-major matrix to v_out.
+ * @param row named row to copy
+ * @param v_out the row-vector storage
+ * @return given result vector v_out for chaining
+ */
+ public Vec4f getRow(final int row, final Vec4f v_out) {
+ v_out.set( get(row+0*4),
+ get(row+1*4),
+ get(row+2*4),
+ get(row+3*4) );
+ return v_out;
+ }
+
+ /**
+ * Get the named row of the given column-major matrix to v_out.
+ * @param row named row to copy
+ * @param v_out the row-vector storage
+ * @return given result vector v_out for chaining
+ */
+ public Vec3f getRow(final int row, final Vec3f v_out) {
+ v_out.set( get(row+0*4),
+ get(row+1*4),
+ get(row+2*4) );
+ return v_out;
+ }
+
+ /**
+ * Get this matrix into the given float[16] array at {@code dst_off} in column major order.
+ *
+ * @param dst float[16] array storage in column major order
+ * @param dst_off offset
+ */
+ public void get(final float[] dst, final int dst_off) {
+ System.arraycopy(m, 0, dst, dst_off, 16);
+ }
+
+ /**
+ * Get this matrix into the given float[16] array in column major order.
+ *
+ * @param dst float[16] array storage in column major order
+ */
+ public void get(final float[] dst) {
+ System.arraycopy(m, 0, dst, 0, 16);
+ }
+
+ /**
+ * Get this matrix into the given {@link FloatBuffer} in column major order.
+ *
+ * Implementation uses relative {@link FloatBuffer#put(float)},
+ * hence caller may want to issue {@link FloatBuffer#reset()} thereafter.
+ *
+ *
+ * @param dst {@link FloatBuffer} array storage in column major order
+ */
+ public void get(final FloatBuffer dst) {
+ dst.put(m, 0, 16);
+ }
+
+ //
+ // Basic matrix operations
+ //
+
+ /**
+ * Returns the determinant of this matrix
+ * @return the matrix determinant
+ */
+ public float determinant() {
+ float ret = 0;
+ ret += m[0+0*4] * ( + m[1+1*4]*(m[2+2*4]*m[3+3*4] - m[2+3*4]*m[3+2*4]) - m[1+2*4]*(m[2+1*4]*m[3+3*4] - m[2+3*4]*m[3+1*4]) + m[1+3*4]*(m[2+1*4]*m[3+2*4] - m[2+2*4]*m[3+1*4]));
+ ret -= m[0+1*4] * ( + m[1+0*4]*(m[2+2*4]*m[3+3*4] - m[2+3*4]*m[3+2*4]) - m[1+2*4]*(m[2+0*4]*m[3+3*4] - m[2+3*4]*m[3+0*4]) + m[1+3*4]*(m[2+0*4]*m[3+2*4] - m[2+2*4]*m[3+0*4]));
+ ret += m[0+2*4] * ( + m[1+0*4]*(m[2+1*4]*m[3+3*4] - m[2+3*4]*m[3+1*4]) - m[1+1*4]*(m[2+0*4]*m[3+3*4] - m[2+3*4]*m[3+0*4]) + m[1+3*4]*(m[2+0*4]*m[3+1*4] - m[2+1*4]*m[3+0*4]));
+ ret -= m[0+3*4] * ( + m[1+0*4]*(m[2+1*4]*m[3+2*4] - m[2+2*4]*m[3+1*4]) - m[1+1*4]*(m[2+0*4]*m[3+2*4] - m[2+2*4]*m[3+0*4]) + m[1+2*4]*(m[2+0*4]*m[3+1*4] - m[2+1*4]*m[3+0*4]));
+ return ret;
+ }
+
+ /**
+ * Transpose this matrix.
+ *
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb transpose() {
+ float tmp;
+
+ tmp = m[1+0*4];
+ m[1+0*4] = m[0+1*4];
+ m[0+1*4] = tmp;
+
+ tmp = m[2+0*4];
+ m[2+0*4] = m[0+2*4];
+ m[0+2*4] = tmp;
+
+ tmp = m[3+0*4];
+ m[3+0*4] = m[0+3*4];
+ m[0+3*4] = tmp;
+
+ tmp = m[2+1*4];
+ m[2+1*4] = m[1+2*4];
+ m[1+2*4] = tmp;
+
+ tmp = m[3+1*4];
+ m[3+1*4] = m[1+3*4];
+ m[1+3*4] = tmp;
+
+ tmp = m[3+2*4];
+ m[3+2*4] = m[2+3*4];
+ m[2+3*4] = tmp;
+
+ return this;
+ }
+
+ /**
+ * Transpose the given {@code src} matrix into this matrix.
+ *
+ * @param src source 4x4 matrix
+ * @return this matrix (result) for chaining
+ */
+ public final Matrix4fb transpose(final Matrix4fb src) {
+ if( src == this ) {
+ return transpose();
+ }
+ m[0+0*4] = src.m[0+0*4];
+ m[1+0*4] = src.m[0+1*4];
+ m[2+0*4] = src.m[0+2*4];
+ m[3+0*4] = src.m[0+3*4];
+
+ m[0+1*4] = src.m[1+0*4];
+ m[1+1*4] = src.m[1+1*4];
+ m[2+1*4] = src.m[1+2*4];
+ m[3+1*4] = src.m[1+3*4];
+
+ m[0+2*4] = src.m[2+0*4];
+ m[1+2*4] = src.m[2+1*4];
+ m[2+2*4] = src.m[2+2*4];
+ m[3+2*4] = src.m[2+3*4];
+
+ m[0+3*4] = src.m[3+0*4];
+ m[1+3*4] = src.m[3+1*4];
+ m[2+3*4] = src.m[3+2*4];
+ m[3+3*4] = src.m[3+3*4];
+ return this;
+ }
+
+ /**
+ * Invert this matrix.
+ * @return false if this matrix is singular and inversion not possible, otherwise true
+ */
+ public boolean invert() {
+ final float scale;
+ {
+ float max = Math.abs(m[0]);
+
+ for( int i = 1; i < 16; i++ ) {
+ final float a = Math.abs(m[i]);
+ if( a > max ) max = a;
+ }
+ if( 0 == max ) {
+ return false;
+ }
+ scale = 1.0f/max;
+ }
+
+ final float a00 = m[0+0*4]*scale;
+ final float a10 = m[1+0*4]*scale;
+ final float a20 = m[2+0*4]*scale;
+ final float a30 = m[3+0*4]*scale;
+
+ final float a01 = m[0+1*4]*scale;
+ final float a11 = m[1+1*4]*scale;
+ final float a21 = m[2+1*4]*scale;
+ final float a31 = m[3+1*4]*scale;
+
+ final float a02 = m[0+2*4]*scale;
+ final float a12 = m[1+2*4]*scale;
+ final float a22 = m[2+2*4]*scale;
+ final float a32 = m[3+2*4]*scale;
+
+ final float a03 = m[0+3*4]*scale;
+ final float a13 = m[1+3*4]*scale;
+ final float a23 = m[2+3*4]*scale;
+ final float a33 = m[3+3*4]*scale;
+
+ final float b00 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31);
+ final float b01 = -( + a10*(a22*a33 - a23*a32) - a12*(a20*a33 - a23*a30) + a13*(a20*a32 - a22*a30));
+ final float b02 = + a10*(a21*a33 - a23*a31) - a11*(a20*a33 - a23*a30) + a13*(a20*a31 - a21*a30);
+ final float b03 = -( + a10*(a21*a32 - a22*a31) - a11*(a20*a32 - a22*a30) + a12*(a20*a31 - a21*a30));
+
+ final float b10 = -( + a01*(a22*a33 - a23*a32) - a02*(a21*a33 - a23*a31) + a03*(a21*a32 - a22*a31));
+ final float b11 = + a00*(a22*a33 - a23*a32) - a02*(a20*a33 - a23*a30) + a03*(a20*a32 - a22*a30);
+ final float b12 = -( + a00*(a21*a33 - a23*a31) - a01*(a20*a33 - a23*a30) + a03*(a20*a31 - a21*a30));
+ final float b13 = + a00*(a21*a32 - a22*a31) - a01*(a20*a32 - a22*a30) + a02*(a20*a31 - a21*a30);
+
+ final float b20 = + a01*(a12*a33 - a13*a32) - a02*(a11*a33 - a13*a31) + a03*(a11*a32 - a12*a31);
+ final float b21 = -( + a00*(a12*a33 - a13*a32) - a02*(a10*a33 - a13*a30) + a03*(a10*a32 - a12*a30));
+ final float b22 = + a00*(a11*a33 - a13*a31) - a01*(a10*a33 - a13*a30) + a03*(a10*a31 - a11*a30);
+ final float b23 = -( + a00*(a11*a32 - a12*a31) - a01*(a10*a32 - a12*a30) + a02*(a10*a31 - a11*a30));
+
+ final float b30 = -( + a01*(a12*a23 - a13*a22) - a02*(a11*a23 - a13*a21) + a03*(a11*a22 - a12*a21));
+ final float b31 = + a00*(a12*a23 - a13*a22) - a02*(a10*a23 - a13*a20) + a03*(a10*a22 - a12*a20);
+ final float b32 = -( + a00*(a11*a23 - a13*a21) - a01*(a10*a23 - a13*a20) + a03*(a10*a21 - a11*a20));
+ final float b33 = + a00*(a11*a22 - a12*a21) - a01*(a10*a22 - a12*a20) + a02*(a10*a21 - a11*a20);
+
+ final float det = (a00*b00 + a01*b01 + a02*b02 + a03*b03) / scale;
+
+ if( 0 == det ) {
+ return false;
+ }
+
+ m[0+0*4] = b00 / det;
+ m[1+0*4] = b01 / det;
+ m[2+0*4] = b02 / det;
+ m[3+0*4] = b03 / det;
+
+ m[0+1*4] = b10 / det;
+ m[1+1*4] = b11 / det;
+ m[2+1*4] = b12 / det;
+ m[3+1*4] = b13 / det;
+
+ m[0+2*4] = b20 / det;
+ m[1+2*4] = b21 / det;
+ m[2+2*4] = b22 / det;
+ m[3+2*4] = b23 / det;
+
+ m[0+3*4] = b30 / det;
+ m[1+3*4] = b31 / det;
+ m[2+3*4] = b32 / det;
+ m[3+3*4] = b33 / det;
+ return true;
+ }
+
+ /**
+ * Invert the {@code src} matrix values into this matrix
+ * @param src the source matrix, which values are to be inverted
+ * @return false if {@code src} matrix is singular and inversion not possible, otherwise true
+ */
+ public boolean invert(final Matrix4fb src) {
+ return load(src).invert();
+ }
+
+ /**
+ * Multiply matrix: [this] = [this] x [b]
+ *
+ * Roughly 15% slower than {@link #mul(Matrix4fb, Matrix4fb)}
+ * Roughly 3% slower than {@link FloatUtil#multMatrix(float[], float[])}
+ *
+ * @param b 4x4 matrix
+ * @return this matrix for chaining
+ * @see #mul(Matrix4fb, Matrix4fb)
+ */
+ public final Matrix4fb mul(final Matrix4fb b) {
+ final float b00 = b.m[0+0*4];
+ final float b10 = b.m[1+0*4];
+ final float b20 = b.m[2+0*4];
+ final float b30 = b.m[3+0*4];
+ final float b01 = b.m[0+1*4];
+ final float b11 = b.m[1+1*4];
+ final float b21 = b.m[2+1*4];
+ final float b31 = b.m[3+1*4];
+ final float b02 = b.m[0+2*4];
+ final float b12 = b.m[1+2*4];
+ final float b22 = b.m[2+2*4];
+ final float b32 = b.m[3+2*4];
+ final float b03 = b.m[0+3*4];
+ final float b13 = b.m[1+3*4];
+ final float b23 = b.m[2+3*4];
+ final float b33 = b.m[3+3*4];
+
+ float ai0=m[0+0*4]; // row-0, m[0+0*4]
+ float ai1=m[0+1*4];
+ float ai2=m[0+2*4];
+ float ai3=m[0+3*4];
+ m[0+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
+ m[0+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
+ m[0+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
+ m[0+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
+
+ ai0=m[1+0*4]; //row-1, m[1+0*4]
+ ai1=m[1+1*4];
+ ai2=m[1+2*4];
+ ai3=m[1+3*4];
+ m[1+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
+ m[1+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
+ m[1+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
+ m[1+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
+
+ ai0=m[2+0*4]; // row-2, m[2+0*4]
+ ai1=m[2+1*4];
+ ai2=m[2+2*4];
+ ai3=m[2+3*4];
+ m[2+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
+ m[2+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
+ m[2+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
+ m[2+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
+
+ ai0=m[3+0*4]; // row-3, m[3+0*4]
+ ai1=m[3+1*4];
+ ai2=m[3+2*4];
+ ai3=m[3+3*4];
+ m[3+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
+ m[3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
+ m[3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
+ m[3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
+ return this;
+ }
+
+ /**
+ * Multiply matrix: [this] = [a] x [b]
+ *
+ * Roughly 13% faster than {@link #mul(Matrix4fb)}
+ * Roughly 11% faster than {@link FloatUtil#multMatrix(float[], float[])}
+ *
+ * @param a 4x4 matrix
+ * @param b 4x4 matrix
+ * @return this matrix for chaining
+ * @see #mul(Matrix4fb)
+ */
+ public final Matrix4fb mul(final Matrix4fb a, final Matrix4fb b) {
+ final float b00 = b.m[0+0*4];
+ final float b10 = b.m[1+0*4];
+ final float b20 = b.m[2+0*4];
+ final float b30 = b.m[3+0*4];
+ final float b01 = b.m[0+1*4];
+ final float b11 = b.m[1+1*4];
+ final float b21 = b.m[2+1*4];
+ final float b31 = b.m[3+1*4];
+ final float b02 = b.m[0+2*4];
+ final float b12 = b.m[1+2*4];
+ final float b22 = b.m[2+2*4];
+ final float b32 = b.m[3+2*4];
+ final float b03 = b.m[0+3*4];
+ final float b13 = b.m[1+3*4];
+ final float b23 = b.m[2+3*4];
+ final float b33 = b.m[3+3*4];
+
+ float ai0=a.m[0+0*4]; // row-0, m[0+0*4]
+ float ai1=a.m[0+1*4];
+ float ai2=a.m[0+2*4];
+ float ai3=a.m[0+3*4];
+ m[0+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
+ m[0+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
+ m[0+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
+ m[0+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
+
+ ai0=a.m[1+0*4]; //row-1, m[1+0*4]
+ ai1=a.m[1+1*4];
+ ai2=a.m[1+2*4];
+ ai3=a.m[1+3*4];
+ m[1+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
+ m[1+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
+ m[1+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
+ m[1+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
+
+ ai0=a.m[2+0*4]; // row-2, m[2+0*4]
+ ai1=a.m[2+1*4];
+ ai2=a.m[2+2*4];
+ ai3=a.m[2+3*4];
+ m[2+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
+ m[2+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
+ m[2+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
+ m[2+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
+
+ ai0=a.m[3+0*4]; // row-3, m[3+0*4]
+ ai1=a.m[3+1*4];
+ ai2=a.m[3+2*4];
+ ai3=a.m[3+3*4];
+ m[3+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ;
+ m[3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ;
+ m[3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ;
+ m[3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ;
+ return this;
+ }
+
+ /**
+ * @param v_in 4-component column-vector
+ * @param v_out this * v_in
+ * @returns v_out for chaining
+ */
+ public final float[] mulVec4f(final float[/*4*/] v_in, final float[/*4*/] v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_in[0], y = v_in[1], z = v_in[2], w = v_in[3];
+ v_out[0] = x * m[0+0*4] + y * m[0+1*4] + z * m[0+2*4] + w * m[0+3*4];
+ v_out[1] = x * m[1+0*4] + y * m[1+1*4] + z * m[1+2*4] + w * m[1+3*4];
+ v_out[2] = x * m[2+0*4] + y * m[2+1*4] + z * m[2+2*4] + w * m[2+3*4];
+ v_out[3] = x * m[3+0*4] + y * m[3+1*4] + z * m[3+2*4] + w * m[3+3*4];
+ return v_out;
+ }
+
+ /**
+ * @param v_in 4-component column-vector
+ * @param v_out this * v_in
+ * @returns v_out for chaining
+ */
+ public final Vec4f mulVec4f(final Vec4f v_in, final Vec4f v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_in.x(), y = v_in.y(), z = v_in.z(), w = v_in.w();
+ v_out.set( x * m[0+0*4] + y * m[0+1*4] + z * m[0+2*4] + w * m[0+3*4],
+ x * m[1+0*4] + y * m[1+1*4] + z * m[1+2*4] + w * m[1+3*4],
+ x * m[2+0*4] + y * m[2+1*4] + z * m[2+2*4] + w * m[2+3*4],
+ x * m[3+0*4] + y * m[3+1*4] + z * m[3+2*4] + w * m[3+3*4] );
+ return v_out;
+ }
+
+ /**
+ * Affine 3f-vector transformation by 4x4 matrix
+ *
+ * 4x4 matrix multiplication with 3-component vector,
+ * using {@code 1} for for {@code v_in[3]} and dropping {@code v_out[3]},
+ * which shall be {@code 1}.
+ *
+ * @param v_in 3-component column-vector
+ * @param v_out m_in * v_in, 3-component column-vector
+ * @returns v_out for chaining
+ */
+ public final float[] mulVec3f(final float[/*3*/] v_in, final float[/*3*/] v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_in[0], y = v_in[1], z = v_in[2];
+ v_out[0] = x * m[0+0*4] + y * m[0+1*4] + z * m[0+2*4] + 1f * m[0+3*4];
+ v_out[1] = x * m[1+0*4] + y * m[1+1*4] + z * m[1+2*4] + 1f * m[1+3*4];
+ v_out[2] = x * m[2+0*4] + y * m[2+1*4] + z * m[2+2*4] + 1f * m[2+3*4];
+ return v_out;
+ }
+
+ /**
+ * Affine 3f-vector transformation by 4x4 matrix
+ *
+ * 4x4 matrix multiplication with 3-component vector,
+ * using {@code 1} for for {@code v_in.w()} and dropping {@code v_out.w()},
+ * which shall be {@code 1}.
+ *
+ * @param v_in 3-component column-vector {@link Vec3f}
+ * @param v_out m_in * v_in, 3-component column-vector {@link Vec3f}
+ * @returns v_out for chaining
+ */
+ public final Vec3f mulVec3f(final Vec3f v_in, final Vec3f v_out) {
+ // (one matrix row in column-major order) X (column vector)
+ final float x = v_in.x(), y = v_in.y(), z = v_in.z();
+ v_out.set( x * m[0+0*4] + y * m[0+1*4] + z * m[0+2*4] + 1f * m[0+3*4],
+ x * m[1+0*4] + y * m[1+1*4] + z * m[1+2*4] + 1f * m[1+3*4],
+ x * m[2+0*4] + y * m[2+1*4] + z * m[2+2*4] + 1f * m[2+3*4] );
+ return v_out;
+ }
+
+ //
+ // Matrix setTo...(), affine + basic
+ //
+
+ /**
+ * Set this matrix to translation.
+ *
+ Translation matrix (Column Order):
+ 1 0 0 0
+ 0 1 0 0
+ 0 0 1 0
+ x y z 1
+ *
+ * @param x x-axis translate
+ * @param y y-axis translate
+ * @param z z-axis translate
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb setToTranslation(final float x, final float y, final float z) {
+ m[0+0*4] = m[1+1*4] = m[2+2*4] = m[3+3*4] = 1.0f;
+ m[0+3*4] = x;
+ m[1+3*4] = y;
+ m[2+3*4] = z;
+ m[0+1*4] = m[0+2*4] =
+ m[1+0*4] = m[1+2*4] =
+ m[2+0*4] = m[2+1*4] =
+ m[3+0*4] = m[3+1*4] = m[3+2*4] = 0.0f;
+ return this;
+ }
+
+ /**
+ * Set this matrix to translation.
+ *
+ Translation matrix (Column Order):
+ 1 0 0 0
+ 0 1 0 0
+ 0 0 1 0
+ x y z 1
+ *
+ * @param t translate Vec3f
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb setToTranslation(final Vec3f t) {
+ return setToTranslation(t.x(), t.y(), t.z());
+ }
+
+ /**
+ * Set this matrix to scale.
+ *
+ Scale matrix (Any Order):
+ x 0 0 0
+ 0 y 0 0
+ 0 0 z 0
+ 0 0 0 1
+ *
+ * @param x x-axis scale
+ * @param y y-axis scale
+ * @param z z-axis scale
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb setToScale(final float x, final float y, final float z) {
+ m[3+3*4] = 1.0f;
+ m[0+0*4] = x;
+ m[1+1*4] = y;
+ m[2+2*4] = z;
+ m[0+1*4] = m[0+2*4] = m[0+3*4] =
+ m[1+0*4] = m[1+2*4] = m[1+3*4] =
+ m[2+0*4] = m[2+1*4] = m[2+3*4] =
+ m[3+0*4] = m[3+1*4] = m[3+2*4] = 0.0f;
+ return this;
+ }
+
+ /**
+ * Set this matrix to rotation from the given axis and angle in radians.
+ *
+ Rotation matrix (Column Order):
+ xx(1-c)+c xy(1-c)+zs xz(1-c)-ys 0
+ xy(1-c)-zs yy(1-c)+c yz(1-c)+xs 0
+ xz(1-c)+ys yz(1-c)-xs zz(1-c)+c 0
+ 0 0 0 1
+ *
+ * @see Matrix-FAQ Q38
+ * @param ang_rad angle in radians
+ * @param x x of rotation axis
+ * @param y y of rotation axis
+ * @param z z of rotation axis
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb setToRotationAxis(final float ang_rad, float x, float y, float z) {
+ final float c = FloatUtil.cos(ang_rad);
+ final float ic= 1.0f - c;
+ final float s = FloatUtil.sin(ang_rad);
+
+ final float[] tmpVec3f = { x, y, z };
+ VectorUtil.normalizeVec3(tmpVec3f);
+ x = tmpVec3f[0]; y = tmpVec3f[1]; z = tmpVec3f[2];
+
+ final float xy = x*y;
+ final float xz = x*z;
+ final float xs = x*s;
+ final float ys = y*s;
+ final float yz = y*z;
+ final float zs = z*s;
+ m[0+0*4] = x*x*ic+c;
+ m[1+0*4] = xy*ic+zs;
+ m[2+0*4] = xz*ic-ys;
+ m[3+0*4] = 0;
+
+ m[0+1*4] = xy*ic-zs;
+ m[1+1*4] = y*y*ic+c;
+ m[2+1*4] = yz*ic+xs;
+ m[3+1*4] = 0;
+
+ m[0+2*4] = xz*ic+ys;
+ m[1+2*4] = yz*ic-xs;
+ m[2+2*4] = z*z*ic+c;
+ m[3+2*4] = 0;
+
+ m[0+3*4] = 0f;
+ m[1+3*4] = 0f;
+ m[2+3*4] = 0f;
+ m[3+3*4] = 1f;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to rotation from the given axis and angle in radians.
+ *
+ Rotation matrix (Column Order):
+ xx(1-c)+c xy(1-c)+zs xz(1-c)-ys 0
+ xy(1-c)-zs yy(1-c)+c yz(1-c)+xs 0
+ xz(1-c)+ys yz(1-c)-xs zz(1-c)+c 0
+ 0 0 0 1
+ *
+ * @see Matrix-FAQ Q38
+ * @param ang_rad angle in radians
+ * @param axis rotation axis
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb setToRotationAxis(final float ang_rad, final Vec3f axis) {
+ return setToRotationAxis(ang_rad, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this matrix to rotation from the given Euler rotation angles in radians.
+ *
+ * The rotations are applied in the given order:
+ *
+ * - y - heading
+ * - z - attitude
+ * - x - bank
+ *
+ *
+ * @param bankX the Euler pitch angle in radians. (rotation about the X axis)
+ * @param headingY the Euler yaw angle in radians. (rotation about the Y axis)
+ * @param attitudeZ the Euler roll angle in radians. (rotation about the Z axis)
+ * @return this matrix for chaining
+ *
+ * Implementation does not use Quaternion and hence is exposed to
+ * Gimbal-Lock,
+ * consider using {@link #setToRotation(Quaternion)}.
+ *
+ * @see Matrix-FAQ Q36
+ * @see euclideanspace.com-eulerToMatrix
+ * @see #setToRotation(Quaternion)
+ */
+ public Matrix4fb setToRotationEuler(final float bankX, final float headingY, final float attitudeZ) {
+ // Assuming the angles are in radians.
+ final float ch = FloatUtil.cos(headingY);
+ final float sh = FloatUtil.sin(headingY);
+ final float ca = FloatUtil.cos(attitudeZ);
+ final float sa = FloatUtil.sin(attitudeZ);
+ final float cb = FloatUtil.cos(bankX);
+ final float sb = FloatUtil.sin(bankX);
+
+ m[0+0*4] = ch*ca;
+ m[1+0*4] = sa;
+ m[2+0*4] = -sh*ca;
+ m[3+0*4] = 0;
+
+ m[0+1*4] = sh*sb - ch*sa*cb;
+ m[1+1*4] = ca*cb;
+ m[2+1*4] = sh*sa*cb + ch*sb;
+ m[3+1*4] = 0;
+
+ m[0+2*4] = ch*sa*sb + sh*cb;
+ m[1+2*4] = -ca*sb;
+ m[2+2*4] = -sh*sa*sb + ch*cb;
+ m[3+2*4] = 0;
+
+ m[0+3*4] = 0;
+ m[1+3*4] = 0;
+ m[2+3*4] = 0;
+ m[3+3*4] = 1;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to rotation using the given Quaternion.
+ *
+ * Implementation Details:
+ *
+ * - makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}
+ * - The fields [m[0+0*4] .. m[2+2*4]] define the rotation
+ *
+ *
+ *
+ * @param q the Quaternion representing the rotation
+ * @return this matrix for chaining
+ * @see Matrix-FAQ Q54
+ * @see Quaternion#toMatrix(float[], int)
+ * @see #getRotation()
+ */
+ public final Matrix4fb setToRotation(final Quaternion q) {
+ // pre-multiply scaled-reciprocal-magnitude to reduce multiplications
+ final float norm = q.magnitudeSquared();
+ if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) {
+ // identity matrix -> srecip = 0f
+ loadIdentity();
+ return this;
+ }
+ final float srecip;
+ if ( FloatUtil.isEqual(1f, norm, FloatUtil.EPSILON) ) {
+ srecip = 2f;
+ } else {
+ srecip = 2.0f / norm;
+ }
+
+ final float x = q.x();
+ final float y = q.y();
+ final float z = q.z();
+ final float w = q.w();
+
+ final float xs = srecip * x;
+ final float ys = srecip * y;
+ final float zs = srecip * z;
+
+ final float xx = x * xs;
+ final float xy = x * ys;
+ final float xz = x * zs;
+ final float xw = xs * w;
+ final float yy = y * ys;
+ final float yz = y * zs;
+ final float yw = ys * w;
+ final float zz = z * zs;
+ final float zw = zs * w;
+
+ m[0+0*4] = 1f - ( yy + zz );
+ m[0+1*4] = ( xy - zw );
+ m[0+2*4] = ( xz + yw );
+ m[0+3*4] = 0f;
+
+ m[1+0*4] = ( xy + zw );
+ m[1+1*4] = 1f - ( xx + zz );
+ m[1+2*4] = ( yz - xw );
+ m[1+3*4] = 0f;
+
+ m[2+0*4] = ( xz - yw );
+ m[2+1*4] = ( yz + xw );
+ m[2+2*4] = 1f - ( xx + yy );
+ m[2+3*4] = 0f;
+
+ m[3+0*4] = m[3+1*4] = m[3+2*4] = 0f;
+ m[3+3*4] = 1f;
+ return this;
+ }
+
+ /**
+ * Returns the rotation [m[0+0*4] .. m[2+2*4]] fields converted to a Quaternion.
+ * @param res resulting Quaternion
+ * @return the resulting Quaternion for chaining.
+ * @see Quaternion#setFromMatrix(float, float, float, float, float, float, float, float, float)
+ * @see #setToRotation(Quaternion)
+ */
+ public final Quaternion getRotation(final Quaternion res) {
+ res.setFromMatrix(m[0+0*4], m[0+1*4], m[0+2*4], m[1+0*4], m[1+1*4], m[1+2*4], m[2+0*4], m[2+1*4], m[2+2*4]);
+ return res;
+ }
+
+ /**
+ * Set this matrix to orthogonal projection.
+ *
+ Ortho matrix (Column Order):
+ 2/dx 0 0 0
+ 0 2/dy 0 0
+ 0 0 2/dz 0
+ tx ty tz 1
+ *
+ * @param left
+ * @param right
+ * @param bottom
+ * @param top
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ */
+ public Matrix4fb setToOrtho(final float left, final float right,
+ final float bottom, final float top,
+ final float zNear, final float zFar) {
+ {
+ // m[0+0*4] = m[1+1*4] = m[2+2*4] = m[3+3*4] = 1f;
+ m[1+0*4] = m[2+0*4] = m[3+0*4] = 0f;
+ m[0+1*4] = m[2+1*4] = m[3+1*4] = 0f;
+ m[0+2*4] = m[1+2*4] = m[3+2*4] = 0f;
+ // m[0+3*4] = m[1+3*4] = m[2+3*4] = 0f;
+ }
+ final float dx=right-left;
+ final float dy=top-bottom;
+ final float dz=zFar-zNear;
+ final float tx=-1.0f*(right+left)/dx;
+ final float ty=-1.0f*(top+bottom)/dy;
+ final float tz=-1.0f*(zFar+zNear)/dz;
+
+ m[0+0*4] = 2.0f/dx;
+ m[1+1*4] = 2.0f/dy;
+ m[2+2*4] = -2.0f/dz;
+
+ m[0+3*4] = tx;
+ m[1+3*4] = ty;
+ m[2+3*4] = tz;
+ m[3+3*4] = 1f;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to frustum.
+ *
+ Frustum matrix (Column Order):
+ 2*zNear/dx 0 0 0
+ 0 2*zNear/dy 0 0
+ A B C -1
+ 0 0 D 0
+ *
+ * @param left
+ * @param right
+ * @param bottom
+ * @param top
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}
+ * or {@code left == right}, or {@code bottom == top}.
+ */
+ public Matrix4fb setToFrustum(final float left, final float right,
+ final float bottom, final float top,
+ final float zNear, final float zFar) throws IllegalArgumentException {
+ if( zNear <= 0.0f || zFar <= zNear ) {
+ throw new IllegalArgumentException("Requirements zNear > 0 and zFar > zNear, but zNear "+zNear+", zFar "+zFar);
+ }
+ if( left == right || top == bottom) {
+ throw new IllegalArgumentException("GL_INVALID_VALUE: top,bottom and left,right must not be equal");
+ }
+ {
+ // m[0+0*4] = m[1+1*4] = m[2+2*4] = m[3+3*4] = 1f;
+ m[1+0*4] = m[2+0*4] = m[3+0*4] = 0f;
+ m[0+1*4] = m[2+1*4] = m[3+1*4] = 0f;
+ m[0+3*4] = m[1+3*4] = 0f;
+ }
+ final float zNear2 = 2.0f*zNear;
+ final float dx=right-left;
+ final float dy=top-bottom;
+ final float dz=zFar-zNear;
+ final float A=(right+left)/dx;
+ final float B=(top+bottom)/dy;
+ final float C=-1.0f*(zFar+zNear)/dz;
+ final float D=-2.0f*(zFar*zNear)/dz;
+
+ m[0+0*4] = zNear2/dx;
+ m[1+1*4] = zNear2/dy;
+
+ m[0+2*4] = A;
+ m[1+2*4] = B;
+ m[2+2*4] = C;
+ m[3+2*4] = -1.0f;
+
+ m[2+3*4] = D;
+ m[3+3*4] = 0f;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to perspective {@link #setToFrustum(float, float, float, float, float, float) frustum} projection.
+ *
+ * @param fovy_rad angle in radians
+ * @param aspect aspect ratio width / height
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}
+ * @see #setToFrustum(float, float, float, float, float, float)
+ */
+ public Matrix4fb setToPerspective(final float fovy_rad, final float aspect, final float zNear, final float zFar) throws IllegalArgumentException {
+ final float top = FloatUtil.tan(fovy_rad/2f) * zNear; // use tangent of half-fov !
+ final float bottom = -1.0f * top; // -1f * fovhvTan.top * zNear
+ final float left = aspect * bottom; // aspect * -1f * fovhvTan.top * zNear
+ final float right = aspect * top; // aspect * fovhvTan.top * zNear
+ return setToFrustum(left, right, bottom, top, zNear, zFar);
+ }
+
+ /**
+ * Set this matrix to perspective {@link #setToFrustum(float, float, float, float, float, float) frustum} projection.
+ *
+ * @param fovhv {@link FovHVHalves} field of view in both directions, may not be centered, either in radians or tangent
+ * @param zNear
+ * @param zFar
+ * @return this matrix for chaining
+ * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}
+ * @see #setToFrustum(float, float, float, float, float, float)
+ * @see Frustum#updateByFovDesc(float[], int, boolean, Frustum.FovDesc)
+ */
+ public Matrix4fb setToPerspective(final FovHVHalves fovhv, final float zNear, final float zFar) throws IllegalArgumentException {
+ final FovHVHalves fovhvTan = fovhv.toTangents(); // use tangent of half-fov !
+ final float top = fovhvTan.top * zNear;
+ final float bottom = -1.0f * fovhvTan.bottom * zNear;
+ final float left = -1.0f * fovhvTan.left * zNear;
+ final float right = fovhvTan.right * zNear;
+ return setToFrustum(left, right, bottom, top, zNear, zFar);
+ }
+
+ /**
+ * Calculate the frustum planes in world coordinates
+ * using the passed float[16] as premultiplied P*MV (column major order).
+ *
+ * Frustum plane's normals will point to the inside of the viewing frustum,
+ * as required by this class.
+ *
+ */
+ public void updateFrustumPlanes(final Frustum frustum) {
+ // Left: a = m41 + m[1+1*4], b = m42 + m[1+2*4], c = m43 + m[1+3*4], d = m44 + m14 - [1..4] column-major
+ // Left: a = m[3+0*4] + m[0+0*4], b = m[3+1*4] + m[0+1*4], c = m[3+2*4] + m[0+2*4], d = m[3+3*4] + m[0+3*4] - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.LEFT];
+ final Vec3f p_n = p.n;
+ p_n.set( m[3+0*4] + m[0+0*4],
+ m[3+1*4] + m[0+1*4],
+ m[3+2*4] + m[0+2*4] );
+ p.d = m[3+3*4] + m[0+3*4];
+ }
+
+ // Right: a = m41 - m[1+1*4], b = m42 - m[1+2*4], c = m43 - m[1+3*4], d = m44 - m14 - [1..4] column-major
+ // Right: a = m[3+0*4] - m[0+0*4], b = m[3+1*4] - m[0+1*4], c = m[3+2*4] - m[0+2*4], d = m[3+3*4] - m[0+3*4] - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.RIGHT];
+ final Vec3f p_n = p.n;
+ p_n.set( m[3+0*4] - m[0+0*4],
+ m[3+1*4] - m[0+1*4],
+ m[3+2*4] - m[0+2*4] );
+ p.d = m[3+3*4] - m[0+3*4];
+ }
+
+ // Bottom: a = m41m21, b = m42m22, c = m43m[2+3*4], d = m44m24 - [1..4] column-major
+ // Bottom: a = m30m10, b = m31m11, c = m32m12, d = m[3+3*4]m[1+3*4] - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.BOTTOM];
+ final Vec3f p_n = p.n;
+ p_n.set( m[3+0*4] + m[1+0*4],
+ m[3+1*4] + m[1+1*4],
+ m[3+2*4] + m[1+2*4] );
+ p.d = m[3+3*4] + m[1+3*4];
+ }
+
+ // Top: a = m41 - m[2+1*4], b = m42 - m[2+2*4], c = m43 - m[2+3*4], d = m44 - m24 - [1..4] column-major
+ // Top: a = m[3+0*4] - m[1+0*4], b = m[3+1*4] - m[1+1*4], c = m[3+2*4] - m[1+2*4], d = m[3+3*4] - m[1+3*4] - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.TOP];
+ final Vec3f p_n = p.n;
+ p_n.set( m[3+0*4] - m[1+0*4],
+ m[3+1*4] - m[1+1*4],
+ m[3+2*4] - m[1+2*4] );
+ p.d = m[3+3*4] - m[1+3*4];
+ }
+
+ // Near: a = m41m31, b = m42m32, c = m43m[3+3*4], d = m44m34 - [1..4] column-major
+ // Near: a = m30m20, b = m31m21, c = m32m22, d = m[3+3*4]m[2+3*4] - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.NEAR];
+ final Vec3f p_n = p.n;
+ p_n.set( m[3+0*4] + m[2+0*4],
+ m[3+1*4] + m[2+1*4],
+ m[3+2*4] + m[2+2*4] );
+ p.d = m[3+3*4] + m[2+3*4];
+ }
+
+ // Far: a = m41 - m[3+1*4], b = m42 - m[3+2*4], c = m43 - m[3+3*4], d = m44 - m34 - [1..4] column-major
+ // Far: a = m[3+0*4] - m[2+0*4], b = m[3+1*4] - m[2+1*4], c = m32m22, d = m[3+3*4]m[2+3*4] - [0..3] column-major
+ {
+ final Frustum.Plane p = frustum.getPlanes()[Frustum.FAR];
+ final Vec3f p_n = p.n;
+ p_n.set( m[3+0*4] - m[2+0*4],
+ m[3+1*4] - m[2+1*4],
+ m[3+2*4] - m[2+2*4] );
+ p.d = m[3+3*4] - m[2+3*4];
+ }
+
+ // Normalize all planes
+ for (int i = 0; i < 6; ++i) {
+ final Plane p = frustum.getPlanes()[i];
+ final Vec3f p_n = p.n;
+ final float invLen = 1f / p_n.length();
+ p_n.scale(invLen);
+ p.d *= invLen;
+ }
+ }
+
+ /**
+ * Make given matrix the look-at matrix based on given parameters.
+ *
+ * Consist out of two matrix multiplications:
+ *
+ * R = L x T,
+ * with L for look-at matrix and
+ * T for eye translation.
+ *
+ * Result R can be utilized for projection or modelview multiplication, i.e.
+ * M = M x R,
+ * with M being the projection or modelview matrix.
+ *
+ *
+ * @param eye 3 component eye vector
+ * @param center 3 component center vector
+ * @param up 3 component up vector
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public Matrix4fb setToLookAt(final Vec3f eye, final Vec3f center, final Vec3f up, final Matrix4fb tmp) {
+ // normalized forward!
+ final Vec3f fwd = new Vec3f( center.x() - eye.x(),
+ center.y() - eye.y(),
+ center.z() - eye.z() ).normalize();
+
+ /* Side = forward x up, normalized */
+ final Vec3f side = fwd.cross(up).normalize();
+
+ /* Recompute up as: up = side x forward */
+ final Vec3f up2 = side.cross(fwd);
+
+ m[0+0*4] = side.x();
+ m[1+0*4] = up2.x();
+ m[2+0*4] = -fwd.x();
+ m[3+0*4] = 0;
+
+ m[0+1*4] = side.y();
+ m[1+1*4] = up2.y();
+ m[2+1*4] = -fwd.y();
+ m[3+1*4] = 0;
+
+ m[0+2*4] = side.z();
+ m[1+2*4] = up2.z();
+ m[2+2*4] = -fwd.z();
+ m[3+2*4] = 0;
+
+ m[0+3*4] = 0;
+ m[1+3*4] = 0;
+ m[2+3*4] = 0;
+ m[3+3*4] = 1;
+
+ return mul( tmp.setToTranslation( -eye.x(), -eye.y(), -eye.z() ) );
+ }
+
+ //
+ // Matrix affine operations using setTo..()
+ //
+
+ /**
+ * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(float, float, float, float) axis-rotation matrix}.
+ * @see Matrix-FAQ Q38
+ * @param angrad angle in radians
+ * @param x x of rotation axis
+ * @param y y of rotation axis
+ * @param z z of rotation axis
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb rotate(final float ang_rad, final float x, final float y, final float z, final Matrix4fb tmp) {
+ return mul( tmp.setToRotationAxis(ang_rad, x, y, z) );
+ }
+
+ /**
+ * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(float, Vec3f) axis-rotation matrix}.
+ * @see Matrix-FAQ Q38
+ * @param angrad angle in radians
+ * @param axis rotation axis
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb rotate(final float ang_rad, final Vec3f axis, final Matrix4fb tmp) {
+ return mul( tmp.setToRotationAxis(ang_rad, axis) );
+ }
+
+ /**
+ * Rotate this matrix with the given {@link Quaternion}, i.e. multiply by {@link #setToRotation(Quaternion) Quaternion's rotation matrix}.
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb rotate(final Quaternion quat, final Matrix4fb tmp) {
+ return mul( tmp.setToRotation(quat) );
+ }
+
+ /**
+ * Translate this matrix, i.e. multiply by {@link #setToTranslation(float, float, float) translation matrix}.
+ * @param x x translation
+ * @param y y translation
+ * @param z z translation
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb translate(final float x, final float y, final float z, final Matrix4fb tmp) {
+ return mul( tmp.setToTranslation(x, y, z) );
+ }
+
+ /**
+ * Translate this matrix, i.e. multiply by {@link #setToTranslation(Vec3f) translation matrix}.
+ * @param t translation Vec3f
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb translate(final Vec3f t, final Matrix4fb tmp) {
+ return mul( tmp.setToTranslation(t) );
+ }
+
+ /**
+ * Scale this matrix, i.e. multiply by {@link #setToScale(float, float, float) scale matrix}.
+ * @param x x scale
+ * @param y y scale
+ * @param z z scale
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb scale(final float x, final float y, final float z, final Matrix4fb tmp) {
+ return mul( tmp.setToScale(x, y, z) );
+ }
+
+ /**
+ * Scale this matrix, i.e. multiply by {@link #setToScale(float, float, float) scale matrix}.
+ * @param s scale for x-, y- and z-axis
+ * @param tmp temporary Matrix4f used for multiplication
+ * @return this matrix for chaining
+ */
+ public final Matrix4fb scale(final float s, final Matrix4fb tmp) {
+ return mul( tmp.setToScale(s, s, s) );
+ }
+
+ //
+ // Matrix Stack
+ //
+
+ /**
+ * Push the matrix to it's stack, while preserving this matrix values.
+ * @see #pop()
+ */
+ public final void push() {
+ stack.push(this);
+ }
+
+ /**
+ * Pop the current matrix from it's stack, replacing this matrix values.
+ * @see #push()
+ */
+ public final void pop() {
+ stack.pop(this);
+ }
+
+ //
+ // equals
+ //
+
+ /**
+ * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ *
+ * Implementation considers following corner cases:
+ *
+ * - NaN == NaN
+ * - +Inf == +Inf
+ * - -Inf == -Inf
+ *
+ * @param o comparison value
+ * @param epsilon consider using {@link FloatUtil#EPSILON}
+ * @return true if all components differ less than {@code epsilon}, otherwise false.
+ */
+ public boolean isEqual(final Matrix4fb o, final float epsilon) {
+ if( this == o ) {
+ return true;
+ } else {
+ for(int i=0; i<16; ++i) {
+ if( !FloatUtil.isEqual(m[i], o.m[i], epsilon) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}.
+ *
+ * Implementation considers following corner cases:
+ *
+ * - NaN == NaN
+ * - +Inf == +Inf
+ * - -Inf == -Inf
+ *
+ * @param o comparison value
+ * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false.
+ */
+ public boolean isEqual(final Matrix4fb o) {
+ return isEqual(o, FloatUtil.EPSILON);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if( o instanceof Matrix4fb ) {
+ return isEqual((Matrix4fb)o, FloatUtil.EPSILON);
+ } else {
+ return false;
+ }
+ }
+
+ //
+ // Static multi Matrix ops
+ //
+
+ /**
+ * Map object coordinates to window coordinates.
+ *
+ * Traditional gluProject
implementation.
+ *
+ *
+ * @param obj object position, 3 component vector
+ * @param mMv modelview matrix
+ * @param mP projection matrix
+ * @param viewport 4 component viewport vector
+ * @param winPos 3 component window coordinate, the result
+ * @return true if successful, otherwise false (z is 1)
+ */
+ public static boolean mapObjToWin(final Vec3f obj, final Matrix4fb mMv, final Matrix4fb mP,
+ final int[] viewport, final float[] winPos)
+ {
+ final Vec4f vec4Tmp1 = new Vec4f(obj, 1f);
+
+ // vec4Tmp2 = Mv * o
+ // rawWinPos = P * vec4Tmp2
+ // rawWinPos = P * ( Mv * o )
+ // rawWinPos = P * Mv * o
+ final Vec4f vec4Tmp2 = mMv.mulVec4f(vec4Tmp1, new Vec4f());
+ final Vec4f rawWinPos = mP.mulVec4f(vec4Tmp2, vec4Tmp1);
+
+ if (rawWinPos.w() == 0.0f) {
+ return false;
+ }
+
+ final float s = ( 1.0f / rawWinPos.w() ) * 0.5f;
+
+ // Map x, y and z to range 0-1 (w is ignored)
+ rawWinPos.scale(s).add(0.5f, 0.5f, 0.5f, 0f);
+
+ // Map x,y to viewport
+ winPos[0] = rawWinPos.x() * viewport[2] + viewport[0];
+ winPos[1] = rawWinPos.y() * viewport[3] + viewport[1];
+ winPos[2] = rawWinPos.z();
+
+ return true;
+ }
+
+ /**
+ * Map object coordinates to window coordinates.
+ *
+ * Traditional gluProject
implementation.
+ *
+ *
+ * @param obj object position, 3 component vector
+ * @param mPMv [projection] x [modelview] matrix, i.e. P x Mv
+ * @param viewport 4 component viewport vector
+ * @param winPos 3 component window coordinate, the result
+ * @return true if successful, otherwise false (z is 1)
+ */
+ public static boolean mapObjToWin(final Vec3f obj, final Matrix4fb mPMv,
+ final int[] viewport, final float[] winPos)
+ {
+ final Vec4f vec4Tmp2 = new Vec4f(obj, 1f);
+
+ // rawWinPos = P * Mv * o
+ final Vec4f rawWinPos = mPMv.mulVec4f(vec4Tmp2, new Vec4f());
+
+ if (rawWinPos.w() == 0.0f) {
+ return false;
+ }
+
+ final float s = ( 1.0f / rawWinPos.w() ) * 0.5f;
+
+ // Map x, y and z to range 0-1 (w is ignored)
+ rawWinPos.scale(s).add(0.5f, 0.5f, 0.5f, 0f);
+
+ // Map x,y to viewport
+ winPos[0] = rawWinPos.x() * viewport[2] + viewport[0];
+ winPos[1] = rawWinPos.y() * viewport[3] + viewport[1];
+ winPos[2] = rawWinPos.z();
+
+ return true;
+ }
+
+ /**
+ * Map window coordinates to object coordinates.
+ *
+ * Traditional gluUnProject
implementation.
+ *
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param mMv 4x4 modelview matrix
+ * @param mP 4x4 projection matrix
+ * @param viewport 4 component viewport vector
+ * @param objPos 3 component object coordinate, the result
+ * @param mat4Tmp 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz,
+ final Matrix4fb mMv, final Matrix4fb mP,
+ final int[] viewport,
+ final Vec3f objPos,
+ final Matrix4fb mat4Tmp)
+ {
+ // invPMv = Inv(P x Mv)
+ final Matrix4fb invPMv = mat4Tmp.mul(mP, mMv);
+ if( !invPMv.invert() ) {
+ return false;
+ }
+
+ final Vec4f winPos = new Vec4f(winx, winy, winz, 1f);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport[0], -viewport[1], 0f, 0f).scale(1f/viewport[2], 1f/viewport[3], 1f, 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // rawObjPos = Inv(P x Mv) * winPos
+ final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f());
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ return true;
+ }
+
+ /**
+ * Map window coordinates to object coordinates.
+ *
+ * Traditional gluUnProject
implementation.
+ *
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv)
+ * @param viewport 4 component viewport vector
+ * @param objPos 3 component object coordinate, the result
+ * @param mat4Tmp 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz,
+ final Matrix4fb invPMv,
+ final int[] viewport,
+ final Vec3f objPos,
+ final Matrix4fb mat4Tmp)
+ {
+ final Vec4f winPos = new Vec4f(winx, winy, winz, 1f);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport[0], -viewport[1], 0f, 0f).scale(1f/viewport[2], 1f/viewport[3], 1f, 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // rawObjPos = Inv(P x Mv) * winPos
+ final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f());
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ return true;
+ }
+
+ /**
+ * Map two window coordinates to two object coordinates,
+ * distinguished by their z component.
+ *
+ * Traditional gluUnProject
implementation.
+ *
+ *
+ * @param winx
+ * @param winy
+ * @param winz1
+ * @param winz2
+ * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv)
+ * @param viewport 4 component viewport vector
+ * @param objPos1 3 component object coordinate, the result
+ * @param mat4Tmp 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj(final float winx, final float winy, final float winz1, final float winz2,
+ final Matrix4fb invPMv,
+ final int[] viewport,
+ final Vec3f objPos1, final Vec3f objPos2,
+ final Matrix4fb mat4Tmp)
+ {
+ final Vec4f winPos = new Vec4f(winx, winy, winz1, 1f);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport[0], -viewport[1], 0f, 0f).scale(1f/viewport[2], 1f/viewport[3], 1f, 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // rawObjPos = Inv(P x Mv) * winPos1
+ final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f());
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos1.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ //
+ // winz2
+ //
+ // Map Z to range -1 to 1
+ winPos.setZ( winz2 * 2f - 1f );
+
+ // rawObjPos = Inv(P x Mv) * winPos2
+ invPMv.mulVec4f(winPos, rawObjPos);
+
+ if ( rawObjPos.w() == 0.0f ) {
+ return false;
+ }
+ objPos2.set( rawObjPos.scale( 1f / rawObjPos.w() ) );
+
+ return true;
+ }
+
+ /**
+ * Map window coordinates to object coordinates.
+ *
+ * Traditional gluUnProject4
implementation.
+ *
+ *
+ * @param winx
+ * @param winy
+ * @param winz
+ * @param clipw
+ * @param mMv 4x4 modelview matrix
+ * @param mP 4x4 projection matrix
+ * @param viewport 4 component viewport vector
+ * @param near
+ * @param far
+ * @param obj_pos 4 component object coordinate, the result
+ * @param mat4Tmp 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z)
+ */
+ public static boolean mapWinToObj4(final float winx, final float winy, final float winz, final float clipw,
+ final Matrix4fb mMv, final Matrix4fb mP,
+ final int[] viewport,
+ final float near, final float far,
+ final Vec4f objPos,
+ final Matrix4fb mat4Tmp)
+ {
+ // invPMv = Inv(P x Mv)
+ final Matrix4fb invPMv = mat4Tmp.mul(mP, mMv);
+ if( !invPMv.invert() ) {
+ return false;
+ }
+
+ final Vec4f winPos = new Vec4f(winx, winy, winz, clipw);
+
+ // Map x and y from window coordinates
+ winPos.add(-viewport[0], -viewport[1], -near, 0f).scale(1f/viewport[2], 1f/viewport[3], 1f/(far-near), 1f);
+
+ // Map to range -1 to 1
+ winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f);
+
+ // objPos = Inv(P x Mv) * winPos
+ invPMv.mulVec4f(winPos, objPos);
+
+ if ( objPos.w() == 0.0f ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Map two window coordinates w/ shared X/Y and distinctive Z
+ * to a {@link Ray}. The resulting {@link Ray} maybe used for picking
+ * using a {@link AABBox#getRayIntersection(Ray, float[]) bounding box}.
+ *
+ * Notes for picking winz0 and winz1:
+ *
+ * - see {@link FloatUtil#getZBufferEpsilon(int, float, float)}
+ * - see {@link FloatUtil#getZBufferValue(int, float, float, float)}
+ * - see {@link FloatUtil#getOrthoWinZ(float, float, float)}
+ *
+ *
+ * @param winx
+ * @param winy
+ * @param winz0
+ * @param winz1
+ * @param mMv 4x4 modelview matrix
+ * @param mP 4x4 projection matrix
+ * @param viewport 4 component viewport vector
+ * @param ray storage for the resulting {@link Ray}
+ * @param mat4Tmp1 16 component matrix for temp storage
+ * @param mat4Tmp2 16 component matrix for temp storage
+ * @return true if successful, otherwise false (failed to invert matrix, or becomes z is infinity)
+ */
+ public static boolean mapWinToRay(final float winx, final float winy, final float winz0, final float winz1,
+ final Matrix4fb mMv,
+ final Matrix4fb mP,
+ final int[] viewport,
+ final Ray ray,
+ final Matrix4fb mat4Tmp1, final Matrix4fb mat4Tmp2) {
+ // invPMv = Inv(P x Mv)
+ final Matrix4fb invPMv = mat4Tmp1.mul(mP, mMv);
+ if( !invPMv.invert() ) {
+ return false;
+ }
+
+ if( mapWinToObj(winx, winy, winz0, winz1, invPMv, viewport,
+ ray.orig, ray.dir, mat4Tmp2) ) {
+ ray.dir.sub(ray.orig).normalize();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ //
+ // String and internals
+ //
+
+ /**
+ * @param sb optional passed StringBuilder instance to be used
+ * @param rowPrefix optional prefix for each row
+ * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter}
+ * @return matrix string representation
+ */
+ public StringBuilder toString(final StringBuilder sb, final String rowPrefix, final String f) {
+ final float[] tmp = new float[16];
+ this.get(tmp);
+ return FloatUtil.matrixToString(sb, rowPrefix, f,tmp, 0, 4, 4, false /* rowMajorOrder */);
+ }
+
+ @Override
+ public String toString() {
+ return toString(null, null, "%10.5f").toString();
+ }
+
+ private final float[] m = new float[16];
+
+ final Stack stack = new Stack(0, 16*16); // start w/ zero size, growSize is half GL-min size (32)
+
+ private static class Stack {
+ private int position;
+ private float[] buffer;
+ private final int growSize;
+
+ /**
+ * @param initialSize initial size
+ * @param growSize grow size if {@link #position()} is reached, maybe 0
+ * in which case an {@link IndexOutOfBoundsException} is thrown.
+ */
+ public Stack(final int initialSize, final int growSize) {
+ this.position = 0;
+ this.growSize = growSize;
+ this.buffer = new float[initialSize];
+ }
+
+ private final void growIfNecessary(final int length) throws IndexOutOfBoundsException {
+ if( position + length > buffer.length ) {
+ if( 0 >= growSize ) {
+ throw new IndexOutOfBoundsException("Out of fixed stack size: "+this);
+ }
+ final float[] newBuffer =
+ new float[buffer.length + growSize];
+ System.arraycopy(buffer, 0, newBuffer, 0, position);
+ buffer = newBuffer;
+ }
+ }
+
+ public final Matrix4fb push(final Matrix4fb src) throws IndexOutOfBoundsException {
+ growIfNecessary(16);
+ src.get(buffer, position);
+ position += 16;
+ return src;
+ }
+
+ public final Matrix4fb pop(final Matrix4fb dest) throws IndexOutOfBoundsException {
+ position -= 16;
+ dest.load(buffer, position);
+ return dest;
+ }
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestFloatUtilProject01NOUI.java b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestFloatUtilProject01NOUI.java
index 05126676d..107190840 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestFloatUtilProject01NOUI.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestFloatUtilProject01NOUI.java
@@ -76,12 +76,12 @@ public class TestFloatUtilProject01NOUI extends JunitTracer {
m.gluProject(1f, 0f, 0f, viewport, 0, winA00, 0);
System.err.println("A.0.0 - Project 1,0 -->" + Arrays.toString(winA00));
- FloatUtil.mapObjToWinCoords(1f, 0f, 0f, mat4PMv, viewport, 0, winB00, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(1f, 0f, 0f, mat4PMv, viewport, winB00, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.0 - Project 1,0 -->" + Arrays.toString(winB00));
m.gluProject(0f, 0f, 0f, viewport, 0, winA01, 0);
System.err.println("A.0.1 - Project 0,0 -->" + Arrays.toString(winA01));
- FloatUtil.mapObjToWinCoords(0f, 0f, 0f, mat4PMv, viewport, 0, winB01, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(0f, 0f, 0f, mat4PMv, viewport, winB01, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.1 - Project 0,0 -->" + Arrays.toString(winB01));
m.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
@@ -93,12 +93,12 @@ public class TestFloatUtilProject01NOUI extends JunitTracer {
m.gluProject(1f, 0f, 0f, viewport, 0, winA10, 0);
System.err.println("A.1.0 - Project 1,0 -->" +Arrays.toString(winA10));
- FloatUtil.mapObjToWinCoords(1f, 0f, 0f, mat4PMv, viewport, 0, winB10, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(1f, 0f, 0f, mat4PMv, viewport, winB10, vec4Tmp1, vec4Tmp2);
System.err.println("B.1.0 - Project 1,0 -->" +Arrays.toString(winB10));
m.gluProject(0f, 0f, 0f, viewport, 0, winA11, 0);
System.err.println("A.1.1 - Project 0,0 -->" +Arrays.toString(winA11));
- FloatUtil.mapObjToWinCoords(0f, 0f, 0f, mat4PMv, viewport, 0, winB11, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(0f, 0f, 0f, mat4PMv, viewport, winB11, vec4Tmp1, vec4Tmp2);
System.err.println("B.1.1 - Project 0,0 -->" +Arrays.toString(winB11));
Assert.assertArrayEquals("A/B 0.0 Project 1,0 failure", winB00, winA00, epsilon);
@@ -135,12 +135,12 @@ public class TestFloatUtilProject01NOUI extends JunitTracer {
m.gluProject(1f, 0f, 0f, viewport, 0, winA00, 0);
System.err.println("A.0.0 - Project 1,0 -->" + Arrays.toString(winA00));
- FloatUtil.mapObjToWinCoords(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB00, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB00, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.0 - Project 1,0 -->" + Arrays.toString(winB00));
m.gluProject(0f, 0f, 0f, viewport, 0, winA01, 0);
System.err.println("A.0.1 - Project 0,0 -->" + Arrays.toString(winA01));
- FloatUtil.mapObjToWinCoords(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB01, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB01, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.1 - Project 0,0 -->" + Arrays.toString(winB01));
m.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
@@ -154,12 +154,12 @@ public class TestFloatUtilProject01NOUI extends JunitTracer {
m.gluProject(1f, 0f, 0f, viewport, 0, winA10, 0);
System.err.println("A.1.0 - Project 1,0 -->" +Arrays.toString(winA10));
- FloatUtil.mapObjToWinCoords(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB10, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB10, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.1.0 - Project 1,0 -->" +Arrays.toString(winB10));
m.gluProject(0f, 0f, 0f, viewport, 0, winA11, 0);
System.err.println("A.1.1 - Project 0,0 -->" +Arrays.toString(winA11));
- FloatUtil.mapObjToWinCoords(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB11, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB11, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.1.1 - Project 0,0 -->" +Arrays.toString(winB11));
Assert.assertArrayEquals("A/B 0.0 Project 1,0 failure", winB00, winA00, epsilon);
@@ -197,12 +197,12 @@ public class TestFloatUtilProject01NOUI extends JunitTracer {
glu.gluProject(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winA00, 0);
System.err.println("A.0.0 - Project 1,0 -->" + Arrays.toString(winA00));
- FloatUtil.mapObjToWinCoords(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB00, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB00, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.0 - Project 1,0 -->" + Arrays.toString(winB00));
glu.gluProject(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winA01, 0);
System.err.println("A.0.1 - Project 0,0 -->" + Arrays.toString(winA01));
- FloatUtil.mapObjToWinCoords(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB01, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB01, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.1 - Project 0,0 -->" + Arrays.toString(winB01));
m.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
@@ -216,12 +216,12 @@ public class TestFloatUtilProject01NOUI extends JunitTracer {
glu.gluProject(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winA10, 0);
System.err.println("A.1.0 - Project 1,0 -->" +Arrays.toString(winA10));
- FloatUtil.mapObjToWinCoords(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB10, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB10, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.1.0 - Project 1,0 -->" +Arrays.toString(winB10));
glu.gluProject(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winA11, 0);
System.err.println("A.1.1 - Project 0,0 -->" +Arrays.toString(winA11));
- FloatUtil.mapObjToWinCoords(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB11, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB11, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.1.1 - Project 0,0 -->" +Arrays.toString(winB11));
Assert.assertArrayEquals("A/B 0.0 Project 1,0 failure", winB00, winA00, epsilon);
@@ -261,12 +261,12 @@ public class TestFloatUtilProject01NOUI extends JunitTracer {
glu.gluProject(1f, 0f, 0f, d_mat4Mv, 0, d_mat4P, 0, viewport, 0, winA00, 0);
System.err.println("A.0.0 - Project 1,0 -->" + Arrays.toString(winA00));
- FloatUtil.mapObjToWinCoords(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB00, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB00, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.0 - Project 1,0 -->" + Arrays.toString(winB00));
glu.gluProject(0f, 0f, 0f, d_mat4Mv, 0, d_mat4P, 0, viewport, 0, winA01, 0);
System.err.println("A.0.1 - Project 0,0 -->" + Arrays.toString(winA01));
- FloatUtil.mapObjToWinCoords(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB01, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB01, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.1 - Project 0,0 -->" + Arrays.toString(winB01));
m.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
@@ -282,12 +282,12 @@ public class TestFloatUtilProject01NOUI extends JunitTracer {
glu.gluProject(1f, 0f, 0f, d_mat4Mv, 0, d_mat4P, 0, viewport, 0, winA10, 0);
System.err.println("A.1.0 - Project 1,0 -->" +Arrays.toString(winA10));
- FloatUtil.mapObjToWinCoords(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB10, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(1f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB10, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.1.0 - Project 1,0 -->" +Arrays.toString(winB10));
glu.gluProject(0f, 0f, 0f, d_mat4Mv, 0, d_mat4P, 0, viewport, 0, winA11, 0);
System.err.println("A.1.1 - Project 0,0 -->" +Arrays.toString(winA11));
- FloatUtil.mapObjToWinCoords(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB11, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(0f, 0f, 0f, mat4Mv, 0, mat4P, 0, viewport, 0, winB11, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.1.1 - Project 0,0 -->" +Arrays.toString(winB11));
double[] d_winBxx = Buffers.getDoubleArray(winB00, 0, null, 0, -1);
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestFloatUtilProject02NOUI.java b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestFloatUtilProject02NOUI.java
index ed3f68f5d..c715a41a0 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestFloatUtilProject02NOUI.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestFloatUtilProject02NOUI.java
@@ -74,7 +74,7 @@ public class TestFloatUtilProject02NOUI extends JunitTracer {
System.err.println("pP");
System.err.println(FloatUtil.matrixToString(null, "", "%25.20ff", mat4P, 0, 4, 4, true/* rowMajorOrder */));
- FloatUtil.mapObjToWinCoords(objPos[0], objPos[1], objPos[2], mat4Mv, 0, mat4P, 0, viewport, 0, winHas, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(objPos[0], objPos[1], objPos[2], mat4Mv, 0, mat4P, 0, viewport, 0, winHas, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.0 - Project 1,0 -->" + Arrays.toString(winHas));
Assert.assertEquals("A/B 0.0 Project 1,0 failure.x", winExp[0], Math.round(winHas[0]));
@@ -112,7 +112,7 @@ public class TestFloatUtilProject02NOUI extends JunitTracer {
System.err.println("pP");
System.err.println(FloatUtil.matrixToString(null, "", "%25.20ff", mat4P, 0, 4, 4, true/* rowMajorOrder */));
- FloatUtil.mapObjToWinCoords(objPos[0], objPos[1], objPos[2], mat4Mv, 0, mat4P, 0, viewport, 0, winHas, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(objPos[0], objPos[1], objPos[2], mat4Mv, 0, mat4P, 0, viewport, 0, winHas, 0, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.0 - Project 1,0 -->" + Arrays.toString(winHas));
Assert.assertEquals("A/B 0.0 Project 1,0 failure.x", winExp[0], Math.round(winHas[0]));
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f01NOUI.java b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f01NOUI.java
new file mode 100644
index 000000000..2657bce03
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f01NOUI.java
@@ -0,0 +1,177 @@
+/**
+ * Copyright 2012-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.math;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
+import com.jogamp.opengl.math.Vec3f;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestMatrix4f01NOUI extends JunitTracer {
+
+ final float[] mI_0 = new float[]{ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1 };
+ final Matrix4f mI = new Matrix4f(mI_0);
+
+ final float[] m1_0 = new float[]{ 1, 3, 4, 0,
+ 6, 7, 8, 5,
+ 98, 7, 6, 9,
+ 54, 3, 2, 5 };
+ final Matrix4f m1 = new Matrix4f(m1_0);
+
+ final float[] m1T_0 = new float[]{ 1, 6, 98, 54,
+ 3, 7, 7, 3,
+ 4, 8, 6, 2,
+ 0, 5, 9, 5 };
+ final Matrix4f m1T = new Matrix4f(m1T_0);
+
+ final float[] m2_0 = new float[]{ 1, 6, 98, 54,
+ 3, 7, 7, 3,
+ 4, 8, 6, 2,
+ 0, 5, 9, 5 };
+ final Matrix4f m2 = new Matrix4f(m2_0);
+
+ final float[] m2xm1_0 =
+ new float[]{ 26, 59, 143, 71,
+ 59, 174, 730, 386,
+ 143, 730, 9770, 5370,
+ 71, 386, 5370, 2954 };
+ final Matrix4f m2xm1 = new Matrix4f(m2xm1_0);
+
+ final float[] m1xm2_0 =
+ new float[]{12557, 893, 748, 1182,
+ 893, 116, 116, 113,
+ 748, 116, 120, 104,
+ 1182, 113, 104, 131 };
+ final Matrix4f m1xm2 = new Matrix4f(m1xm2_0);
+
+ @Test
+ public void test00_load_get() {
+ {
+ final Matrix4f m = new Matrix4f();
+ Assert.assertEquals(mI, m);
+ }
+ {
+ final float[] f16 = new float[16];
+ m1.get(f16);
+ Assert.assertArrayEquals(m1_0, f16, FloatUtil.EPSILON);
+ final Matrix4f m = new Matrix4f();
+ m.load(f16);
+ Assert.assertEquals(m1, m);
+ }
+ }
+
+ @Test
+ public void test01_mul(){
+ {
+ final float[] r_0 = new float[16];
+ FloatUtil.multMatrix(m1_0, 0, m2_0, 0, r_0, 0);
+ Assert.assertArrayEquals(m1xm2_0, r_0, 0f);
+
+ Assert.assertEquals(m1xm2, new Matrix4f(m1).mul(m2));
+ Assert.assertEquals(m1xm2, new Matrix4f().mul(m1, m2));
+ }
+ {
+ final float[] r_0 = new float[16];
+ FloatUtil.multMatrix(m2_0, 0, m1_0, 0, r_0, 0);
+ Assert.assertArrayEquals(m2xm1_0, r_0, 0f);
+
+ Assert.assertEquals(m2xm1, new Matrix4f(m2).mul(m1));
+ Assert.assertEquals(m2xm1, new Matrix4f().mul(m2, m1));
+ }
+ }
+
+ @Test
+ public void test02_transpose() {
+ Assert.assertEquals(m1T, new Matrix4f(m1).transpose());
+ Assert.assertEquals(m1T, new Matrix4f().transpose(m1));
+ }
+
+ @Test
+ public void test80LookAtNegZIsNoOp() throws Exception {
+ final Matrix4f tmp = new Matrix4f();
+ final Matrix4f m = new Matrix4f();
+ // Look towards -z
+ m.setToLookAt(
+ new Vec3f(0, 0, 0), // eye
+ new Vec3f(0, 0, -1), // center
+ new Vec3f(0, 1, 0), // up
+ tmp);
+
+ /**
+ * The 3 rows of the matrix (= the 3 columns of the array/buffer) should be: side, up, -forward.
+ */
+ final Matrix4f exp = new Matrix4f(
+ new float[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ } );
+
+ Assert.assertEquals(exp, m);
+ }
+
+ @Test
+ public void test81LookAtPosY() throws Exception {
+ final Matrix4f tmp = new Matrix4f();
+ final Matrix4f m = new Matrix4f();
+ // Look towards -z
+ m.setToLookAt(
+ new Vec3f(0, 0, 0), // eye
+ new Vec3f(0, 1, 0), // center
+ new Vec3f(0, 0, 1), // up
+ tmp);
+
+ /**
+ * The 3 rows of the matrix (= the 3 columns of the array/buffer) should be: side, up, -forward.
+ */
+ final Matrix4f exp = new Matrix4f(
+ new float[] {
+ 1, 0, 0, 0,
+ 0, 0, -1, 0,
+ 0, 1, 0, 0,
+ 0, 0, 0, 1
+ } );
+
+ Assert.assertEquals(exp, m);
+ }
+
+ public static void main(final String args[]) {
+ org.junit.runner.JUnitCore.main(TestMatrix4f01NOUI.class.getName());
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f02MulNOUI.java b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f02MulNOUI.java
new file mode 100644
index 000000000..5180451a1
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f02MulNOUI.java
@@ -0,0 +1,275 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.math;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.common.os.Platform;
+import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestMatrix4f02MulNOUI extends JunitTracer {
+
+ final float[] m1_0 = new float[]{ 1, 3, 4, 0,
+ 6, 7, 8, 5,
+ 98, 7, 6, 9,
+ 54, 3, 2, 5 };
+ final Matrix4f m1 = new Matrix4f(m1_0);
+ final Matrix4fb n1 = new Matrix4fb(m1_0);
+
+
+ final float[] m2_0 = new float[]{ 1, 6, 98, 54,
+ 3, 7, 7, 3,
+ 4, 8, 6, 2,
+ 0, 5, 9, 5 };
+ final Matrix4f m2 = new Matrix4f(m2_0);
+ final Matrix4fb n2 = new Matrix4fb(m2_0);
+
+ final float[] m2xm1_0 =
+ new float[]{ 26, 59, 143, 71,
+ 59, 174, 730, 386,
+ 143, 730, 9770, 5370,
+ 71, 386, 5370, 2954 };
+ final Matrix4f m2xm1 = new Matrix4f(m2xm1_0);
+ final Matrix4fb n2xn1 = new Matrix4fb(m2xm1_0);
+
+ final float[] m1xm2_0 =
+ new float[]{12557, 893, 748, 1182,
+ 893, 116, 116, 113,
+ 748, 116, 120, 104,
+ 1182, 113, 104, 131 };
+ final Matrix4f m1xm2 = new Matrix4f(m1xm2_0);
+ final Matrix4fb n1xn2 = new Matrix4fb(m1xm2_0);
+
+ @Test
+ public void test01_mul(){
+ {
+ final float[] r_0 = new float[16];
+ FloatUtil.multMatrix(m1_0, 0, m2_0, 0, r_0, 0);
+ Assert.assertArrayEquals(m1xm2_0, r_0, 0f);
+
+ Assert.assertEquals(m1xm2, new Matrix4f(m1).mul(m2));
+ Assert.assertEquals(m1xm2, new Matrix4f().mul(m1, m2));
+
+ Assert.assertEquals(n1xn2, new Matrix4fb(n1).mul(n2));
+ Assert.assertEquals(n1xn2, new Matrix4fb().mul(n1, n2));
+ }
+ {
+ final float[] r_0 = new float[16];
+ FloatUtil.multMatrix(m2_0, 0, m1_0, 0, r_0, 0);
+ Assert.assertArrayEquals(m2xm1_0, r_0, 0f);
+
+ Assert.assertEquals(m2xm1, new Matrix4f(m2).mul(m1));
+ Assert.assertEquals(m2xm1, new Matrix4f().mul(m2, m1));
+
+ Assert.assertEquals(n2xn1, new Matrix4fb(n2).mul(n1));
+ Assert.assertEquals(n2xn1, new Matrix4fb().mul(n2, n1));
+ }
+ }
+
+ @Test
+ public void test05Perf01(){
+ final float[] res = new float[16];
+
+ final Matrix4f res_m = new Matrix4f();
+ final Matrix4fb res_n = new Matrix4fb();
+
+ final int warmups = 1000;
+ final int loops = 10*1000*1000;
+ long tI1 = 0;
+ long tI2 = 0;
+ long tI4a = 0;
+ long tI4b = 0;
+ long tI5a = 0;
+ long tI5b = 0;
+
+ // warm-up
+ for(int i=0; i Math.abs(temp[i4+i])) {
+ swap = j;
+ }
+ }
+
+ if (swap != i) {
+ final int swap4 = swap*4;
+ //
+ // Swap rows.
+ //
+ for (k = 0; k < 4; k++) {
+ t = temp[i4+k];
+ temp[i4+k] = temp[swap4+k];
+ temp[swap4+k] = t;
+
+ t = mres[i4+k+mres_offset];
+ mres[i4+k+mres_offset] = mres[swap4+k+mres_offset];
+ mres[swap4+k+mres_offset] = t;
+ }
+ }
+
+ if (temp[i4+i] == 0) {
+ //
+ // No non-zero pivot. The matrix is singular, which shouldn't
+ // happen. This means the user gave us a bad matrix.
+ //
+ return null;
+ }
+
+ t = temp[i4+i];
+ for (k = 0; k < 4; k++) {
+ temp[i4+k] /= t;
+ mres[i4+k+mres_offset] /= t;
+ }
+ for (j = 0; j < 4; j++) {
+ if (j != i) {
+ final int j4 = j*4;
+ t = temp[j4+i];
+ for (k = 0; k < 4; k++) {
+ temp[j4+k] -= temp[i4+k] * t;
+ mres[j4+k+mres_offset] -= mres[i4+k+mres_offset]*t;
+ }
+ }
+ }
+ }
+ return mres;
+ }
+
+ public static void main(final String args[]) {
+ org.junit.runner.JUnitCore.main(TestMatrix4f02MulNOUI.class.getName());
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f03InversionNOUI.java b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f03InversionNOUI.java
new file mode 100644
index 000000000..fee38bb54
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestMatrix4f03InversionNOUI.java
@@ -0,0 +1,403 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.test.junit.jogl.math;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.common.os.Platform;
+import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestMatrix4f03InversionNOUI extends JunitTracer {
+
+ @Test
+ public void test01Ident(){
+ final float[] res1 = new float[16];
+ final float[] res2 = new float[16];
+ final float[] temp = new float[16];
+
+ final float[] identity = new float[] { 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1 };
+
+ FloatUtil.invertMatrix(identity, 0, res1, 0);
+ System.err.println(FloatUtil.matrixToString(null, "inv-1: ", "%10.7f", res1, 0, 4, 4, false /* rowMajorOrder */));
+ invertMatrix(identity, 0, res2, 0, temp);
+ System.err.println(FloatUtil.matrixToString(null, "inv-2: ", "%10.7f", res2, 0, 4, 4, false /* rowMajorOrder */));
+
+ Assert.assertArrayEquals("I1/I2 failure", res1, res2, FloatUtil.INV_DEVIANCE);
+ Assert.assertArrayEquals("I2 failure", identity, res2, FloatUtil.INV_DEVIANCE);
+ Assert.assertArrayEquals("I1 failure", identity, res1, FloatUtil.INV_DEVIANCE);
+
+ final Matrix4f res3 = new Matrix4f(identity);
+ Assert.assertTrue( res3.invert() );
+ System.err.println(res3.toString(null, "inv-4: ", "%10.7f"));
+ Assert.assertEquals(new Matrix4f(res1), res3);
+ Assert.assertEquals(new Matrix4f(), res3);
+
+ final Matrix4fb res4 = new Matrix4fb(identity);
+ Assert.assertTrue( res4.invert() );
+ System.err.println(res4.toString(null, "inv-5: ", "%10.7f"));
+ Assert.assertEquals(new Matrix4fb(res1), res4);
+ Assert.assertEquals(new Matrix4fb(), res4);
+ }
+
+ private void testImpl(final float[] matrix) {
+ final float[] inv1_0 = new float[16];
+ final float[] inv1_1 = new float[16];
+ final float[] inv1_2 = new float[16];
+ final float[] inv2_0 = new float[16];
+ final float[] inv2_1 = new float[16];
+ final float[] inv2_2 = new float[16];
+ final float[] temp = new float[16];
+
+ System.err.println(FloatUtil.matrixToString(null, "orig : ", "%10.7f", matrix, 0, 4, 4, false /* rowMajorOrder */));
+ invertMatrix(matrix, 0, inv1_0, 0, temp);
+ invertMatrix(inv1_0, 0, inv2_0, 0, temp);
+ System.err.println(FloatUtil.matrixToString(null, "inv1_0: ", "%10.7f", inv1_0, 0, 4, 4, false /* rowMajorOrder */));
+ System.err.println(FloatUtil.matrixToString(null, "inv2_0: ", "%10.7f", inv2_0, 0, 4, 4, false /* rowMajorOrder */));
+ FloatUtil.invertMatrix(matrix, 0, inv1_1, 0);
+ FloatUtil.invertMatrix(inv1_1, 0, inv2_1, 0);
+ System.err.println(FloatUtil.matrixToString(null, "inv1_1: ", "%10.7f", inv1_1, 0, 4, 4, false /* rowMajorOrder */));
+ System.err.println(FloatUtil.matrixToString(null, "inv2_1: ", "%10.7f", inv2_1, 0, 4, 4, false /* rowMajorOrder */));
+ FloatUtil.invertMatrix(matrix, inv1_2);
+ FloatUtil.invertMatrix(inv1_2, inv2_2);
+ System.err.println(FloatUtil.matrixToString(null, "inv1_2: ", "%10.7f", inv1_2, 0, 4, 4, false /* rowMajorOrder */));
+ System.err.println(FloatUtil.matrixToString(null, "inv2_2: ", "%10.7f", inv2_2, 0, 4, 4, false /* rowMajorOrder */));
+
+ Assert.assertArrayEquals("I1_1/I1_2 failure", inv1_1, inv1_2, FloatUtil.INV_DEVIANCE);
+ Assert.assertArrayEquals("I2_1/I2_2 failure", inv2_1, inv2_2, FloatUtil.INV_DEVIANCE);
+
+ Assert.assertArrayEquals("I1_0/I1_1 failure", inv1_0, inv1_2, FloatUtil.INV_DEVIANCE);
+ Assert.assertArrayEquals("I2_0/I2_1 failure", inv2_0, inv2_2, FloatUtil.INV_DEVIANCE);
+
+ Assert.assertArrayEquals("I1 failure", matrix, inv2_0, FloatUtil.INV_DEVIANCE);
+ Assert.assertArrayEquals("I2 failure", matrix, inv2_2, FloatUtil.INV_DEVIANCE);
+ Assert.assertArrayEquals("I2 failure", matrix, inv2_1, FloatUtil.INV_DEVIANCE);
+
+ final Matrix4f matrix_m = new Matrix4f(matrix);
+ final Matrix4f inv1_4a = new Matrix4f(matrix_m);
+ Assert.assertTrue( inv1_4a.invert() );
+ final Matrix4f inv2_4a = new Matrix4f(inv1_4a);
+ Assert.assertTrue( inv2_4a.invert() );
+ System.err.println(inv1_4a.toString(null, "inv1_4a: ", "%10.7f"));
+ System.err.println(inv2_4a.toString(null, "inv2_4a: ", "%10.7f"));
+
+ Assert.assertEquals(new Matrix4f(inv1_2), inv1_4a);
+ Assert.assertEquals(new Matrix4f(inv2_2), inv2_4a);
+ Assert.assertTrue("I4 failure: "+matrix_m+" != "+inv2_4a, matrix_m.isEqual(inv2_4a, FloatUtil.INV_DEVIANCE));
+
+ final Matrix4f inv1_4b = new Matrix4f();
+ Assert.assertTrue( inv1_4b.invert(matrix_m) );
+ final Matrix4f inv2_4b = new Matrix4f();
+ Assert.assertTrue( inv2_4b.invert(inv1_4b) );
+ System.err.println(inv1_4b.toString(null, "inv1_4b: ", "%10.7f"));
+ System.err.println(inv2_4b.toString(null, "inv2_4b: ", "%10.7f"));
+
+ Assert.assertEquals(new Matrix4f(inv1_2), inv1_4b);
+ Assert.assertEquals(new Matrix4f(inv2_2), inv2_4b);
+ Assert.assertTrue("I4 failure: "+matrix_m+" != "+inv2_4b, matrix_m.isEqual(inv2_4b, FloatUtil.INV_DEVIANCE));
+
+ //
+ //
+
+ final Matrix4fb matrix_n = new Matrix4fb(matrix);
+ final Matrix4fb inv1_5a = new Matrix4fb(matrix_n);
+ Assert.assertTrue( inv1_5a.invert() );
+ final Matrix4fb inv2_5a = new Matrix4fb(inv1_5a);
+ Assert.assertTrue( inv2_5a.invert() );
+ System.err.println(inv1_5a.toString(null, "inv1_5a: ", "%10.7f"));
+ System.err.println(inv2_5a.toString(null, "inv2_5a: ", "%10.7f"));
+
+ Assert.assertEquals(new Matrix4fb(inv1_2), inv1_5a);
+ Assert.assertEquals(new Matrix4fb(inv2_2), inv2_5a);
+ Assert.assertTrue("I5 failure: "+matrix_n+" != "+inv2_5a, matrix_n.isEqual(inv2_5a, FloatUtil.INV_DEVIANCE));
+
+ final Matrix4fb inv1_5b = new Matrix4fb();
+ Assert.assertTrue( inv1_5b.invert(matrix_n) );
+ final Matrix4fb inv2_5b = new Matrix4fb();
+ Assert.assertTrue( inv2_5b.invert(inv1_5b) );
+ System.err.println(inv1_5b.toString(null, "inv1_5b: ", "%10.7f"));
+ System.err.println(inv2_5b.toString(null, "inv2_5b: ", "%10.7f"));
+
+ Assert.assertEquals(new Matrix4fb(inv1_2), inv1_5b);
+ Assert.assertEquals(new Matrix4fb(inv2_2), inv2_5b);
+ Assert.assertTrue("I5 failure: "+matrix_n+" != "+inv2_5b, matrix_n.isEqual(inv2_5b, FloatUtil.INV_DEVIANCE));
+ }
+
+ @Test
+ public void test02(){
+ final float[] p = new float[] { 2.3464675f, 0, 0, 0,
+ 0, 2.4142134f, 0, 0,
+ 0, 0, -1.0002f, -1,
+ 0, 0, -20.002f, 0 };
+ testImpl(p);
+ }
+
+ @Test
+ public void test03(){
+ final float[] mv = new float[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, -200, 1 } ;
+ testImpl(mv);
+ }
+
+ @Test
+ public void test04(){
+ final float[] p = new float[] {
+ 2.3464675f, 0, 0, 0,
+ 0, 2.4142134f, 0, 0,
+ 0, 0, -1.0002f, -1,
+ 0, 0, -20.002f, 0 };
+
+ testImpl(p);
+ }
+
+ @Test
+ public void test05Perf01(){
+ final float[] p1 = new float[] {
+ 2.3464675f, 0, 0, 0,
+ 0, 2.4142134f, 0, 0,
+ 0, 0, -1.0002f, -1,
+ 0, 0, -20.002f, 0 };
+ final Matrix4f p1_m = new Matrix4f(p1);
+ final Matrix4fb p1_n = new Matrix4fb(p1);
+
+ final float[] p2 = new float[]{
+ 26, 59, 143, 71,
+ 59, 174, 730, 386,
+ 143, 730, 9770, 5370,
+ 71, 386, 5370, 2954 };
+ final Matrix4f p2_m = new Matrix4f(p2);
+ final Matrix4fb p2_n = new Matrix4fb(p2);
+
+ final float[] res = new float[16];
+ final float[] temp = new float[16];
+
+ final Matrix4f res_m = new Matrix4f();
+ final Matrix4fb res_n = new Matrix4fb();
+
+ final int warmups = 1000;
+ final int loops = 10*1000*1000;
+ long tI0 = 0;
+ long tI1 = 0;
+ long tI2 = 0;
+ long tI4a = 0;
+ long tI4b = 0;
+ long tI5a = 0;
+ long tI5b = 0;
+
+ // warm-up
+ for(int i=0; i res
+ invertMatrix(p1, 0, res, 0, temp);
+
+ // I0: p2 -> res
+ invertMatrix(p2, 0, res, 0, temp);
+ }
+ tI0 = Platform.currentTimeMillis() - t_0;
+
+ // warm-up
+ for(int i=0; i res
+ FloatUtil.invertMatrix(p1, 0, res, 0);
+
+ // I1: p2 -> res
+ FloatUtil.invertMatrix(p2, 0, res, 0);
+ }
+ tI1 = Platform.currentTimeMillis() - t_0;
+
+ // warm-up
+ for(int i=0; i res
+ FloatUtil.invertMatrix(p1, res);
+
+ // I2: p2 -> res
+ FloatUtil.invertMatrix(p2, res);
+ }
+ tI2 = Platform.currentTimeMillis() - t_0;
+
+ //
+ // Matrix4f
+ //
+
+ // warm-up
+ for(int i=0; i Math.abs(temp[i4+i])) {
+ swap = j;
+ }
+ }
+
+ if (swap != i) {
+ final int swap4 = swap*4;
+ //
+ // Swap rows.
+ //
+ for (k = 0; k < 4; k++) {
+ t = temp[i4+k];
+ temp[i4+k] = temp[swap4+k];
+ temp[swap4+k] = t;
+
+ t = mres[i4+k+mres_offset];
+ mres[i4+k+mres_offset] = mres[swap4+k+mres_offset];
+ mres[swap4+k+mres_offset] = t;
+ }
+ }
+
+ if (temp[i4+i] == 0) {
+ //
+ // No non-zero pivot. The matrix is singular, which shouldn't
+ // happen. This means the user gave us a bad matrix.
+ //
+ return null;
+ }
+
+ t = temp[i4+i];
+ for (k = 0; k < 4; k++) {
+ temp[i4+k] /= t;
+ mres[i4+k+mres_offset] /= t;
+ }
+ for (j = 0; j < 4; j++) {
+ if (j != i) {
+ final int j4 = j*4;
+ t = temp[j4+i];
+ for (k = 0; k < 4; k++) {
+ temp[j4+k] -= temp[i4+k] * t;
+ mres[j4+k+mres_offset] -= mres[i4+k+mres_offset]*t;
+ }
+ }
+ }
+ }
+ return mres;
+ }
+
+ public static void main(final String args[]) {
+ org.junit.runner.JUnitCore.main(TestMatrix4f03InversionNOUI.class.getName());
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestPMVMatrix03NOUI.java b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestPMVMatrix03NOUI.java
index 63cb5b539..9468afbd2 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestPMVMatrix03NOUI.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestPMVMatrix03NOUI.java
@@ -44,12 +44,12 @@ public class TestPMVMatrix03NOUI extends JunitTracer {
m.gluProject(1f, 0f, 0f, viewport, 0, winA00, 0);
System.err.println("A.0.0 - Project 1,0 -->" + Arrays.toString(winA00));
- FloatUtil.mapObjToWinCoords(1f, 0f, 0f, mat4PMv, viewport, 0, winB00, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(1f, 0f, 0f, mat4PMv, viewport, winB00, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.0 - Project 1,0 -->" + Arrays.toString(winB00));
m.gluProject(0f, 0f, 0f, viewport, 0, winA01, 0);
System.err.println("A.0.1 - Project 0,0 -->" + Arrays.toString(winA01));
- FloatUtil.mapObjToWinCoords(0f, 0f, 0f, mat4PMv, viewport, 0, winB01, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(0f, 0f, 0f, mat4PMv, viewport, winB01, vec4Tmp1, vec4Tmp2);
System.err.println("B.0.1 - Project 0,0 -->" + Arrays.toString(winB01));
m.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
@@ -61,12 +61,12 @@ public class TestPMVMatrix03NOUI extends JunitTracer {
m.gluProject(1f, 0f, 0f, viewport, 0, winA10, 0);
System.err.println("A.1.0 - Project 1,0 -->" +Arrays.toString(winA10));
- FloatUtil.mapObjToWinCoords(1f, 0f, 0f, mat4PMv, viewport, 0, winB10, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(1f, 0f, 0f, mat4PMv, viewport, winB10, vec4Tmp1, vec4Tmp2);
System.err.println("B.1.0 - Project 1,0 -->" +Arrays.toString(winB10));
m.gluProject(0f, 0f, 0f, viewport, 0, winA11, 0);
System.err.println("A.1.1 - Project 0,0 -->" +Arrays.toString(winA11));
- FloatUtil.mapObjToWinCoords(0f, 0f, 0f, mat4PMv, viewport, 0, winB11, 0, vec4Tmp1, vec4Tmp2);
+ FloatUtil.mapObjToWin(0f, 0f, 0f, mat4PMv, viewport, winB11, vec4Tmp1, vec4Tmp2);
System.err.println("B.1.1 - Project 0,0 -->" +Arrays.toString(winB11));
Assert.assertArrayEquals("A/B 0.0 Project 1,0 failure", winB00, winA00, epsilon);
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestQuaternion01NOUI.java b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestQuaternion01NOUI.java
index 80d2e088f..ecda4778d 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/math/TestQuaternion01NOUI.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/math/TestQuaternion01NOUI.java
@@ -37,7 +37,10 @@ import org.junit.runners.MethodSorters;
import com.jogamp.junit.util.JunitTracer;
import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Matrix4f;
import com.jogamp.opengl.math.Quaternion;
+import com.jogamp.opengl.math.Vec3f;
+import com.jogamp.opengl.math.Vec4f;
import com.jogamp.opengl.math.VectorUtil;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -46,20 +49,20 @@ public class TestQuaternion01NOUI extends JunitTracer {
static final Quaternion QUAT_IDENT = new Quaternion(0f, 0f, 0f, 1f);
- static final float[] ZERO = new float[] { 0f, 0f, 0f };
- static final float[] ONE = new float[] { 1f, 1f, 1f };
- static final float[] NEG_ONE = new float[] { -1f, -1f, -1f };
- static final float[] UNIT_X = new float[] { 1f, 0f, 0f };
- static final float[] UNIT_Y = new float[] { 0f, 1f, 0f };
- static final float[] UNIT_Z = new float[] { 0f, 0f, 1f };
- static final float[] NEG_UNIT_X = new float[] { -1f, 0f, 0f };
- static final float[] NEG_UNIT_Y = new float[] { 0f, -1f, 0f };
- static final float[] NEG_UNIT_Z = new float[] { 0f, 0f, -1f };
+ static final Vec3f ZERO = new Vec3f ( 0f, 0f, 0f );
+ static final Vec3f ONE = new Vec3f ( 1f, 1f, 1f );
+ static final Vec3f NEG_ONE = new Vec3f ( -1f, -1f, -1f );
+ static final Vec3f UNIT_X = new Vec3f ( 1f, 0f, 0f );
+ static final Vec3f UNIT_Y = new Vec3f ( 0f, 1f, 0f );
+ static final Vec3f UNIT_Z = new Vec3f ( 0f, 0f, 1f );
+ static final Vec3f NEG_UNIT_X = new Vec3f ( -1f, 0f, 0f );
+ static final Vec3f NEG_UNIT_Y = new Vec3f ( 0f, -1f, 0f );
+ static final Vec3f NEG_UNIT_Z = new Vec3f ( 0f, 0f, -1f );
- static final float[] NEG_ONE_v4 = new float[] { -1f, -1f, -1f, 0f };
- static final float[] ONE_v4 = new float[] { 1f, 1f, 1f, 0f };
+ static final Vec4f NEG_ONE_v4 = new Vec4f ( -1f, -1f, -1f, 0f );
+ static final Vec4f ONE_v4 = new Vec4f ( 1f, 1f, 1f, 0f );
- static final float MACH_EPSILON = FloatUtil.getMachineEpsilon();
+ static final float MACH_EPSILON = FloatUtil.EPSILON;
//
// Basic
@@ -76,8 +79,9 @@ public class TestQuaternion01NOUI extends JunitTracer {
@Test
public void test02RotateZeroVector() {
final Quaternion quat = new Quaternion();
- final float[] rotVec0 = quat.rotateVector(new float[3], 0, ZERO, 0);
- Assert.assertArrayEquals(ZERO, rotVec0, FloatUtil.EPSILON);
+ final Vec3f ZERO = new Vec3f(0, 0, 0);
+ final Vec3f rotVec0 = quat.rotateVector(ZERO, new Vec3f());
+ Assert.assertEquals(ZERO, rotVec0);
}
@Test
@@ -110,24 +114,24 @@ public class TestQuaternion01NOUI extends JunitTracer {
@Test
public void test10AngleAxis() {
- final float[] tmpV3f = new float[3];
- final Quaternion quat1 = new Quaternion().setFromAngleAxis(FloatUtil.HALF_PI, new float[] { 2, 0, 0 }, tmpV3f );
- final Quaternion quat2 = new Quaternion().setFromAngleNormalAxis(FloatUtil.HALF_PI, new float[] { 1, 0, 0 } );
+ final Vec3f tmpV3f = new Vec3f();
+ final Quaternion quat1 = new Quaternion().setFromAngleAxis(FloatUtil.HALF_PI, new Vec3f ( 2, 0, 0 ), tmpV3f );
+ final Quaternion quat2 = new Quaternion().setFromAngleNormalAxis(FloatUtil.HALF_PI, new Vec3f ( 1, 0, 0 ) );
Assert.assertEquals(quat2, quat1);
// System.err.println("M "+quat2.magnitude()+", 1-M "+(1f-quat2.magnitude())+", Eps "+FloatUtil.EPSILON);
Assert.assertEquals(0f, 1 - quat2.magnitude(), FloatUtil.EPSILON);
Assert.assertTrue(1 - quat1.magnitude() <= FloatUtil.EPSILON);
- final float[] vecOut1 = new float[3];
- final float[] vecOut2 = new float[3];
- quat1.rotateVector(vecOut1, 0, ONE, 0);
- quat2.rotateVector(vecOut2, 0, ONE, 0);
- Assert.assertArrayEquals(vecOut1, vecOut2, FloatUtil.EPSILON);
- Assert.assertEquals(0f, Math.abs( VectorUtil.distVec3(vecOut1, vecOut2) ), FloatUtil.EPSILON );
+ final Vec3f vecOut1 = new Vec3f();
+ final Vec3f vecOut2 = new Vec3f();
+ quat1.rotateVector(Vec3f.ONE, vecOut1);
+ quat2.rotateVector(Vec3f.ONE, vecOut2);
+ Assert.assertEquals(vecOut1, vecOut2);
+ Assert.assertEquals(0f, Math.abs( vecOut1.dist(vecOut2) ), FloatUtil.EPSILON );
- quat1.rotateVector(vecOut1, 0, UNIT_Z, 0);
- Assert.assertEquals(0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_Y, vecOut1) ), FloatUtil.EPSILON );
+ quat1.rotateVector(Vec3f.UNIT_Z, vecOut1);
+ Assert.assertEquals(0f, Math.abs( Vec3f.UNIT_Y_NEG.dist(vecOut1) ), FloatUtil.EPSILON );
quat2.setFromAngleAxis(FloatUtil.HALF_PI, ZERO, tmpV3f);
Assert.assertEquals(QUAT_IDENT, quat2);
@@ -139,14 +143,14 @@ public class TestQuaternion01NOUI extends JunitTracer {
quat1.set(0, 0, 0, 0);
angle = quat1.toAngleAxis(vecOut1);
Assert.assertTrue(0.0f == angle);
- Assert.assertArrayEquals(UNIT_X, vecOut1, FloatUtil.EPSILON);
+ Assert.assertEquals(UNIT_X, vecOut1);
}
@Test
public void test11FromVectorToVector() {
- final float[] tmp0V3f = new float[3];
- final float[] tmp1V3f = new float[3];
- final float[] vecOut = new float[3];
+ final Vec3f tmp0V3f = new Vec3f();
+ final Vec3f tmp1V3f = new Vec3f();
+ final Vec3f vecOut = new Vec3f();
final Quaternion quat = new Quaternion();
quat.setFromVectors(UNIT_Z, UNIT_X, tmp0V3f, tmp1V3f);
@@ -158,21 +162,21 @@ public class TestQuaternion01NOUI extends JunitTracer {
Assert.assertEquals(quat2, quat);
quat.setFromVectors(UNIT_Z, NEG_UNIT_Z, tmp0V3f, tmp1V3f);
- quat.rotateVector(vecOut, 0, UNIT_Z, 0);
+ quat.rotateVector(UNIT_Z, vecOut);
// System.err.println("vecOut: "+Arrays.toString(vecOut));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_Z, vecOut) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals( 0f, Math.abs( NEG_UNIT_Z.dist(vecOut) ), Quaternion.ALLOWED_DEVIANCE );
quat.setFromVectors(UNIT_X, NEG_UNIT_X, tmp0V3f, tmp1V3f);
- quat.rotateVector(vecOut, 0, UNIT_X, 0);
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_X, vecOut) ), Quaternion.ALLOWED_DEVIANCE );
+ quat.rotateVector(UNIT_X, vecOut);
+ Assert.assertEquals( 0f, Math.abs( NEG_UNIT_X.dist(vecOut) ), Quaternion.ALLOWED_DEVIANCE );
quat.setFromVectors(UNIT_Y, NEG_UNIT_Y, tmp0V3f, tmp1V3f);
- quat.rotateVector(vecOut, 0, UNIT_Y, 0);
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_Y, vecOut) ), Quaternion.ALLOWED_DEVIANCE );
+ quat.rotateVector(UNIT_Y, vecOut);
+ Assert.assertEquals( 0f, Math.abs( NEG_UNIT_Y.dist(vecOut) ), Quaternion.ALLOWED_DEVIANCE );
quat.setFromVectors(ONE, NEG_ONE, tmp0V3f, tmp1V3f);
- quat.rotateVector(vecOut, 0, ONE, 0);
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_ONE, vecOut) ), Quaternion.ALLOWED_DEVIANCE );
+ quat.rotateVector(ONE, vecOut);
+ Assert.assertEquals( 0f, Math.abs( NEG_ONE.dist(vecOut) ), Quaternion.ALLOWED_DEVIANCE );
quat.setFromVectors(ZERO, ZERO, tmp0V3f, tmp1V3f);
Assert.assertEquals(QUAT_IDENT, quat);
@@ -182,14 +186,14 @@ public class TestQuaternion01NOUI extends JunitTracer {
public void test12FromAndToEulerAngles() {
// Y.Z.X -> X.Y.Z
final Quaternion quat = new Quaternion();
- final float[] angles0Exp = new float[] { 0f, FloatUtil.HALF_PI, 0f};
+ final Vec3f angles0Exp = new Vec3f( 0f, FloatUtil.HALF_PI, 0f );
quat.setFromEuler(angles0Exp);
Assert.assertEquals(1.0f, quat.magnitude(), FloatUtil.EPSILON);
- final float[] angles0Has = quat.toEuler(new float[3]);
+ final Vec3f angles0Has = quat.toEuler(new Vec3f());
// System.err.println("exp0 "+Arrays.toString(angles0Exp));
// System.err.println("has0 "+Arrays.toString(angles0Has));
- Assert.assertArrayEquals(angles0Exp, angles0Has, FloatUtil.EPSILON);
+ Assert.assertEquals(angles0Exp, angles0Has);
final Quaternion quat2 = new Quaternion();
quat2.setFromEuler(angles0Has);
@@ -197,28 +201,28 @@ public class TestQuaternion01NOUI extends JunitTracer {
///
- final float[] angles1Exp = new float[] { 0f, 0f, -FloatUtil.HALF_PI };
+ final Vec3f angles1Exp = new Vec3f(0f, 0f, -FloatUtil.HALF_PI);
quat.setFromEuler(angles1Exp);
Assert.assertEquals(1.0f, quat.magnitude(), FloatUtil.EPSILON);
- final float[] angles1Has = quat.toEuler(new float[3]);
+ final Vec3f angles1Has = quat.toEuler(new Vec3f());
// System.err.println("exp1 "+Arrays.toString(angles1Exp));
// System.err.println("has1 "+Arrays.toString(angles1Has));
- Assert.assertArrayEquals(angles1Exp, angles1Has, FloatUtil.EPSILON);
+ Assert.assertEquals(angles1Exp, angles1Has);
quat2.setFromEuler(angles1Has);
Assert.assertEquals(quat, quat2);
///
- final float[] angles2Exp = new float[] { FloatUtil.HALF_PI, 0f, 0f };
+ final Vec3f angles2Exp = new Vec3f(FloatUtil.HALF_PI, 0f, 0f);
quat.setFromEuler(angles2Exp);
Assert.assertEquals(1.0f, quat.magnitude(), FloatUtil.EPSILON);
- final float[] angles2Has = quat.toEuler(new float[3]);
+ final Vec3f angles2Has = quat.toEuler(new Vec3f());
// System.err.println("exp2 "+Arrays.toString(angles2Exp));
// System.err.println("has2 "+Arrays.toString(angles2Has));
- Assert.assertArrayEquals(angles2Exp, angles2Has, FloatUtil.EPSILON);
+ Assert.assertEquals(angles2Exp, angles2Has);
quat2.setFromEuler(angles2Has);
Assert.assertEquals(quat, quat2);
@@ -230,233 +234,307 @@ public class TestQuaternion01NOUI extends JunitTracer {
quat.setFromEuler(0, FloatUtil.HALF_PI, 0); // 90 degrees y-axis
Assert.assertEquals(1.0f, quat.magnitude(), FloatUtil.EPSILON);
- final float[] v2 = quat.rotateVector(new float[3], 0, UNIT_X, 0);
- Assert.assertEquals(0f, Math.abs(VectorUtil.distVec3(NEG_UNIT_Z, v2)), FloatUtil.EPSILON);
+ final Vec3f v2 = quat.rotateVector(UNIT_X, new Vec3f());
+ Assert.assertEquals(0f, Math.abs( NEG_UNIT_Z.dist(v2)), FloatUtil.EPSILON);
quat.setFromEuler(0, 0, -FloatUtil.HALF_PI);
Assert.assertEquals(1.0f, quat.magnitude(), FloatUtil.EPSILON);
- quat.rotateVector(v2, 0, UNIT_X, 0);
- Assert.assertEquals(0f, Math.abs(VectorUtil.distVec3(NEG_UNIT_Y, v2)), FloatUtil.EPSILON);
+ quat.rotateVector(UNIT_X, v2);
+ Assert.assertEquals(0f, Math.abs( NEG_UNIT_Y.dist(v2)), FloatUtil.EPSILON);
quat.setFromEuler(FloatUtil.HALF_PI, 0, 0);
Assert.assertEquals(1.0f, quat.magnitude(), FloatUtil.EPSILON);
- quat.rotateVector(v2, 0, UNIT_Y, 0);
- Assert.assertEquals(0f, Math.abs(VectorUtil.distVec3(UNIT_Z, v2)), FloatUtil.EPSILON);
+ quat.rotateVector(UNIT_Y, v2);
+ Assert.assertEquals(0f, Math.abs( UNIT_Z.dist(v2)), FloatUtil.EPSILON);
}
@Test
public void test14Matrix() {
- final float[] vecHas = new float[3];
- final float[] vecOut2 = new float[4];
- float[] mat1 = new float[4*4];
- final float[] mat2 = new float[4*4];
+ final Vec3f vecHas = new Vec3f();
+ final Vec3f vecOut3 = new Vec3f();
+ final Vec4f vecOut4 = new Vec4f();
+ final Matrix4f mat1 = new Matrix4f();;
+ final Matrix4f mat2 = new Matrix4f();
final Quaternion quat = new Quaternion();
//
// IDENTITY CHECK
//
- FloatUtil.makeIdentity(mat1);
+ mat1.loadIdentity();
quat.set(0, 0, 0, 0);
- quat.toMatrix(mat2, 0);
- Assert.assertArrayEquals(mat1, mat2, FloatUtil.EPSILON);
+ quat.toMatrix(mat2);
+ Assert.assertEquals(mat1, mat2);
//
// 90 degrees rotation on X
//
float a = FloatUtil.HALF_PI;
- mat1 = new float[] { // Column Order
- 1, 0, 0, 0, //
- 0, FloatUtil.cos(a), FloatUtil.sin(a), 0, //
- 0, -FloatUtil.sin(a), FloatUtil.cos(a), 0,
- 0, 0, 0, 1 };
+ final float[] mat1_0 = new float[] { // Column Order
+ 1, 0, 0, 0, //
+ 0, FloatUtil.cos(a), FloatUtil.sin(a), 0, //
+ 0, -FloatUtil.sin(a), FloatUtil.cos(a), 0,
+ 0, 0, 0, 1 };
+ mat1.load( mat1_0 );
+ {
+ // Matrix4f load() <-> toFloats()
+ final float[] mat2_0 = new float[16];
+ mat1.get(mat2_0);
+ Assert.assertArrayEquals(mat1_0, mat2_0, FloatUtil.EPSILON);
+ }
{
// Validate Matrix via Euler rotation on Quaternion!
quat.setFromEuler(a, 0f, 0f);
- quat.toMatrix(mat2, 0);
- // System.err.println(FloatUtil.matrixToString(null, "quat-rot", "%10.5f", mat1, 0, mat2, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(mat1, mat2, FloatUtil.EPSILON);
- quat.rotateVector(vecHas, 0, UNIT_Y, 0);
+ {
+ // quat.toMatrix(float[])
+ final float[] mat2_0 = new float[16];
+ quat.toMatrix(mat2_0, 0);
+ Assert.assertArrayEquals(mat1_0, mat2_0, FloatUtil.EPSILON);
+ }
+ {
+ // quat.toMatrix(float[]) and Matrix4f.load()
+ final float[] mat2_0 = new float[16];
+ quat.toMatrix(mat2_0, 0);
+ Assert.assertArrayEquals(mat1_0, mat2_0, FloatUtil.EPSILON);
+ mat2.load(mat2_0);
+ Assert.assertEquals(mat1, mat2);
+ }
+ {
+ // Quaternion.toMatrix(Matrix4f)
+ quat.toMatrix(mat2);
+ // System.err.println(FloatUtil.matrixToString(null, "quat-rot", "%10.5f", mat1, 0, mat2, 0, 4, 4, false).toString());
+ Assert.assertEquals(mat1, mat2);
+ }
+ quat.rotateVector(UNIT_Y, vecHas);
// System.err.println("exp0 "+Arrays.toString(NEG_UNIT_X));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(UNIT_Z, vecHas) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals( 0f, Math.abs( UNIT_Z.dist(vecHas) ), Quaternion.ALLOWED_DEVIANCE );
}
- quat.setFromMatrix(mat1, 0);
- quat.rotateVector(vecHas, 0, UNIT_Y, 0);
+ mat1.getRotation(quat);
+ quat.setFromMatrix(mat1);
+ quat.rotateVector(UNIT_Y, vecHas);
// System.err.println("exp0 "+Arrays.toString(UNIT_Z));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(UNIT_Z, vecHas) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals( 0f, Math.abs( UNIT_Z.dist(vecHas) ), Quaternion.ALLOWED_DEVIANCE );
- quat.toMatrix(mat2, 0);
+ quat.toMatrix(mat2);
// System.err.println(FloatUtil.matrixToString(null, null, "%10.5f", mat1, 0, mat2, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(mat1, mat2, FloatUtil.EPSILON);
+ Assert.assertEquals(mat1, mat2);
- quat.rotateVector(vecHas, 0, NEG_ONE, 0);
- FloatUtil.multMatrixVec(mat2, NEG_ONE_v4, vecOut2);
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(vecHas, vecOut2) ), Quaternion.ALLOWED_DEVIANCE );
+ quat.rotateVector(NEG_ONE, vecHas);
+ {
+ // 1st use float[] math
+ final float[] vecHas_0 = new float[3];
+ vecHas.get(vecHas_0);
+ final float[] mat2_0 = new float[16];
+ quat.toMatrix(mat2_0, 0);
+ final float[] NEG_ONE_0 = new float[3];
+ NEG_ONE.get(NEG_ONE_0);
+ final float[] vecOut3_0 = new float[3];
+ FloatUtil.multMatrixVec3(mat2_0, NEG_ONE_0, vecOut3_0);
+ Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(vecHas_0, vecOut3_0) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertArrayEquals(vecHas_0, vecOut3_0, FloatUtil.EPSILON);
+
+ // 2nd use Vec3f math
+ mat2.mulVec3f(NEG_ONE, vecOut3);
+ Assert.assertEquals( 0f, Math.abs( vecHas.dist(vecOut3) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals(vecHas, vecOut3);
+
+ // 3rd compare both
+ final float[] vecOut3_1 = new float[3];
+ vecOut3.get(vecOut3_1);
+ Assert.assertArrayEquals(vecOut3_0, vecOut3_1, FloatUtil.EPSILON);
+ }
+ {
+ // 1st use float[] math
+ final float[] vecHas_0 = new float[4];
+ vecHas.get(vecHas_0); // w is 0
+ final float[] mat2_0 = new float[16];
+ quat.toMatrix(mat2_0, 0);
+ final float[] NEG_ONE_v4_0 = new float[4];
+ NEG_ONE_v4.get(NEG_ONE_v4_0);
+ final float[] vecOut4_0 = new float[4];
+ FloatUtil.multMatrixVec(mat2_0, NEG_ONE_v4_0, vecOut4_0);
+ Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(vecHas_0, vecOut4_0) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertArrayEquals(vecHas_0, vecOut4_0, FloatUtil.EPSILON);
+
+ // 2nd use Vec4f math
+ mat2.mulVec4f(NEG_ONE_v4, vecOut4);
+ vecOut3.set(vecOut4);
+ Assert.assertEquals( 0f, Math.abs( vecHas.dist(vecOut3) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals(vecHas, vecOut3);
+
+ // 3rd compare both
+ final float[] vecOut4_1 = new float[4];
+ vecOut4.get(vecOut4_1);
+ Assert.assertArrayEquals(vecOut4_0, vecOut4_1, FloatUtil.EPSILON);
+ }
//
// 180 degrees rotation on X
//
a = FloatUtil.PI;
- mat1 = new float[] { // Column Order
+ mat1.load( new float[] { // Column Order
1, 0, 0, 0, //
0, FloatUtil.cos(a), FloatUtil.sin(a), 0, //
0, -FloatUtil.sin(a), FloatUtil.cos(a), 0,
- 0, 0, 0, 1 };
+ 0, 0, 0, 1 } );
{
// Validate Matrix via Euler rotation on Quaternion!
quat.setFromEuler(a, 0f, 0f);
- quat.toMatrix(mat2, 0);
+ quat.toMatrix(mat2);
// System.err.println(FloatUtil.matrixToString(null, "quat-rot", "%10.5f", mat1, 0, mat2, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(mat1, mat2, FloatUtil.EPSILON);
- quat.rotateVector(vecHas, 0, UNIT_Y, 0);
+ Assert.assertEquals(mat1, mat2);
+ quat.rotateVector(UNIT_Y, vecHas);
// System.err.println("exp0 "+Arrays.toString(NEG_UNIT_X));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_Y, vecHas) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals( 0f, Math.abs( NEG_UNIT_Y.dist(vecHas) ), Quaternion.ALLOWED_DEVIANCE );
}
- quat.setFromMatrix(mat1, 0);
- quat.rotateVector(vecHas, 0, UNIT_Y, 0);
+ quat.setFromMatrix(mat1);
+ quat.rotateVector(UNIT_Y, vecHas);
// System.err.println("exp0 "+Arrays.toString(NEG_UNIT_Y));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_Y, vecHas) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals( 0f, Math.abs( NEG_UNIT_Y.dist(vecHas) ), Quaternion.ALLOWED_DEVIANCE );
- quat.toMatrix(mat2, 0);
+ quat.toMatrix(mat2);
// System.err.println(FloatUtil.matrixToString(null, null, "%10.5f", mat1, 0, mat2, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(mat1, mat2, FloatUtil.EPSILON);
+ Assert.assertEquals(mat1, mat2);
- quat.rotateVector(vecHas, 0, ONE, 0);
- FloatUtil.multMatrixVec(mat2, ONE_v4, vecOut2);
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(vecHas, vecOut2) ), Quaternion.ALLOWED_DEVIANCE );
+ quat.rotateVector(ONE, vecHas);
+ mat2.mulVec4f(ONE_v4, vecOut4);
+ vecOut3.set(vecOut4);
+ Assert.assertEquals( 0f, Math.abs( vecHas.dist(vecOut3) ), Quaternion.ALLOWED_DEVIANCE );
//
// 180 degrees rotation on Y
//
a = FloatUtil.PI;
- mat1 = new float[] { // Column Order
+ mat1.load( new float[] { // Column Order
FloatUtil.cos(a), 0, -FloatUtil.sin(a), 0, //
0, 1, 0, 0, //
FloatUtil.sin(a), 0, FloatUtil.cos(a), 0,
- 0, 0, 0, 1 };
+ 0, 0, 0, 1 } );
{
// Validate Matrix via Euler rotation on Quaternion!
quat.setFromEuler(0f, a, 0f);
- quat.toMatrix(mat2, 0);
+ quat.toMatrix(mat2);
// System.err.println(FloatUtil.matrixToString(null, "quat-rot", "%10.5f", mat1, 0, mat2, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(mat1, mat2, FloatUtil.EPSILON);
- quat.rotateVector(vecHas, 0, UNIT_X, 0);
+ Assert.assertEquals(mat1, mat2);
+ quat.rotateVector(UNIT_X, vecHas);
// System.err.println("exp0 "+Arrays.toString(NEG_UNIT_X));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_X, vecHas) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals( 0f, Math.abs( NEG_UNIT_X.dist(vecHas) ), Quaternion.ALLOWED_DEVIANCE );
}
- quat.setFromMatrix(mat1, 0);
- quat.rotateVector(vecHas, 0, UNIT_X, 0);
+ quat.setFromMatrix(mat1);
+ quat.rotateVector(UNIT_X, vecHas);
// System.err.println("exp0 "+Arrays.toString(NEG_UNIT_X));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_X, vecHas) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals( 0f, Math.abs( NEG_UNIT_X.dist(vecHas) ), Quaternion.ALLOWED_DEVIANCE );
- quat.toMatrix(mat2, 0);
+ quat.toMatrix(mat2);
// System.err.println(FloatUtil.matrixToString(null, "matr-rot", "%10.5f", mat1, 0, mat2, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(mat1, mat2, FloatUtil.EPSILON);
+ Assert.assertEquals(mat1, mat2);
- quat.rotateVector(vecHas, 0, NEG_ONE, 0);
- FloatUtil.multMatrixVec(mat2, NEG_ONE_v4, vecOut2);
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(vecHas, vecOut2) ), Quaternion.ALLOWED_DEVIANCE );
+ quat.rotateVector(NEG_ONE, vecHas);
+ mat2.mulVec4f(NEG_ONE_v4, vecOut4);
+ vecOut3.set(vecOut4);
+ Assert.assertEquals( 0f, Math.abs( vecHas.dist(vecOut3) ), Quaternion.ALLOWED_DEVIANCE );
//
// 180 degrees rotation on Z
//
a = FloatUtil.PI;
- mat1 = new float[] { // Column Order
+ mat1.load( new float[] { // Column Order
FloatUtil.cos(a), FloatUtil.sin(a), 0, 0, //
-FloatUtil.sin(a), FloatUtil.cos(a), 0, 0,
0, 0, 1, 0,
- 0, 0, 0, 1 };
+ 0, 0, 0, 1 } );
{
// Validate Matrix via Euler rotation on Quaternion!
quat.setFromEuler(0f, 0f, a);
- quat.toMatrix(mat2, 0);
+ quat.toMatrix(mat2);
// System.err.println(FloatUtil.matrixToString(null, "quat-rot", "%10.5f", mat1, 0, mat2, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(mat1, mat2, FloatUtil.EPSILON);
- quat.rotateVector(vecHas, 0, UNIT_X, 0);
+ Assert.assertEquals(mat1, mat2);
+ quat.rotateVector(UNIT_X, vecHas);
// System.err.println("exp0 "+Arrays.toString(NEG_UNIT_X));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_X, vecHas) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals( 0f, Math.abs( NEG_UNIT_X.dist(vecHas) ), Quaternion.ALLOWED_DEVIANCE );
}
- quat.setFromMatrix(mat1, 0);
- quat.rotateVector(vecHas, 0, UNIT_X, 0);
+ quat.setFromMatrix(mat1);
+ quat.rotateVector(UNIT_X, vecHas);
// System.err.println("exp0 "+Arrays.toString(NEG_UNIT_X));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_X, vecHas) ), Quaternion.ALLOWED_DEVIANCE );
+ Assert.assertEquals( 0f, Math.abs( NEG_UNIT_X.dist(vecHas) ), Quaternion.ALLOWED_DEVIANCE );
- quat.toMatrix(mat2, 0);
+ quat.toMatrix(mat2);
// System.err.println(FloatUtil.matrixToString(null, "matr-rot", "%10.5f", mat1, 0, mat2, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(mat1, mat2, FloatUtil.EPSILON);
+ Assert.assertEquals(mat1, mat2);
- quat.rotateVector(vecHas, 0, ONE, 0);
- FloatUtil.multMatrixVec(mat2, ONE_v4, vecOut2);
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(vecHas, vecOut2) ), Quaternion.ALLOWED_DEVIANCE );
+ quat.rotateVector(ONE, vecHas);
+ mat2.mulVec4f(ONE_v4, vecOut4);
+ vecOut3.set(vecOut4);
+ Assert.assertEquals( 0f, Math.abs( vecHas.dist(vecOut3) ), Quaternion.ALLOWED_DEVIANCE );
//
// Test Matrix-Columns
//
a = FloatUtil.QUARTER_PI;
- final float[] vecExp = new float[3];
- final float[] vecCol = new float[3];
- mat1 = new float[] { // Column Order
+ final Vec3f vecExp0 = new Vec3f( FloatUtil.cos(a), FloatUtil.sin(a), 0);
+ final Vec3f vecExp1 = new Vec3f(-FloatUtil.sin(a), FloatUtil.cos(a), 0);
+ final Vec3f vecExp2 = new Vec3f( 0, 0, 1);
+ final Vec3f vecCol = new Vec3f();
+ mat1.load( new float[] { // Column Order
FloatUtil.cos(a), FloatUtil.sin(a), 0, 0, //
-FloatUtil.sin(a), FloatUtil.cos(a), 0, 0,
0, 0, 1, 0,
- 0, 0, 0, 1 };
- quat.setFromMatrix(mat1, 0);
- FloatUtil.copyMatrixColumn(mat1, 0, 0, vecExp, 0);
- quat.copyMatrixColumn(0, vecCol, 0);
+ 0, 0, 0, 1 } );
+ mat1.getColumn(0, vecCol);
// System.err.println("exp0 "+Arrays.toString(vecExp));
- // System.err.println("has0 "+Arrays.toString(vecCol));
- Assert.assertEquals(0f, Math.abs( VectorUtil.distVec3(vecExp, vecCol)), FloatUtil.EPSILON);
+ // System.err.println("has0 "+Arrays.toString(vecCol))
+ Assert.assertEquals(vecExp0, vecCol);
+ Assert.assertEquals(0f, Math.abs( vecExp0.dist(vecCol)), FloatUtil.EPSILON);
- FloatUtil.copyMatrixColumn(mat1, 0, 1, vecExp, 0);
- quat.copyMatrixColumn(1, vecCol, 0);
- // System.err.println("exp1 "+Arrays.toString(vecExp));
- // System.err.println("has1 "+Arrays.toString(vecCol));
- Assert.assertEquals(0f, Math.abs( VectorUtil.distVec3(vecExp, vecCol)), FloatUtil.EPSILON);
-
- FloatUtil.copyMatrixColumn(mat1, 0, 2, vecExp, 0);
- quat.copyMatrixColumn(2, vecCol, 0);
- // System.err.println("exp2 "+Arrays.toString(vecExp));
- // System.err.println("has2 "+Arrays.toString(vecCol));
- Assert.assertEquals(0f, Math.abs( VectorUtil.distVec3(vecExp, vecCol)), FloatUtil.EPSILON);
-
- quat.set(0f, 0f, 0f, 0f);
- Assert.assertArrayEquals(UNIT_X, quat.copyMatrixColumn(0, vecCol, 0), FloatUtil.EPSILON);
+ mat1.getColumn(1, vecCol);
+ Assert.assertEquals(vecExp1, vecCol);
+ Assert.assertEquals(0f, Math.abs( vecExp1.dist(vecCol)), FloatUtil.EPSILON);
+ mat1.getColumn(2, vecCol);
+ Assert.assertEquals(vecExp2, vecCol);
+ Assert.assertEquals(0f, Math.abs( vecExp2.dist(vecCol)), FloatUtil.EPSILON);
}
@Test
public void test15aAxesAndMatrix() {
- final float[] eulerExp = new float[] { 0f, FloatUtil.HALF_PI, 0f };
- final float[] matExp = new float[4*4];
- FloatUtil.makeRotationEuler(matExp, 0, eulerExp[0], eulerExp[1], eulerExp[2]); // 45 degr on X, 90 degr on Y
+ final Vec3f eulerExp = new Vec3f ( 0f, FloatUtil.HALF_PI, 0f ); // 45 degr on X, 90 degr on Y
+ final Matrix4f matExp1 = new Matrix4f();
+ matExp1.setToRotationEuler(eulerExp.x(), eulerExp.y(), eulerExp.z());
+ {
+ final float[] matExp0 = new float[4*4];
+ FloatUtil.makeRotationEuler(matExp0, 0, eulerExp.x(), eulerExp.y(), eulerExp.z());
+ final Matrix4f matExp0b = new Matrix4f();
+ matExp0b.load(matExp0);
+ Assert.assertEquals(matExp0b, matExp1);
+ }
- final float[] matHas = new float[4*4];
+ final Matrix4f matHas = new Matrix4f();;
final Quaternion quat1 = new Quaternion();
quat1.setFromEuler(eulerExp);
- quat1.toMatrix(matHas, 0);
+ quat1.toMatrix(matHas);
// System.err.println(FloatUtil.matrixToString(null, "exp-has", "%10.5f", matExp, 0, matHas, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(matExp, matHas, FloatUtil.EPSILON);
+ Assert.assertEquals(matExp1, matHas);
- final float[] eulerHas = new float[3];
+ final Vec3f eulerHas = new Vec3f();
final Quaternion quat2 = new Quaternion();
- quat2.setFromMatrix(matExp, 0);
+ quat2.setFromMatrix(matExp1);
quat2.toEuler(eulerHas);
// System.err.println("exp-euler "+Arrays.toString(eulerExp));
// System.err.println("has-euler "+Arrays.toString(eulerHas));
- Assert.assertArrayEquals(eulerExp, eulerHas, FloatUtil.EPSILON);
+ Assert.assertEquals(eulerExp, eulerHas);
Assert.assertEquals(quat2, quat1);
- final float[] angles = new float[3];
+ final Vec3f angles = new Vec3f();
quat2.toEuler(angles);
quat1.setFromEuler(angles);
Assert.assertEquals(quat2, quat1);
@@ -464,28 +542,39 @@ public class TestQuaternion01NOUI extends JunitTracer {
@Test
public void test15bAxesAndMatrix() {
- final float[] eulerExp = new float[] { FloatUtil.HALF_PI, 0f, 0f };
- final float[] matExp = new float[4*4];
- FloatUtil.makeRotationEuler(matExp, 0, eulerExp[0], eulerExp[1], eulerExp[2]); // 45 degr on X, 90 degr on Y
+ final Vec3f eulerExp = new Vec3f(FloatUtil.HALF_PI, 0f, 0f);
+ final Matrix4f matExp = new Matrix4f();
+ matExp.setToRotationEuler(eulerExp.x(), eulerExp.y(), eulerExp.z()); // 45 degr on X, 90 degr on Y (?)
+ {
+ final float[] matExp_b0 = new float[4*4];
+ FloatUtil.makeRotationEuler(matExp_b0, 0, eulerExp.x(), eulerExp.y(), eulerExp.z());
+ final Matrix4f matExp_b = new Matrix4f();
+ matExp_b.load(matExp_b0);
+ Assert.assertEquals(matExp_b, matExp);
+
+ final float[] matExp_b1 = new float[16];
+ matExp.get(matExp_b1);
+ Assert.assertArrayEquals(matExp_b0, matExp_b1, FloatUtil.EPSILON);
+ }
- final float[] matHas = new float[4*4];
+ final Matrix4f matHas = new Matrix4f();
final Quaternion quat1 = new Quaternion();
quat1.setFromEuler(eulerExp);
- quat1.toMatrix(matHas, 0);
+ quat1.toMatrix(matHas);
// System.err.println(FloatUtil.matrixToString(null, "exp-has", "%10.5f", matExp, 0, matHas, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(matExp, matHas, FloatUtil.EPSILON);
+ Assert.assertEquals(matExp, matHas);
- final float[] eulerHas = new float[3];
+ final Vec3f eulerHas = new Vec3f();
final Quaternion quat2 = new Quaternion();
- quat2.setFromMatrix(matExp, 0);
+ quat2.setFromMatrix(matExp);
quat2.toEuler(eulerHas);
// System.err.println("exp-euler "+Arrays.toString(eulerExp));
// System.err.println("has-euler "+Arrays.toString(eulerHas));
- Assert.assertArrayEquals(eulerExp, eulerHas, FloatUtil.EPSILON);
+ Assert.assertEquals(eulerExp, eulerHas);
Assert.assertEquals(quat2, quat1);
- final float[] angles = new float[3];
+ final Vec3f angles = new Vec3f();
quat2.toEuler(angles);
quat1.setFromEuler(angles);
Assert.assertEquals(quat2, quat1);
@@ -493,28 +582,68 @@ public class TestQuaternion01NOUI extends JunitTracer {
@Test
public void test15cAxesAndMatrix() {
- final float[] eulerExp = new float[] { FloatUtil.QUARTER_PI, FloatUtil.HALF_PI, 0f };
- final float[] matExp = new float[4*4];
- FloatUtil.makeRotationEuler(matExp, 0, eulerExp[0], eulerExp[1], eulerExp[2]); // 45 degr on X, 90 degr on Y
+ final Vec3f eulerExp1 = new Vec3f(FloatUtil.QUARTER_PI, FloatUtil.HALF_PI, 0f); // 45 degr on X, 90 degr on Y
+ final float[] eulerExp0 = new float[3];
+ eulerExp1.get(eulerExp0);
- final float[] matHas = new float[4*4];
+ final Matrix4f matExp = new Matrix4f();
+ matExp.setToRotationEuler(eulerExp1.x(), eulerExp1.y(), eulerExp1.z());
+ {
+ final float[] matExp_b0 = new float[4*4];
+ FloatUtil.makeRotationEuler(matExp_b0, 0, eulerExp1.x(), eulerExp1.y(), eulerExp1.z());
+ final Matrix4f matExp_b = new Matrix4f();
+ matExp_b.load(matExp_b0);
+ Assert.assertEquals(matExp_b, matExp);
+
+ final float[] matExp_b1 = new float[16];
+ matExp.get(matExp_b1);
+ Assert.assertArrayEquals(matExp_b0, matExp_b1, FloatUtil.EPSILON);
+
+ matExp.get(matExp_b0);
+ final Quaternion quat2 = new Quaternion();
+ quat2.setFromMatrix(matExp);
+ quat2.toMatrix(matExp_b1, 0);
+ Assert.assertArrayEquals(matExp_b0, matExp_b1, FloatUtil.EPSILON);
+ quat2.toMatrix(matExp_b);
+ Assert.assertEquals(matExp, matExp_b);
+ }
+
+ final Matrix4f matHas = new Matrix4f();
final Quaternion quat1 = new Quaternion();
- quat1.setFromEuler(eulerExp);
- quat1.toMatrix(matHas, 0);
+ quat1.setFromEuler(eulerExp1);
+ quat1.toMatrix(matHas);
// System.err.println(FloatUtil.matrixToString(null, "exp-has", "%10.5f", matExp, 0, matHas, 0, 4, 4, false).toString());
- Assert.assertArrayEquals(matExp, matHas, FloatUtil.EPSILON);
+ Assert.assertEquals(matExp, matHas);
- final float[] eulerHas = new float[3];
+ final Vec3f eulerHas1 = new Vec3f();
final Quaternion quat2 = new Quaternion();
- quat2.setFromMatrix(matExp, 0);
- quat2.toEuler(eulerHas);
- // System.err.println("exp-euler "+Arrays.toString(eulerExp));
- // System.err.println("has-euler "+Arrays.toString(eulerHas));
- Assert.assertArrayEquals(eulerExp, eulerHas, FloatUtil.EPSILON);
+ quat2.setFromMatrix(matExp);
+ quat2.toEuler(eulerHas1); // Vec3f
+ if( DEBUG ) {
+ System.err.println("PI");
+ System.err.printf(" double %20.20f%n", Math.PI);
+ System.err.printf(" float %20.20f%n", FloatUtil.PI);
+ System.err.printf(" diff %20.20f%n", (Math.PI - FloatUtil.PI));
+ System.err.println("PI/2");
+ System.err.printf(" double %20.20f%n", Math.PI/2f);
+ System.err.printf(" float %20.20f%n", FloatUtil.HALF_PI);
+ System.err.printf(" diff %20.20f%n", (Math.PI/2f - FloatUtil.HALF_PI));
+
+ System.err.println("exp-euler "+eulerExp1);
+ System.err.println("has-euler1 "+eulerHas1);
+ System.err.println("dif-euler1 "+eulerExp1.minus(eulerHas1));
+ }
+ {
+ final float[] eulerHas0 = new float[3];
+ eulerHas1.get(eulerHas0);
+ Assert.assertArrayEquals(eulerExp0, eulerHas0, FloatUtil.EPSILON);
+ }
+ Assert.assertTrue(eulerExp1+" != "+eulerHas1, eulerExp1.isEqual(eulerHas1, Quaternion.ALLOWED_DEVIANCE));
+ // Assert.assertEquals(eulerExp1, eulerHas1); // `diff < EPSILON` criteria hits, while `Assert.assertArrayEquals(..)` uses `diff <= EPSILON`
Assert.assertEquals(quat2, quat1);
- final float[] angles = new float[3];
+ final Vec3f angles = new Vec3f();
quat2.toEuler(angles);
quat1.setFromEuler(angles);
Assert.assertEquals(quat2, quat1);
@@ -562,20 +691,20 @@ public class TestQuaternion01NOUI extends JunitTracer {
quat2.set(quat1);
quat2.mult(quat1); // q2 = q1 * q1 -> 2 * 45 degr -> 90 degr on Y
- final float[] vecOut = new float[3];
- quat2.rotateVector(vecOut, 0, UNIT_Z, 0);
- Assert.assertTrue( Math.abs( VectorUtil.distVec3(UNIT_X, vecOut)) <= Quaternion.ALLOWED_DEVIANCE);
+ final Vec3f vecOut = new Vec3f();
+ quat2.rotateVector(UNIT_Z, vecOut);
+ Assert.assertTrue( Math.abs( UNIT_X.dist(vecOut)) <= Quaternion.ALLOWED_DEVIANCE);
quat2.setFromAngleNormalAxis(FloatUtil.HALF_PI, UNIT_Y); // 90 degr on Y
quat1.mult(quat1); // q1 = q1 * q1 -> 2 * 45 degr -> 90 degr on Y
quat1.mult(quat2); // q1 = q1 * q2 -> 2 * 90 degr -> 180 degr on Y
- quat1.rotateVector(vecOut, 0, UNIT_Z, 0);
- Assert.assertTrue( Math.abs( VectorUtil.distVec3(NEG_UNIT_Z, vecOut)) <= Quaternion.ALLOWED_DEVIANCE);
+ quat1.rotateVector(UNIT_Z, vecOut);
+ Assert.assertTrue( Math.abs( NEG_UNIT_Z.dist(vecOut)) <= Quaternion.ALLOWED_DEVIANCE);
quat2.setFromEuler(0f, FloatUtil.HALF_PI, 0f);
quat1.mult(quat2); // q1 = q1 * q2 = q1 * rotMat(0, 90degr, 0)
- quat1.rotateVector(vecOut, 0, UNIT_Z, 0);
- Assert.assertTrue( Math.abs( VectorUtil.distVec3(NEG_UNIT_X, vecOut)) <= Quaternion.ALLOWED_DEVIANCE);
+ quat1.rotateVector(UNIT_Z, vecOut);
+ Assert.assertTrue( Math.abs( NEG_UNIT_X.dist(vecOut)) <= Quaternion.ALLOWED_DEVIANCE);
}
@Test
@@ -631,50 +760,54 @@ public class TestQuaternion01NOUI extends JunitTracer {
}
- float[] vecExp = new float[3];
- float[] vecRot = new float[3];
+ final Vec3f vecExp = new Vec3f();
+ final Vec3f vecRot = new Vec3f();
final Quaternion quat = new Quaternion();
// Try a new way with new angles...
quat.setFromEuler(FloatUtil.HALF_PI, FloatUtil.QUARTER_PI, FloatUtil.PI);
- vecRot = new float[] { 1f, 1f, 1f };
- quat.rotateVector(vecRot, 0, vecRot, 0);
+ vecRot.set(1f, 1f, 1f);
+ quat.rotateVector(vecRot, vecRot);
// expected
- vecExp = new float[] { 1f, 1f, 1f };
+ vecExp.set(1f, 1f, 1f);
final Quaternion worker = new Quaternion();
// put together matrix, then apply to vector, so YZX
worker.rotateByAngleY(FloatUtil.QUARTER_PI).rotateByAngleZ(FloatUtil.PI).rotateByAngleX(FloatUtil.HALF_PI);
- quat.rotateVector(vecExp, 0, vecExp, 0);
- Assert.assertEquals(0f, VectorUtil.distVec3(vecExp, vecRot), FloatUtil.EPSILON);
+ quat.rotateVector(vecExp, vecExp);
+ Assert.assertEquals(0f, vecExp.dist(vecRot), FloatUtil.EPSILON);
+ Assert.assertEquals(vecExp, vecRot);
// test axis rotation methods against general purpose
// X AXIS
- vecExp = new float[] { 1f, 1f, 1f };
- vecRot = new float[] { 1f, 1f, 1f };
- worker.setIdentity().rotateByAngleX(FloatUtil.QUARTER_PI).rotateVector(vecExp, 0, vecExp, 0);
- worker.setIdentity().rotateByAngleNormalAxis(FloatUtil.QUARTER_PI, 1f, 0f, 0f).rotateVector(vecRot, 0, vecRot, 0);
+ vecExp.set(1f, 1f, 1f);
+ vecRot.set(1f, 1f, 1f);
+ worker.setIdentity().rotateByAngleX(FloatUtil.QUARTER_PI).rotateVector(vecExp, vecExp);
+ worker.setIdentity().rotateByAngleNormalAxis(FloatUtil.QUARTER_PI, 1f, 0f, 0f).rotateVector(vecRot, vecRot);
// System.err.println("exp0 "+Arrays.toString(vecExp)+", len "+VectorUtil.length(vecExp));
// System.err.println("has0 "+Arrays.toString(vecRot)+", len "+VectorUtil.length(vecRot));
- Assert.assertEquals(0f, VectorUtil.distVec3(vecExp, vecRot), FloatUtil.EPSILON);
+ Assert.assertEquals(0f, vecExp.dist(vecRot), FloatUtil.EPSILON);
+ Assert.assertEquals(vecExp, vecRot);
// Y AXIS
- vecExp = new float[] { 1f, 1f, 1f };
- vecRot = new float[] { 1f, 1f, 1f };
- worker.setIdentity().rotateByAngleY(FloatUtil.QUARTER_PI).rotateVector(vecExp, 0, vecExp, 0);
- worker.setIdentity().rotateByAngleNormalAxis(FloatUtil.QUARTER_PI, 0f, 1f, 0f).rotateVector(vecRot, 0, vecRot, 0);
+ vecExp.set(1f, 1f, 1f);
+ vecRot.set(1f, 1f, 1f);
+ worker.setIdentity().rotateByAngleY(FloatUtil.QUARTER_PI).rotateVector(vecExp, vecExp);
+ worker.setIdentity().rotateByAngleNormalAxis(FloatUtil.QUARTER_PI, 0f, 1f, 0f).rotateVector(vecRot, vecRot);
// System.err.println("exp0 "+Arrays.toString(vecExp));
// System.err.println("has0 "+Arrays.toString(vecRot));
- Assert.assertEquals(0f, VectorUtil.distVec3(vecExp, vecRot), FloatUtil.EPSILON);
+ Assert.assertEquals(0f, vecExp.dist(vecRot), FloatUtil.EPSILON);
+ Assert.assertEquals(vecExp, vecRot);
// Z AXIS
- vecExp = new float[] { 1f, 1f, 1f };
- vecRot = new float[] { 1f, 1f, 1f };
- worker.setIdentity().rotateByAngleZ(FloatUtil.QUARTER_PI).rotateVector(vecExp, 0, vecExp, 0);
- worker.setIdentity().rotateByAngleNormalAxis(FloatUtil.QUARTER_PI, 0f, 0f, 1f).rotateVector(vecRot, 0, vecRot, 0);
+ vecExp.set(1f, 1f, 1f);
+ vecRot.set(1f, 1f, 1f);
+ worker.setIdentity().rotateByAngleZ(FloatUtil.QUARTER_PI).rotateVector(vecExp, vecExp);
+ worker.setIdentity().rotateByAngleNormalAxis(FloatUtil.QUARTER_PI, 0f, 0f, 1f).rotateVector(vecRot, vecRot);
// System.err.println("exp0 "+Arrays.toString(vecExp));
// System.err.println("has0 "+Arrays.toString(vecRot));
- Assert.assertEquals(0f, VectorUtil.distVec3(vecExp, vecRot), FloatUtil.EPSILON);
+ Assert.assertEquals(0f, vecExp.dist(vecRot), FloatUtil.EPSILON);
+ Assert.assertEquals(vecExp, vecRot);
quat.set(worker);
worker.rotateByAngleNormalAxis(0f, 0f, 0f, 0f);
@@ -684,18 +817,18 @@ public class TestQuaternion01NOUI extends JunitTracer {
@Test
public void test24Axes() {
final Quaternion quat0 = new Quaternion().rotateByAngleX(FloatUtil.QUARTER_PI).rotateByAngleY(FloatUtil.HALF_PI);
- final float[] rotMat = new float[4*4];
- quat0.toMatrix(rotMat, 0);
- final float[] xAxis = new float[3];
- final float[] yAxis = new float[3];
- final float[] zAxis = new float[3];
- FloatUtil.copyMatrixColumn(rotMat, 0, 0, xAxis, 0);
- FloatUtil.copyMatrixColumn(rotMat, 0, 1, yAxis, 0);
- FloatUtil.copyMatrixColumn(rotMat, 0, 2, zAxis, 0);
+ final Matrix4f rotMat = new Matrix4f();
+ quat0.toMatrix(rotMat);
+ final Vec3f xAxis = new Vec3f();
+ final Vec3f yAxis = new Vec3f();
+ final Vec3f zAxis = new Vec3f();
+ rotMat.getColumn(0, xAxis);
+ rotMat.getColumn(1, yAxis);
+ rotMat.getColumn(2, zAxis);
final Quaternion quat1 = new Quaternion().setFromAxes(xAxis, yAxis, zAxis);
Assert.assertEquals(quat0, quat1);
- final Quaternion quat2 = new Quaternion().setFromMatrix(rotMat, 0);
+ final Quaternion quat2 = new Quaternion().setFromMatrix(rotMat);
Assert.assertEquals(quat2, quat1);
quat1.toAxes(xAxis, yAxis, zAxis, rotMat);
@@ -709,107 +842,126 @@ public class TestQuaternion01NOUI extends JunitTracer {
final Quaternion quat1 = new Quaternion(); // angle: 0 degrees
final Quaternion quat2 = new Quaternion().rotateByAngleY(FloatUtil.HALF_PI); // angle: 90 degrees, axis Y
- float[] vecExp = new float[] { FloatUtil.sin(FloatUtil.QUARTER_PI), 0f, FloatUtil.sin(FloatUtil.QUARTER_PI) };
- final float[] vecHas = new float[3];
+ final Vec3f vecExp = new Vec3f( FloatUtil.sin(FloatUtil.QUARTER_PI), 0f, FloatUtil.sin(FloatUtil.QUARTER_PI) );
+ final Vec3f vecHas = new Vec3f();
final Quaternion quatS = new Quaternion();
// System.err.println("Slerp #01: 1/2 * 90 degrees Y");
quatS.setSlerp(quat1, quat2, 0.5f);
- quatS.rotateVector(vecHas, 0, UNIT_Z, 0);
+ quatS.rotateVector(UNIT_Z, vecHas);
// System.err.println("exp0 "+Arrays.toString(vecExp));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(vecExp, vecHas)), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals( 0f, Math.abs( vecExp.dist(vecHas)), Quaternion.ALLOWED_DEVIANCE);
+ if( !vecExp.equals(vecHas) ) {
+ System.err.println("Deviance: "+vecExp+", "+vecHas+": "+vecExp.minus(vecHas)+", dist "+vecExp.dist(vecHas));
+ }
+ // Assert.assertEquals(vecExp, vecHas);
// delta == 100%
quat2.setIdentity().rotateByAngleZ(FloatUtil.PI); // angle: 180 degrees, axis Z
// System.err.println("Slerp #02: 1 * 180 degrees Z");
quatS.setSlerp(quat1, quat2, 1.0f);
- quatS.rotateVector(vecHas, 0, UNIT_X, 0);
+ quatS.rotateVector(UNIT_X, vecHas);
// System.err.println("exp0 "+Arrays.toString(NEG_UNIT_X));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(NEG_UNIT_X, vecHas)), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals( 0f, Math.abs( NEG_UNIT_X.dist(vecHas)), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals(NEG_UNIT_X, vecHas);
quat2.setIdentity().rotateByAngleZ(FloatUtil.PI); // angle: 180 degrees, axis Z
// System.err.println("Slerp #03: 1/2 * 180 degrees Z");
quatS.setSlerp(quat1, quat2, 0.5f);
- quatS.rotateVector(vecHas, 0, UNIT_X, 0);
+ quatS.rotateVector(UNIT_X, vecHas);
// System.err.println("exp0 "+Arrays.toString(UNIT_Y));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(UNIT_Y, vecHas)), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals( 0f, Math.abs( UNIT_Y.dist(vecHas)), Quaternion.ALLOWED_DEVIANCE);
+ if( !UNIT_Y.equals(vecHas) ) {
+ System.err.println("Deviance: "+UNIT_Y+", "+vecHas+": "+UNIT_Y.minus(vecHas)+", dist "+UNIT_Y.dist(vecHas));
+ }
+ // Assert.assertEquals(UNIT_Y, vecHas);
// delta == 0%
quat2.setIdentity().rotateByAngleZ(FloatUtil.PI); // angle: 180 degrees, axis Z
// System.err.println("Slerp #04: 0 * 180 degrees Z");
quatS.setSlerp(quat1, quat2, 0.0f);
- quatS.rotateVector(vecHas, 0, UNIT_X, 0);
+ quatS.rotateVector(UNIT_X, vecHas);
// System.err.println("exp0 "+Arrays.toString(UNIT_X));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(UNIT_X, vecHas)), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals( 0f, Math.abs( UNIT_X.dist(vecHas)), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals(UNIT_X, vecHas);
// a==b
quat2.setIdentity();
// System.err.println("Slerp #05: 1/4 * 0 degrees");
quatS.setSlerp(quat1, quat2, 0.25f); // 1/4 of identity .. NOP
- quatS.rotateVector(vecHas, 0, UNIT_X, 0);
+ quatS.rotateVector(UNIT_X, vecHas);
// System.err.println("exp0 "+Arrays.toString(UNIT_X));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(UNIT_X, vecHas)), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals( 0f, Math.abs( UNIT_X.dist(vecHas)), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals(UNIT_X, vecHas);
// negative dot product
- vecExp = new float[] { 0f, -FloatUtil.sin(FloatUtil.QUARTER_PI), FloatUtil.sin(FloatUtil.QUARTER_PI) };
+ vecExp.set(0f, -FloatUtil.sin(FloatUtil.QUARTER_PI), FloatUtil.sin(FloatUtil.QUARTER_PI));
quat1.setIdentity().rotateByAngleX( -2f * FloatUtil.HALF_PI); // angle: -180 degrees, axis X
quat2.setIdentity().rotateByAngleX( FloatUtil.HALF_PI); // angle: 90 degrees, axis X
// System.err.println("Slerp #06: 1/2 * 270 degrees");
quatS.setSlerp(quat1, quat2, 0.5f);
- quatS.rotateVector(vecHas, 0, UNIT_Y, 0);
+ quatS.rotateVector(UNIT_Y, vecHas);
// System.err.println("exp0 "+Arrays.toString(vecExp));
// System.err.println("has0 "+Arrays.toString(vecHas));
- Assert.assertEquals( 0f, Math.abs( VectorUtil.distVec3(vecExp, vecHas)), Quaternion.ALLOWED_DEVIANCE);
-
-
+ Assert.assertEquals( 0f, Math.abs( vecExp.dist(vecHas) ), Quaternion.ALLOWED_DEVIANCE);
+ if( !vecExp.equals(vecHas) ) {
+ System.err.println("Deviance: "+vecExp+", "+vecHas+": "+vecExp.minus(vecHas)+", dist "+vecExp.dist(vecHas));
+ }
+ // Assert.assertEquals(vecExp, vecHas);
}
@Test
public void test26LookAt() {
- final float[] direction = new float[3];
- final float[] xAxis = new float[3];
- final float[] yAxis = new float[3];
- final float[] zAxis = new float[3];
- final float[] vecHas = new float[3];
+ final Vec3f direction = new Vec3f();
+ final Vec3f xAxis = new Vec3f();
+ final Vec3f yAxis = new Vec3f();
+ final Vec3f zAxis = new Vec3f();
+ final Vec3f vecHas = new Vec3f();
if( DEBUG ) System.err.println("LookAt #01");
- VectorUtil.copyVec3(direction, 0, NEG_UNIT_X, 0);
+ direction.set(NEG_UNIT_X);
final Quaternion quat = new Quaternion().setLookAt(direction, UNIT_Y, xAxis, yAxis, zAxis);
- Assert.assertEquals(0f, VectorUtil.distVec3(direction, quat.rotateVector(vecHas, 0, UNIT_Z, 0)), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals(0f, direction.dist( quat.rotateVector(UNIT_Z, vecHas) ), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals(direction, vecHas);
if( DEBUG ) System.err.println("LookAt #02");
- VectorUtil.normalizeVec3(VectorUtil.copyVec3(direction, 0, ONE, 0));
+ direction.set(ONE).normalize();
quat.setLookAt(direction, UNIT_Y, xAxis, yAxis, zAxis);
if( DEBUG )System.err.println("quat0 "+quat);
- quat.rotateVector(vecHas, 0, UNIT_Z, 0);
+ quat.rotateVector(UNIT_Z, vecHas);
if( DEBUG ) {
- System.err.println("xAxis "+Arrays.toString(xAxis)+", len "+VectorUtil.normVec3(xAxis));
- System.err.println("yAxis "+Arrays.toString(yAxis)+", len "+VectorUtil.normVec3(yAxis));
- System.err.println("zAxis "+Arrays.toString(zAxis)+", len "+VectorUtil.normVec3(zAxis));
- System.err.println("exp0 "+Arrays.toString(direction)+", len "+VectorUtil.normVec3(direction));
- System.err.println("has0 "+Arrays.toString(vecHas)+", len "+VectorUtil.normVec3(vecHas));
+ System.err.println("xAxis "+xAxis+", len "+xAxis.length());
+ System.err.println("yAxis "+yAxis+", len "+yAxis.length());
+ System.err.println("zAxis "+zAxis+", len "+zAxis.length());
+ System.err.println("exp0 "+direction+", len "+direction.length());
+ System.err.println("has0 "+vecHas+", len "+vecHas.length());
}
// Assert.assertEquals(0f, VectorUtil.distance(direction, quat.rotateVector(vecHas, 0, UNIT_Z, 0)), Quaternion.ALLOWED_DEVIANCE);
- Assert.assertEquals(0f, VectorUtil.distVec3(direction, vecHas), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals(0f, direction.dist(vecHas), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals(direction, vecHas);
if( DEBUG )System.err.println("LookAt #03");
- VectorUtil.normalizeVec3(VectorUtil.copyVec3(direction, 0, new float[] { -1f, 2f, -1f }, 0));
+ direction.set(-1f, 2f, -1f).normalize();
quat.setLookAt(direction, UNIT_Y, xAxis, yAxis, zAxis);
if( DEBUG )System.err.println("quat0 "+quat);
- quat.rotateVector(vecHas, 0, UNIT_Z, 0);
+ quat.rotateVector(UNIT_Z, vecHas);
if( DEBUG ) {
- System.err.println("xAxis "+Arrays.toString(xAxis)+", len "+VectorUtil.normVec3(xAxis));
- System.err.println("yAxis "+Arrays.toString(yAxis)+", len "+VectorUtil.normVec3(yAxis));
- System.err.println("zAxis "+Arrays.toString(zAxis)+", len "+VectorUtil.normVec3(zAxis));
- System.err.println("exp0 "+Arrays.toString(direction)+", len "+VectorUtil.normVec3(direction));
- System.err.println("has0 "+Arrays.toString(vecHas)+", len "+VectorUtil.normVec3(vecHas));
+ System.err.println("xAxis "+xAxis+", len "+xAxis.length());
+ System.err.println("yAxis "+yAxis+", len "+yAxis.length());
+ System.err.println("zAxis "+zAxis+", len "+zAxis.length());
+ System.err.println("exp0 "+direction+", len "+direction.length());
+ System.err.println("has0 "+vecHas+", len "+vecHas.length());
}
// Assert.assertEquals(0f, VectorUtil.distance(direction, quat.rotateVector(vecHas, 0, UNIT_Z, 0)), Quaternion.ALLOWED_DEVIANCE);
- Assert.assertEquals(0f, VectorUtil.distVec3(direction, vecHas), Quaternion.ALLOWED_DEVIANCE);
+ Assert.assertEquals(0f, direction.dist(vecHas), Quaternion.ALLOWED_DEVIANCE);
+ if( !direction.equals(vecHas) ) {
+ System.err.println("Deviance: "+direction+", "+vecHas+": "+direction.minus(vecHas)+", dist "+direction.dist(vecHas));
+ }
+ // Assert.assertEquals(direction, vecHas);
}
public static void main(final String args[]) {
--
cgit v1.2.3