diff options
author | Sven Gothel <[email protected]> | 2014-06-27 18:16:43 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-06-27 18:16:43 +0200 |
commit | 0bded476868c5fdfe44502bfd55957469d0d72bb (patch) | |
tree | 8f3baefe8c7267a11dffacc4ba1814478c4b2123 /src/jogl/classes/com/jogamp | |
parent | 21b84da775fae5806481ecc658a207bf603126d5 (diff) |
Enhance FloatUtil: Merge ProjectFloat features while adding optimized variations; PMVMatrix: Remove NIO buffer path, use backing-array only and FloatUtil direct.
- FloatUtil pptimized variants:
- mapObjToWinCoords (gluProject) passing 'P x Mv' for batch operations
- mapWinToObjCoords (gluUnProject) passing 'Inv(P x Mv)' for batch operations
- mapWinToObjCoords (gluUnProject) passing 'Inv(P x Mv)' and two winz values
for two ray picking resulting in two obj positions. (-> mapWinToRay)
- PMVMatrix
- dropped low performance NIO mode
- simply use common backing-array and fixed offsets directly
- drop ProjectFloat usage in favor of FloatUtil
- reduce number of temporary arrays
Diffstat (limited to 'src/jogl/classes/com/jogamp')
6 files changed, 1691 insertions, 481 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java index cf56ff0a4..f7a12f2dd 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java @@ -34,6 +34,7 @@ import javax.media.opengl.GLException; import jogamp.opengl.Debug; import com.jogamp.common.os.Platform; +import com.jogamp.opengl.math.geom.AABBox; /** * Basic Float math utility functions. @@ -61,64 +62,263 @@ import com.jogamp.common.os.Platform; * * @author Erik Duijs, Kenneth Russell, et al. */ -public class FloatUtil { +public final class FloatUtil { public static final boolean DEBUG = Debug.debug("Math"); - private static final float[] IDENTITY_MATRIX = - new float[] { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f }; + // + // Matrix Ops + // - private static final float[] ZERO_MATRIX = - new float[] { - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f }; + /** + * Make matrix an identity matrix + * @param m 4x4 matrix in column-major order (also result) + * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix + * @return given matrix for chaining + */ + public static float[] makeIdentity(final float[] m, final int m_offset) { + m[m_offset+0+4*0] = 1f; + m[m_offset+1+4*0] = 0f; + m[m_offset+2+4*0] = 0f; + m[m_offset+3+4*0] = 0f; + + m[m_offset+0+4*1] = 0f; + m[m_offset+1+4*1] = 1f; + m[m_offset+2+4*1] = 0f; + m[m_offset+3+4*1] = 0f; + + m[m_offset+0+4*2] = 0f; + m[m_offset+1+4*2] = 0f; + m[m_offset+2+4*2] = 1f; + m[m_offset+3+4*2] = 0f; + + m[m_offset+0+4*3] = 0f; + m[m_offset+1+4*3] = 0f; + m[m_offset+2+4*3] = 0f; + m[m_offset+3+4*3] = 1f; + return m; + } /** * Make matrix an identity matrix + * @param m 4x4 matrix in column-major order (also result) + * @return given matrix for chaining */ - public static final void makeIdentityf(float[] m, int offset) { - for (int i = 0; i < 16; i++) { - m[i+offset] = IDENTITY_MATRIX[i]; - } + public static float[] makeIdentity(final float[] m) { + m[0+4*0] = 1f; + m[1+4*0] = 0f; + m[2+4*0] = 0f; + m[3+4*0] = 0f; + + m[0+4*1] = 0f; + m[1+4*1] = 1f; + m[2+4*1] = 0f; + m[3+4*1] = 0f; + + m[0+4*2] = 0f; + m[1+4*2] = 0f; + m[2+4*2] = 1f; + m[3+4*2] = 0f; + + m[0+4*3] = 0f; + m[1+4*3] = 0f; + m[2+4*3] = 0f; + m[3+4*3] = 1f; + return m; } /** * Make matrix an identity matrix + * @param m 4x4 matrix in column-major order (also result) + * @return given matrix for chaining */ - public static final void makeIdentityf(FloatBuffer m) { - final int oldPos = m.position(); - m.put(IDENTITY_MATRIX); - m.position(oldPos); + public static FloatBuffer makeIdentity(final FloatBuffer m) { + final int m_offset = m.position(); + m.put(m_offset+0+4*0, 1f); + m.put(m_offset+1+4*0, 0f); + m.put(m_offset+2+4*0, 0f); + m.put(m_offset+3+4*0, 0f); + + m.put(m_offset+0+4*1, 0f); + m.put(m_offset+1+4*1, 1f); + m.put(m_offset+2+4*1, 0f); + m.put(m_offset+3+4*1, 0f); + + m.put(m_offset+0+4*2, 0f); + m.put(m_offset+1+4*2, 0f); + m.put(m_offset+2+4*2, 1f); + m.put(m_offset+3+4*2, 0f); + + m.put(m_offset+0+4*3, 0f); + m.put(m_offset+1+4*3, 0f); + m.put(m_offset+2+4*3, 0f); + m.put(m_offset+3+4*3, 1f); + return m; } /** - * Make matrix an zero matrix + * Make a translation matrix in column-major order from the given axis deltas + * <pre> + Translation matrix (Column Order): + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + x y z 1 + * </pre> + * <p> + * All matrix fields are only set if <code>initM</code> is <code>true</code>. + * </p> + * @param m 4x4 matrix in column-major order (also result) + * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix + * @param initM if true, given matrix will be initialized w/ identity matrix, + * otherwise only the diagonal and last-row is set. + * The latter can be utilized to share a once {@link #makeIdentity(float[], int) identity set} matrix + * for {@link #makeScale(float[], int, boolean, float, float, float) scaling} + * and {@link #makeTranslation(float[], int, boolean, float, float, float) translation}, + * while leaving the other fields untouched for performance reasons. + * @return given matrix for chaining */ - public static final void makeZero(float[] m, int offset) { - for (int i = 0; i < 16; i++) { - m[i+offset] = 0; - } + public static float[] makeTranslation(final float[] m, final int m_offset, final boolean initM, final float tx, final float ty, final float tz) { + if( initM ) { + makeIdentity(m, m_offset); + } else { + m[m_offset+0+4*0] = 1; + m[m_offset+1+4*1] = 1; + m[m_offset+2+4*2] = 1; + m[m_offset+3+4*3] = 1; + } + m[m_offset+0+4*3] = tx; + m[m_offset+1+4*3] = ty; + m[m_offset+2+4*3] = tz; + return m; } /** - * Make matrix an zero matrix + * Make a translation matrix in column-major order from the given axis deltas + * <pre> + Translation matrix (Column Order): + 1 0 0 0 + 0 1 0 0 + 0 0 1 0 + x y z 1 + * </pre> + * <p> + * All matrix fields are only set if <code>initM</code> is <code>true</code>. + * </p> + * @param m 4x4 matrix in column-major order (also result) + * @param initM if true, given matrix will be initialized w/ identity matrix, + * otherwise only the diagonal and last-row is set. + * The latter can be utilized to share a once {@link #makeIdentity(float[], int) identity set} matrix + * for {@link #makeScale(float[], int, boolean, float, float, float) scaling} + * and {@link #makeTranslation(float[], int, boolean, float, float, float) translation}, + * while leaving the other fields untouched for performance reasons. + * @return given matrix for chaining + */ + public static float[] makeTranslation(final float[] m, final boolean initM, final float tx, final float ty, final float tz) { + if( initM ) { + makeIdentity(m); + } else { + m[0+4*0] = 1; + m[1+4*1] = 1; + m[2+4*2] = 1; + m[3+4*3] = 1; + } + m[0+4*3] = tx; + m[1+4*3] = ty; + m[2+4*3] = tz; + return m; + } + + /** + * Make a scale matrix in column-major order from the given axis factors + * <pre> + Scale matrix (Any Order): + x 0 0 0 + 0 y 0 0 + 0 0 z 0 + 0 0 0 1 + * </pre> + * <p> + * All matrix fields are only set if <code>initM</code> is <code>true</code>. + * </p> + * @param m 4x4 matrix in column-major order (also result) + * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix + * @param initM if true, given matrix will be initialized w/ identity matrix, + * otherwise only the diagonal and last-row is set. + * The latter can be utilized to share a once {@link #makeIdentity(float[], int) identity set} matrix + * for {@link #makeScale(float[], int, boolean, float, float, float) scaling} + * and {@link #makeTranslation(float[], int, boolean, float, float, float) translation}, + * while leaving the other fields untouched for performance reasons. + * @return given matrix for chaining + */ + public static float[] makeScale(final float[] m, final int m_offset, final boolean initM, final float sx, final float sy, final float sz) { + if( initM ) { + makeIdentity(m, m_offset); + } else { + m[m_offset+0+4*3] = 0; + m[m_offset+1+4*3] = 0; + m[m_offset+2+4*3] = 0; + m[m_offset+3+4*3] = 1; + } + m[m_offset+0+4*0] = sx; + m[m_offset+1+4*1] = sy; + m[m_offset+2+4*2] = sz; + return m; + } + + /** + * Make a scale matrix in column-major order from the given axis factors + * <pre> + Scale matrix (Any Order): + x 0 0 0 + 0 y 0 0 + 0 0 z 0 + 0 0 0 1 + * </pre> + * <p> + * All matrix fields are only set if <code>initM</code> is <code>true</code>. + * </p> + * @param m 4x4 matrix in column-major order (also result) + * @param initM if true, given matrix will be initialized w/ identity matrix, + * otherwise only the diagonal and last-row is set. + * The latter can be utilized to share a once {@link #makeIdentity(float[], int) identity set} matrix + * for {@link #makeScale(float[], int, boolean, float, float, float) scaling} + * and {@link #makeTranslation(float[], int, boolean, float, float, float) translation}, + * while leaving the other fields untouched for performance reasons. + * @return given matrix for chaining */ - public static final void makeZero(FloatBuffer m) { - final int oldPos = m.position(); - m.put(ZERO_MATRIX); - m.position(oldPos); + public static float[] makeScale(final float[] m, final boolean initM, final float sx, final float sy, final float sz) { + if( initM ) { + makeIdentity(m); + } else { + m[0+4*3] = 0; + m[1+4*3] = 0; + m[2+4*3] = 0; + m[3+4*3] = 1; + } + m[0+4*0] = sx; + m[1+4*1] = sy; + m[2+4*2] = sz; + return m; } /** * Make a rotation matrix from the given axis and angle in radians. + * <pre> + 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 + * </pre> + * <p> + * All matrix fields are set. + * </p> * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a> + * @param m 4x4 matrix in column-major order (also result) + * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix + * @return given matrix for chaining */ - public static final void makeRotationAxis(final float angrad, float x, float y, float z, final float[] mat, final int mat_offset, final float[] tmpVec3f) { + public static float[] makeRotationAxis(final float[] m, final int m_offset, final float angrad, float x, float y, float z, final float[] tmpVec3f) { final float c = cos(angrad); final float ic= 1.0f - c; final float s = sin(angrad); @@ -127,28 +327,33 @@ public class FloatUtil { VectorUtil.normalizeVec3(tmpVec3f); x = tmpVec3f[0]; y = tmpVec3f[1]; z = tmpVec3f[2]; - // Rotation matrix (Row 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 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; - mat[0+0*4+mat_offset] = x*x*ic+c; - mat[1+0*4+mat_offset] = xy*ic+zs; - mat[2+0*4+mat_offset] = xz*ic-ys; - - mat[0+1*4+mat_offset] = xy*ic-zs; - mat[1+1*4+mat_offset] = y*y*ic+c; - mat[2+1*4+mat_offset] = yz*ic+xs; - - mat[0+2*4+mat_offset] = xz*ic+ys; - mat[1+2*4+mat_offset] = yz*ic-xs; - mat[2+2*4+mat_offset] = z*z*ic+c; + m[0+0*4+m_offset] = x*x*ic+c; + m[1+0*4+m_offset] = xy*ic+zs; + m[2+0*4+m_offset] = xz*ic-ys; + m[3+0*4+m_offset] = 0; + + m[0+1*4+m_offset] = xy*ic-zs; + m[1+1*4+m_offset] = y*y*ic+c; + m[2+1*4+m_offset] = yz*ic+xs; + m[3+1*4+m_offset] = 0; + + m[0+2*4+m_offset] = xz*ic+ys; + m[1+2*4+m_offset] = yz*ic-xs; + m[2+2*4+m_offset] = z*z*ic+c; + m[3+2*4+m_offset] = 0; + + m[0+3*4+m_offset] = 0f; + m[1+3*4+m_offset] = 0f; + m[2+3*4+m_offset] = 0f; + m[3+3*4+m_offset] = 1f; + + return m; } /** @@ -161,9 +366,15 @@ public class FloatUtil { * <li>x - bank</li> * </ul> * </p> + * <p> + * All matrix fields are set. + * </p> + * @param m 4x4 matrix in column-major order (also result) + * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix * @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 given matrix for chaining * <p> * Implementation does not use Quaternion and hence is exposed to * <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q34">Gimbal-Lock</a> @@ -171,7 +382,7 @@ public class FloatUtil { * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q36">Matrix-FAQ Q36</a> * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm">euclideanspace.com-eulerToMatrix</a> */ - public static final void makeRotationEuler(final float bankX, final float headingY, final float attitudeZ, final float[] mat, final int mat_offset) { + public static float[] makeRotationEuler(final float[] m, final int m_offset, final float bankX, final float headingY, final float attitudeZ) { // Assuming the angles are in radians. final float ch = cos(headingY); final float sh = sin(headingY); @@ -180,32 +391,45 @@ public class FloatUtil { final float cb = cos(bankX); final float sb = sin(bankX); - mat[0+0*4+mat_offset] = ch*ca; - mat[0+1*4+mat_offset] = sh*sb - ch*sa*cb; - mat[0+2*4+mat_offset] = ch*sa*sb + sh*cb; - mat[1+0*4+mat_offset] = sa; - mat[1+1*4+mat_offset] = ca*cb; - mat[1+2*4+mat_offset] = -ca*sb; - mat[2+0*4+mat_offset] = -sh*ca; - mat[2+1*4+mat_offset] = sh*sa*cb + ch*sb; - mat[2+2*4+mat_offset] = -sh*sa*sb + ch*cb; + m[0+0*4+m_offset] = ch*ca; + m[0+1*4+m_offset] = sh*sb - ch*sa*cb; + m[0+2*4+m_offset] = ch*sa*sb + sh*cb; + m[0+3*4+m_offset] = 0; + + m[1+0*4+m_offset] = sa; + m[1+1*4+m_offset] = ca*cb; + m[1+2*4+m_offset] = -ca*sb; + m[1+3*4+m_offset] = 0; + + m[2+0*4+m_offset] = -sh*ca; + m[2+1*4+m_offset] = sh*sa*cb + ch*sb; + m[2+2*4+m_offset] = -sh*sa*sb + ch*cb; + m[2+3*4+m_offset] = 0; - mat[3+0*4+mat_offset] = 0; - mat[3+1*4+mat_offset] = 0; - mat[3+2*4+mat_offset] = 0; + m[3+0*4+m_offset] = 0; + m[3+1*4+m_offset] = 0; + m[3+2*4+m_offset] = 0; + m[3+3*4+m_offset] = 1; - mat[0+3*4+mat_offset] = 0; - mat[1+3*4+mat_offset] = 0; - mat[2+3*4+mat_offset] = 0; - mat[3+3*4+mat_offset] = 1; + return m; } /** * Make given matrix the orthogonal matrix based on given parameters. - * - * @param a 4x4 matrix in column-major order (also result) - * @param a_off - * @param initA if true, given matrix will be initialized w/ identity matrix. + * <pre> + Ortho matrix (Column Order): + 2/dx 0 0 0 + 0 2/dy 0 0 + 0 0 2/dz 0 + tx ty tz 1 + * </pre> + * <p> + * All matrix fields are only set if <code>initM</code> is <code>true</code>. + * </p> + * @param m 4x4 matrix in column-major order (also result) + * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix + * @param initM if true, given matrix will be initialized w/ identity matrix, + * otherwise only the orthogonal fields are set. * @param left * @param right * @param bottom @@ -214,18 +438,31 @@ public class FloatUtil { * @param zFar * @return given matrix for chaining */ - public static final float[] makeOrthof(final float[] a, final int a_off, final boolean initA, - final float left, final float right, - final float bottom, final float top, - final float zNear, final float zFar) { - if( initA ) { - FloatUtil.makeIdentityf(a, a_off); - } - // Ortho matrix (Column Order): - // 2/dx 0 0 0 - // 0 2/dy 0 0 - // 0 0 2/dz 0 - // tx ty tz 1 + public static float[] makeOrtho(final float[] m, final int m_offset, final boolean initM, + final float left, final float right, + final float bottom, final float top, + final float zNear, final float zFar) { + if( initM ) { + // m[m_offset+0+4*0] = 1f; + m[m_offset+1+4*0] = 0f; + m[m_offset+2+4*0] = 0f; + m[m_offset+3+4*0] = 0f; + + m[m_offset+0+4*1] = 0f; + // m[m_offset+1+4*1] = 1f; + m[m_offset+2+4*1] = 0f; + m[m_offset+3+4*1] = 0f; + + m[m_offset+0+4*2] = 0f; + m[m_offset+1+4*2] = 0f; + // m[m_offset+2+4*2] = 1f; + m[m_offset+3+4*2] = 0f; + + // m[m_offset+0+4*3] = 0f; + // m[m_offset+1+4*3] = 0f; + // m[m_offset+2+4*3] = 0f; + // m[m_offset+3+4*3] = 1f; + } final float dx=right-left; final float dy=top-bottom; final float dz=zFar-zNear; @@ -233,22 +470,37 @@ public class FloatUtil { final float ty=-1.0f*(top+bottom)/dy; final float tz=-1.0f*(zFar+zNear)/dz; - a[a_off+0+4*0] = 2.0f/dx; - a[a_off+1+4*1] = 2.0f/dy; - a[a_off+2+4*2] = -2.0f/dz; - a[a_off+0+4*3] = tx; - a[a_off+1+4*3] = ty; - a[a_off+2+4*3] = tz; + m[m_offset+0+4*0] = 2.0f/dx; - return a; + m[m_offset+1+4*1] = 2.0f/dy; + + m[m_offset+2+4*2] = -2.0f/dz; + + m[m_offset+0+4*3] = tx; + m[m_offset+1+4*3] = ty; + m[m_offset+2+4*3] = tz; + m[m_offset+3+4*3] = 1f; + + return m; } /** * Make given matrix the frustum matrix based on given parameters. + * <pre> + Frustum matrix (Column Order): + 2*zNear/dx 0 0 0 + 0 2*zNear/dy 0 0 + A B C -1 + 0 0 D 0 + * </pre> + * <p> + * All matrix fields are only set if <code>initM</code> is <code>true</code>. + * </p> * - * @param a 4x4 matrix in column-major order (also result) - * @param a_off - * @param initA if true, given matrix will be initialized w/ identity matrix. + * @param m 4x4 matrix in column-major order (also result) + * @param m_offset offset in given array <i>m</i>, 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 left * @param right * @param bottom @@ -257,24 +509,37 @@ public class FloatUtil { * @param zFar * @return given matrix for chaining */ - public static final float[] makeFrustumf(final float[] a, final int a_off, final boolean initA, - final float left, final float right, - final float bottom, final float top, - final float zNear, final float zFar) { + public static float[] makeFrustum(final float[] m, final int m_offset, final boolean initM, + final float left, final float right, + final float bottom, final float top, + final float zNear, final float zFar) { if(zNear<=0.0f||zFar<0.0f) { throw new GLException("GL_INVALID_VALUE: zNear and zFar must be positive, and zNear>0"); } if(left==right || top==bottom) { throw new GLException("GL_INVALID_VALUE: top,bottom and left,right must not be equal"); } - if( initA ) { - FloatUtil.makeIdentityf(a, a_off); + if( initM ) { + // m[m_offset+0+4*0] = 1f; + m[m_offset+1+4*0] = 0f; + m[m_offset+2+4*0] = 0f; + m[m_offset+3+4*0] = 0f; + + m[m_offset+0+4*1] = 0f; + // m[m_offset+1+4*1] = 1f; + m[m_offset+2+4*1] = 0f; + m[m_offset+3+4*1] = 0f; + + // m[m_offset+0+4*2] = 0f; + // m[m_offset+1+4*2] = 0f; + // m[m_offset+2+4*2] = 1f; + // m[m_offset+3+4*2] = 0f; + + m[m_offset+0+4*3] = 0f; + m[m_offset+1+4*3] = 0f; + // m[m_offset+2+4*3] = 0f; + // m[m_offset+3+4*3] = 1f; } - // Frustum matrix (Column Order): - // 2*zNear/dx 0 0 0 - // 0 2*zNear/dy 0 0 - // A B C -1 - // 0 0 D 0 final float zNear2 = 2.0f*zNear; final float dx=right-left; final float dy=top-bottom; @@ -284,37 +549,875 @@ public class FloatUtil { final float C=-1.0f*(zFar+zNear)/dz; final float D=-2.0f*(zFar*zNear)/dz; - a[a_off+0+4*0] = zNear2/dx; - a[a_off+1+4*1] = zNear2/dy; - a[a_off+2+4*2] = C; + m[m_offset+0+4*0] = zNear2/dx; + + m[m_offset+1+4*1] = zNear2/dy; + + m[m_offset+0+4*2] = A; + m[m_offset+1+4*2] = B; + m[m_offset+2+4*2] = C; + m[m_offset+3+4*2] = -1.0f; - a[a_off+0+4*2] = A; - a[a_off+1+4*2] = B; + m[m_offset+2+4*3] = D; + m[m_offset+3+4*3] = 0f; - a[a_off+2+4*3] = D; - a[a_off+3+4*2] = -1.0f; - return a; + return m; } /** * Make given matrix the perspective matrix based on given parameters. + * <p> + * All matrix fields are only set if <code>initM</code> is <code>true</code>. + * </p> * - * @param a 4x4 matrix in column-major order (also result) - * @param a_off - * @param initA if true, given matrix will be initialized w/ identity matrix. + * @param m 4x4 matrix in column-major order (also result) + * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix + * @param initM if true, given matrix will be initialized w/ identity matrix, + * otherwise only the non-zero fields are set. * @param fovy angle in radians * @param aspect * @param zNear * @param zFar * @return given matrix for chaining */ - public static final float[] makePerspective(final float[] a, final int a_off, final boolean initA, - final float fovy, final float aspect, final float zNear, final float zFar) { + public static float[] makePerspective(final float[] m, final int m_off, final boolean initM, + final float fovy, final float aspect, final float zNear, final float zFar) { float top=(float)Math.tan(fovy)*zNear; float bottom=-1.0f*top; float left=aspect*bottom; float right=aspect*top; - return makeFrustumf(a, a_off, initA, left, right, bottom, top, zNear, zFar); + return makeFrustum(m, m_off, initM, left, right, bottom, top, zNear, zFar); + } + + /** + * Make given matrix the <i>look-at</i> matrix based on given parameters. + * <p> + * Consist out of two matrix multiplications: + * <pre> + * <b>R</b> = <b>L</b> x <b>T</b>, + * with <b>L</b> for <i>look-at</i> matrix and + * <b>T</b> for eye translation. + * + * Result <b>R</b> can be utilized for <i>modelview</i> multiplication, i.e. + * <b>M</b> = <b>M</b> x <b>R</b>, + * with <b>M</b> being the <i>modelview</i> matrix. + * </pre> + * </p> + * <p> + * All matrix fields are set. + * </p> + * @param m 4x4 matrix in column-major order, result only + * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix + * @param eye 3 component eye vector + * @param eye_offset + * @param center 3 component center vector + * @param center_offset + * @param up 3 component up vector + * @param up_offset + * @param mat4Tmp temp float[16] storage + * @return given matrix <code>m</code> for chaining + */ + public static float[] makeLookAt(final float[] m, final int m_offset, + final float[] eye, final int eye_offset, + final float[] center, final int center_offset, + final float[] up, final int up_offset, + final float[] mat4Tmp) { + final int forward_off = 0; + final int side_off = 3; + final int up2_off = 6; + + // forward! + mat4Tmp[0] = center[0+center_offset] - eye[0+eye_offset]; + mat4Tmp[1] = center[1+center_offset] - eye[1+eye_offset]; + mat4Tmp[2] = center[2+center_offset] - eye[2+eye_offset]; + + VectorUtil.normalizeVec3(mat4Tmp); // normalize forward + + /* Side = forward x up */ + VectorUtil.crossVec3(mat4Tmp, side_off, mat4Tmp, forward_off, up, up_offset); + VectorUtil.normalizeVec3(mat4Tmp, side_off); // normalize side + + /* Recompute up as: up = side x forward */ + VectorUtil.crossVec3(mat4Tmp, up2_off, mat4Tmp, side_off, mat4Tmp, forward_off); + + m[m_offset + 0 * 4 + 0] = mat4Tmp[0+side_off]; // side + m[m_offset + 1 * 4 + 0] = mat4Tmp[1+side_off]; // side + m[m_offset + 2 * 4 + 0] = mat4Tmp[2+side_off]; // side + m[m_offset + 3 * 4 + 0] = 0; + + m[m_offset + 0 * 4 + 1] = mat4Tmp[0+up2_off]; // up2 + m[m_offset + 1 * 4 + 1] = mat4Tmp[1+up2_off]; // up2 + m[m_offset + 2 * 4 + 1] = mat4Tmp[2+up2_off]; // up2 + m[m_offset + 3 * 4 + 1] = 0; + + m[m_offset + 0 * 4 + 2] = -mat4Tmp[0]; // forward + m[m_offset + 1 * 4 + 2] = -mat4Tmp[1]; // forward + m[m_offset + 2 * 4 + 2] = -mat4Tmp[2]; // forward + m[m_offset + 3 * 4 + 2] = 0; + + m[m_offset + 0 * 4 + 3] = 0; + m[m_offset + 1 * 4 + 3] = 0; + m[m_offset + 2 * 4 + 3] = 0; + m[m_offset + 3 * 4 + 3] = 1; + + makeTranslation(mat4Tmp, true, -eye[0+eye_offset], -eye[1+eye_offset], -eye[2+eye_offset]); + multMatrix(m, m_offset, mat4Tmp, 0); + + return m; + } + + /** + * Make given matrix the <i>pick</i> matrix based on given parameters. + * <p> + * Traditional <code>gluPickMatrix</code> implementation. + * </p> + * <p> + * Consist out of two matrix multiplications: + * <pre> + * <b>R</b> = <b>T</b> x <b>S</b>, + * with <b>T</b> for viewport translation matrix and + * <b>S</b> for viewport scale matrix. + * + * Result <b>R</b> can be utilized for <i>projection</i> multiplication, i.e. + * <b>P</b> = <b>P</b> x <b>R</b>, + * with <b>P</b> being the <i>projection</i> matrix. + * </pre> + * </p> + * <p> + * All matrix fields are set. + * </p> + * @param m 4x4 matrix in column-major order, result only + * @param m_offset offset in given array <i>m</i>, i.e. start of the 4x4 matrix + * @param x + * @param y + * @param deltaX + * @param deltaY + * @param viewport 4 component viewport vector + * @param viewport_offset + * @param mat4Tmp temp float[16] storage + * @return given matrix <code>m</code> for chaining or <code>null</code> if either delta value is <= zero. + */ + public static float[] makePick(final float[] m, final int m_offset, + final float x, final float y, + final float deltaX, final float deltaY, + final int[] viewport, final int viewport_offset, + final float[] mat4Tmp) { + if (deltaX <= 0 || deltaY <= 0) { + return null; + } + + /* Translate and scale the picked region to the entire window */ + makeTranslation(m, m_offset, true, + (viewport[2+viewport_offset] - 2 * (x - viewport[0+viewport_offset])) / deltaX, + (viewport[3+viewport_offset] - 2 * (y - viewport[1+viewport_offset])) / deltaY, + 0); + makeScale(mat4Tmp, true, + viewport[2+viewport_offset] / deltaX, viewport[3+viewport_offset] / deltaY, 1.0f); + multMatrix(m, m_offset, mat4Tmp, 0); + return m; + } + + /** + * Transpose the given matrix. + * + * @param msrc 4x4 matrix in column-major order, the source + * @param msrc_offset offset in given array <i>msrc</i>, i.e. start of the 4x4 matrix + * @param mres 4x4 matrix in column-major order, the result - may be <code>msrc</code> (in-place) + * @param mres_offset offset in given array <i>mres</i>, i.e. start of the 4x4 matrix - may be <code>msrc_offset</code> (in-place) + * @return given result matrix <i>mres</i> for chaining + */ + public static float[] transposeMatrix(final float[] msrc, final int msrc_offset, final float[] mres, final int mres_offset) { + for (int i = 0; i < 4; i++) { + final int i4 = i*4; + for (int j = 0; j < 4; j++) { + mres[mres_offset+j+i4] = msrc[msrc_offset+i+j*4]; + } + } + return mres; + } + + /** + * Transpose the given matrix in place. + * + * @param m 4x4 matrix in column-major order, the source + * @param m_offset offset in given array <i>msrc</i>, i.e. start of the 4x4 matrix + * @param temp temporary 4*4 float storage + * @return given result matrix <i>m</i> for chaining + */ + public static float[] transposeMatrix(final float[] m, final int m_offset, final float[/*4*4*/] temp) { + int i, j; + for (i = 0; i < 4; i++) { + final int i4 = i*4; + for (j = 0; j < 4; j++) { + temp[i4+j] = m[i4+j+m_offset]; + } + } + for (i = 0; i < 4; i++) { + final int i4 = i*4; + for (j = 0; j < 4; j++) { + m[m_offset+j+i4] = temp[i+j*4]; + } + } + return m; + } + + /** + * Transpose the given matrix. + * + * @param msrc 4x4 matrix in column-major order, the source + * @param mres 4x4 matrix in column-major order, the result - may be <code>msrc</code> (in-place) + * @return given result matrix <i>mres</i> for chaining + */ + public static FloatBuffer transposeMatrix(final FloatBuffer msrc, final FloatBuffer mres) { + final int msrc_offset = msrc.position(); + final int mres_offset = mres.position(); + for (int i = 0; i < 4; i++) { + final int i4 = i*4; + for (int j = 0; j < 4; j++) { + mres.put(mres_offset+j+i4, msrc.get(msrc_offset+i+j*4)); + } + } + return mres; + } + + /** + * Transpose the given matrix in place. + * + * @param m 4x4 matrix in column-major order, the source + * @param temp temporary 4*4 float storage + * @return given matrix <i>m</i> for chaining + */ + public static FloatBuffer transposeMatrix(FloatBuffer m, final float[/*4*4*/] temp) { + final int m_offset = m.position(); + int i, j; + for (i = 0; i < 4; i++) { + final int i4 = i*4; + for (j = 0; j < 4; j++) { + temp[i4+j] = m.get(i4+j+m_offset); + } + } + for (i = 0; i < 4; i++) { + final int i4 = i*4; + for (j = 0; j < 4; j++) { + m.put(m_offset+j+i4, temp[i+j*4]); + } + } + return m; + } + + /** + * Invert the given matrix. + * <p> + * Returns <code>null</code> if inversion is not possible, + * e.g. matrix is singular due to a bad matrix. + * </p> + * + * @param msrc 4x4 matrix in column-major order, the source + * @param msrc_offset offset in given array <i>msrc</i>, i.e. start of the 4x4 matrix + * @param mres 4x4 matrix in column-major order, the result - may be <code>msrc</code> (in-place) + * @param mres_offset offset in given array <i>mres</i>, i.e. start of the 4x4 matrix - may be <code>msrc_offset</code> (in-place) + * @param temp temporary 4*4 float storage + * @return given result matrix <i>mres</i> for chaining if successful, otherwise <code>null</code>. See above. + */ + public static float[] invertMatrix(final float[] msrc, final int msrc_offset, final float[] mres, final int mres_offset, final float[/*4*4*/] temp) { + int i, j, k, swap; + float t; + for (i = 0; i < 4; i++) { + final int i4 = i*4; + for (j = 0; j < 4; j++) { + temp[i4+j] = msrc[i4+j+msrc_offset]; + } + } + makeIdentity(mres, mres_offset); + + for (i = 0; i < 4; i++) { + final int i4 = i*4; + + // + // Look for largest element in column + // + swap = i; + for (j = i + 1; j < 4; j++) { + if (Math.abs(temp[j*4+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; + } + + /** + * Invert the given matrix. + * <p> + * Returns <code>null</code> if inversion is not possible, + * e.g. matrix is singular due to a bad matrix. + * </p> + * + * @param msrc 4x4 matrix in column-major order, the source + * @param mres 4x4 matrix in column-major order, the result - may be <code>msrc</code> (in-place) + * @param temp temporary 4*4 float storage + * @return given result matrix <i>mres</i> for chaining if successful, otherwise <code>null</code>. See above. + */ + public static FloatBuffer invertMatrix(final FloatBuffer msrc, final FloatBuffer mres, final float[/*4*4*/] temp) { + int i, j, k, swap; + float t; + + final int msrc_offset = msrc.position(); + final int mres_offset = mres.position(); + + for (i = 0; i < 4; i++) { + final int i4 = i*4; + for (j = 0; j < 4; j++) { + temp[i4+j] = msrc.get(i4+j + msrc_offset); + } + } + makeIdentity(mres); + + for (i = 0; i < 4; i++) { + final int i4 = i*4; + + // + // Look for largest element in column + // + swap = i; + for (j = i + 1; j < 4; j++) { + if (Math.abs(temp[j*4+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.get(i4+k + mres_offset); + mres.put(i4+k + mres_offset, mres.get(swap4+k + mres_offset)); + mres.put(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; + final int z = i4+k + mres_offset; + mres.put(z, mres.get(z) / 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; + final int z = j4+k + mres_offset; + mres.put(z, mres.get(z) - mres.get(i4+k + mres_offset) * t); + } + } + } + } + return mres; + } + + + /** + * Map object coordinates to window coordinates. + * <p> + * Traditional <code>gluProject</code> implementation. + * </p> + * + * @param objx + * @param objy + * @param objz + * @param modelMatrix 4x4 modelview matrix + * @param modelMatrix_offset + * @param projMatrix 4x4 projection matrix + * @param projMatrix_offset + * @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[] modelMatrix, final int modelMatrix_offset, + final float[] projMatrix, final int projMatrix_offset, + final int[] viewport, final int viewport_offset, + final float[] win_pos, int win_pos_offset, + final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) { + vec4Tmp1[0] = objx; + vec4Tmp1[1] = objy; + vec4Tmp1[2] = objz; + vec4Tmp1[3] = 1.0f; + + // vec4Tmp2 = Mv * o + // vec4Tmp1 = P * vec4Tmp2 + // vec4Tmp1 = P * ( Mv * o ) + // vec4Tmp1 = P * Mv * o + multMatrixVec(modelMatrix, modelMatrix_offset, vec4Tmp1, 0, vec4Tmp2, 0); + multMatrixVec(projMatrix, projMatrix_offset, vec4Tmp2, 0, vec4Tmp1, 0); + + if (vec4Tmp1[3] == 0.0f) { + return false; + } + + vec4Tmp1[3] = (1.0f / vec4Tmp1[3]) * 0.5f; + + // Map x, y and z to range 0-1 + vec4Tmp1[0] = vec4Tmp1[0] * vec4Tmp1[3] + 0.5f; + vec4Tmp1[1] = vec4Tmp1[1] * vec4Tmp1[3] + 0.5f; + 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]; + + return true; + } + + /** + * Map object coordinates to window coordinates. + * <p> + * Traditional <code>gluProject</code> implementation. + * </p> + * + * @param objx + * @param objy + * @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, int win_pos_offset, + final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) { + vec4Tmp2[0] = objx; + vec4Tmp2[1] = objy; + vec4Tmp2[2] = objz; + vec4Tmp2[3] = 1.0f; + + // vec4Tmp1 = P * Mv * o + multMatrixVec(mat4PMv, vec4Tmp2, vec4Tmp1); + + if (vec4Tmp1[3] == 0.0f) { + return false; + } + + vec4Tmp1[3] = (1.0f / vec4Tmp1[3]) * 0.5f; + + // Map x, y and z to range 0-1 + vec4Tmp1[0] = vec4Tmp1[0] * vec4Tmp1[3] + 0.5f; + vec4Tmp1[1] = vec4Tmp1[1] * vec4Tmp1[3] + 0.5f; + 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]; + + return true; + } + + /** + * Map window coordinates to object coordinates. + * <p> + * Traditional <code>gluUnProject</code> implementation. + * </p> + * + * @param winx + * @param winy + * @param winz + * @param modelMatrix 4x4 modelview matrix + * @param modelMatrix_offset + * @param projMatrix 4x4 projection matrix + * @param projMatrix_offset + * @param viewport 4 component viewport vector + * @param viewport_offset + * @param obj_pos 3 component object coordinate, the result + * @param obj_pos_offset + * @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 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) { + // mat4Tmp1 = P x Mv + multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0); + + // mat4Tmp1 = Inv(P x Mv) + if ( null == invertMatrix(mat4Tmp1, 0, mat4Tmp1, 0, mat4Tmp2) ) { + return false; + } + mat4Tmp2[0] = winx; + mat4Tmp2[1] = winy; + mat4Tmp2[2] = winz; + mat4Tmp2[3] = 1.0f; + + // Map x and y from window coordinates + mat4Tmp2[0] = (mat4Tmp2[0] - viewport[0+viewport_offset]) / viewport[2+viewport_offset]; + mat4Tmp2[1] = (mat4Tmp2[1] - viewport[1+viewport_offset]) / viewport[3+viewport_offset]; + + // Map to range -1 to 1 + mat4Tmp2[0] = mat4Tmp2[0] * 2 - 1; + mat4Tmp2[1] = mat4Tmp2[1] * 2 - 1; + mat4Tmp2[2] = mat4Tmp2[2] * 2 - 1; + + final int raw_off = 4; + // object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2 + multMatrixVec(mat4Tmp1, 0, mat4Tmp2, 0, mat4Tmp2, raw_off); + + if (mat4Tmp2[3+raw_off] == 0.0) { + return false; + } + + mat4Tmp2[3+raw_off] = 1.0f / mat4Tmp2[3+raw_off]; + + obj_pos[0+obj_pos_offset] = mat4Tmp2[0+raw_off] * mat4Tmp2[3+raw_off]; + obj_pos[1+obj_pos_offset] = mat4Tmp2[1+raw_off] * mat4Tmp2[3+raw_off]; + obj_pos[2+obj_pos_offset] = mat4Tmp2[2+raw_off] * mat4Tmp2[3+raw_off]; + + return true; + } + + /** + * Map window coordinates to object coordinates. + * <p> + * Traditional <code>gluUnProject</code> implementation. + * </p> + * + * @param winx + * @param winy + * @param winz + * @param mat4PMvI inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv) + * @param viewport 4 component viewport vector + * @param viewport_offset + * @param obj_pos 3 component object coordinate, the result + * @param obj_pos_offset + * @param vec4Tmp1 4 component vector for temp storage + * @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) { + vec4Tmp1[0] = winx; + vec4Tmp1[1] = winy; + vec4Tmp1[2] = winz; + 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]; + + // Map to range -1 to 1 + vec4Tmp1[0] = vec4Tmp1[0] * 2 - 1; + vec4Tmp1[1] = vec4Tmp1[1] * 2 - 1; + vec4Tmp1[2] = vec4Tmp1[2] * 2 - 1; + + // object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2 + multMatrixVec(mat4PMvI, vec4Tmp1, vec4Tmp2); + + if (vec4Tmp2[3] == 0.0) { + return false; + } + + vec4Tmp2[3] = 1.0f / vec4Tmp2[3]; + + obj_pos[0+obj_pos_offset] = vec4Tmp2[0] * vec4Tmp2[3]; + obj_pos[1+obj_pos_offset] = vec4Tmp2[1] * vec4Tmp2[3]; + obj_pos[2+obj_pos_offset] = vec4Tmp2[2] * vec4Tmp2[3]; + + return true; + } + + /** + * Map two window coordinates to two object coordinates, + * distinguished by their z component. + * + * @param winx + * @param winy + * @param winz1 + * @param winz2 + * @param mat4PMvI inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv) + * @param viewport 4 component viewport vector + * @param viewport_offset + * @param obj1_pos 3 component object coordinate, the result for winz1 + * @param obj1_pos_offset + * @param obj2_pos 3 component object coordinate, the result for winz2 + * @param obj2_pos_offset + * @param vec4Tmp1 4 component vector for temp storage + * @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) { + 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]; + + // Map to range -1 to 1 + vec4Tmp1[0] = vec4Tmp1[0] * 2 - 1; + vec4Tmp1[1] = vec4Tmp1[1] * 2 - 1; + + // + // winz1 + // + vec4Tmp1[2] = winz1; + vec4Tmp1[2] = vec4Tmp1[2] * 2 - 1; + + // object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2 + multMatrixVec(mat4PMvI, vec4Tmp1, vec4Tmp2); + + if (vec4Tmp2[3] == 0.0) { + return false; + } + + 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]; + + // + // winz2 + // + vec4Tmp1[2] = winz2; + vec4Tmp1[2] = vec4Tmp1[2] * 2 - 1; + + // object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2 + multMatrixVec(mat4PMvI, vec4Tmp1, vec4Tmp2); + + if (vec4Tmp2[3] == 0.0) { + return false; + } + + 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]; + + return true; + } + + /** + * Map window coordinates to object coordinates. + * <p> + * Traditional <code>gluUnProject4</code> implementation. + * </p> + * + * @param winx + * @param winy + * @param winz + * @param clipw + * @param modelMatrix 4x4 modelview matrix + * @param modelMatrix_offset + * @param projMatrix 4x4 projection matrix + * @param projMatrix_offset + * @param viewport 4 component viewport vector + * @param viewport_offset + * @param near + * @param far + * @param obj_pos 4 component object coordinate, the result + * @param obj_pos_offset + * @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 infinity due to zero z) + */ + public static boolean mapWinToObjCoords(final float winx, final float winy, final float winz, final float clipw, + float[] modelMatrix, int modelMatrix_offset, + float[] projMatrix, int projMatrix_offset, + int[] viewport, int viewport_offset, + float near, float far, + float[] obj_pos, 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); + + // mat4Tmp1 = Inv(P x Mv) + if ( null == invertMatrix(mat4Tmp1, 0, mat4Tmp1, 0, mat4Tmp2) ) { + return false; + } + + mat4Tmp2[0] = winx; + mat4Tmp2[1] = winy; + mat4Tmp2[2] = winz; + mat4Tmp2[3] = 1.0f; + + // Map x and y from window coordinates + mat4Tmp2[0] = (mat4Tmp2[0] - viewport[0+viewport_offset]) / viewport[2+viewport_offset]; + mat4Tmp2[1] = (mat4Tmp2[1] - viewport[1+viewport_offset]) / viewport[3+viewport_offset]; + mat4Tmp2[2] = (mat4Tmp2[2] - near) / (far - near); + + // Map to range -1 to 1 + mat4Tmp2[0] = mat4Tmp2[0] * 2 - 1; + mat4Tmp2[1] = mat4Tmp2[1] * 2 - 1; + mat4Tmp2[2] = mat4Tmp2[2] * 2 - 1; + + final int raw_off = 4; + // object raw coords = Inv(P x Mv) * winPos -> mat4Tmp2 + multMatrixVec(mat4Tmp1, 0, mat4Tmp2, 0, mat4Tmp2, raw_off); + + if (mat4Tmp2[3+raw_off] == 0.0) { + 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]; + obj_pos[3+obj_pos_offset] = mat4Tmp2[3+raw_off]; + + return true; + } + + + /** + * Map two window coordinates w/ shared X/Y and distinctive Z + * to a {@link Ray}. The resulting {@link Ray} maybe used for <i>picking</i> + * using a {@link AABBox#getRayIntersection(Ray, float[]) bounding box}. + * <p> + * Notes for picking <i>winz0</i> and <i>winz1</i>: + * <ul> + * <li>see {@link #getZBufferEpsilon(int, float, float)}</li> + * <li>see {@link #getZBufferValue(int, float, float, float)}</li> + * <li>see {@link #getOrthoWinZ(float, float, float)}</li> + * </ul> + * </p> + * @param winx + * @param winy + * @param winz0 + * @param winz1 + * @param modelMatrix 4x4 modelview matrix + * @param modelMatrix_offset + * @param projMatrix 4x4 projection matrix + * @param projMatrix_offset + * @param viewport 4 component viewport vector + * @param viewport_offset + * @param ray storage for the resulting {@link Ray} + * @param mat4Tmp1 16 component matrix for temp storage + * @param mat4Tmp2 16 component matrix for temp storage + * @param vec4Tmp2 4 component vector 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 float[] modelMatrix, final int modelMatrix_offset, + final float[] projMatrix, final int projMatrix_offset, + final int[] viewport, final int viewport_offset, + final Ray ray, + final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2, final float[/*4*/] vec4Tmp2) { + // mat4Tmp1 = P x Mv + multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0); + + // mat4Tmp1 = Inv(P x Mv) + if ( null == invertMatrix(mat4Tmp1, 0, mat4Tmp1, 0, mat4Tmp2) ) { + 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) ); + return true; + } else { + return false; + } + } + + /** + * Multiply matrix: [d] = [a] x [b] + * @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 + */ + public static void multMatrix(final float[] a, final int a_off, final float[] b, final int b_off, float[] d, final int d_off) { + for (int i = 0; i < 4; i++) { + // one row in column-major order + final int a_off_i = a_off+i; + final int d_off_i = d_off+i; + final float ai0=a[a_off_i+0*4], ai1=a[a_off_i+1*4], ai2=a[a_off_i+2*4], ai3=a[a_off_i+3*4]; // row-i of a + d[d_off_i+0*4] = ai0 * b[b_off+0+0*4] + ai1 * b[b_off+1+0*4] + ai2 * b[b_off+2+0*4] + ai3 * b[b_off+3+0*4] ; + d[d_off_i+1*4] = ai0 * b[b_off+0+1*4] + ai1 * b[b_off+1+1*4] + ai2 * b[b_off+2+1*4] + ai3 * b[b_off+3+1*4] ; + d[d_off_i+2*4] = ai0 * b[b_off+0+2*4] + ai1 * b[b_off+1+2*4] + ai2 * b[b_off+2+2*4] + ai3 * b[b_off+3+2*4] ; + d[d_off_i+3*4] = ai0 * b[b_off+0+3*4] + ai1 * b[b_off+1+3*4] + ai2 * b[b_off+2+3*4] + ai3 * b[b_off+3+3*4] ; + } } /** @@ -323,14 +1426,14 @@ public class FloatUtil { * @param b 4x4 matrix in column-major order * @param d result a*b in column-major order */ - public static final void multMatrixf(final float[] a, int a_off, final float[] b, int b_off, float[] d, int d_off) { + public static void multMatrix(final float[] a, final float[] b, float[] d) { for (int i = 0; i < 4; i++) { // one row in column-major order - final float ai0=a[a_off+i+0*4], ai1=a[a_off+i+1*4], ai2=a[a_off+i+2*4], ai3=a[a_off+i+3*4]; // row-i of a - d[d_off+i+0*4] = ai0 * b[b_off+0+0*4] + ai1 * b[b_off+1+0*4] + ai2 * b[b_off+2+0*4] + ai3 * b[b_off+3+0*4] ; - d[d_off+i+1*4] = ai0 * b[b_off+0+1*4] + ai1 * b[b_off+1+1*4] + ai2 * b[b_off+2+1*4] + ai3 * b[b_off+3+1*4] ; - d[d_off+i+2*4] = ai0 * b[b_off+0+2*4] + ai1 * b[b_off+1+2*4] + ai2 * b[b_off+2+2*4] + ai3 * b[b_off+3+2*4] ; - d[d_off+i+3*4] = ai0 * b[b_off+0+3*4] + ai1 * b[b_off+1+3*4] + ai2 * b[b_off+2+3*4] + ai3 * b[b_off+3+3*4] ; + final float ai0=a[i+0*4], ai1=a[i+1*4], ai2=a[i+2*4], ai3=a[i+3*4]; // row-i of a + d[i+0*4] = ai0 * b[0+0*4] + ai1 * b[1+0*4] + ai2 * b[2+0*4] + ai3 * b[3+0*4] ; + d[i+1*4] = ai0 * b[0+1*4] + ai1 * b[1+1*4] + ai2 * b[2+1*4] + ai3 * b[3+1*4] ; + d[i+2*4] = ai0 * b[0+2*4] + ai1 * b[1+2*4] + ai2 * b[2+2*4] + ai3 * b[3+2*4] ; + d[i+3*4] = ai0 * b[0+3*4] + ai1 * b[1+3*4] + ai2 * b[2+3*4] + ai3 * b[3+3*4] ; } } @@ -339,7 +1442,7 @@ public class FloatUtil { * @param a 4x4 matrix in column-major order (also result) * @param b 4x4 matrix in column-major order */ - public static final void multMatrixf(final float[] a, int a_off, final float[] b, int b_off) { + public static void multMatrix(final float[] a, final int a_off, final float[] b, final int b_off) { for (int i = 0; i < 4; i++) { // one row in column-major order final int a_off_i = a_off+i; @@ -352,20 +1455,38 @@ public 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 + */ + public static void multMatrix(final float[] a, final float[] b) { + for (int i = 0; i < 4; i++) { + // one row in column-major order + final float ai0=a[i+0*4], ai1=a[i+1*4], ai2=a[i+2*4], ai3=a[i+3*4]; // row-i of a + a[i+0*4] = ai0 * b[0+0*4] + ai1 * b[1+0*4] + ai2 * b[2+0*4] + ai3 * b[3+0*4] ; + a[i+1*4] = ai0 * b[0+1*4] + ai1 * b[1+1*4] + ai2 * b[2+1*4] + ai3 * b[3+1*4] ; + a[i+2*4] = ai0 * b[0+2*4] + ai1 * b[1+2*4] + ai2 * b[2+2*4] + ai3 * b[3+2*4] ; + a[i+3*4] = ai0 * b[0+3*4] + ai1 * b[1+3*4] + ai2 * b[2+3*4] + ai3 * b[3+3*4] ; + } + } + + /** * Multiply matrix: [d] = [a] x [b] * @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 */ - public static final void multMatrixf(final float[] a, int a_off, final float[] b, int b_off, FloatBuffer d) { - final int dP = d.position(); + public static void multMatrix(final float[] a, final int a_off, final float[] b, final int b_off, final FloatBuffer d) { + final int d_off = d.position(); for (int i = 0; i < 4; i++) { // one row in column-major order - final float ai0=a[a_off+i+0*4], ai1=a[a_off+i+1*4], ai2=a[a_off+i+2*4], ai3=a[a_off+i+3*4]; // row-i of a - d.put(dP+i+0*4 , ai0 * b[b_off+0+0*4] + ai1 * b[b_off+1+0*4] + ai2 * b[b_off+2+0*4] + ai3 * b[b_off+3+0*4] ); - d.put(dP+i+1*4 , ai0 * b[b_off+0+1*4] + ai1 * b[b_off+1+1*4] + ai2 * b[b_off+2+1*4] + ai3 * b[b_off+3+1*4] ); - d.put(dP+i+2*4 , ai0 * b[b_off+0+2*4] + ai1 * b[b_off+1+2*4] + ai2 * b[b_off+2+2*4] + ai3 * b[b_off+3+2*4] ); - d.put(dP+i+3*4 , ai0 * b[b_off+0+3*4] + ai1 * b[b_off+1+3*4] + ai2 * b[b_off+2+3*4] + ai3 * b[b_off+3+3*4] ); + final int a_off_i = a_off+i; + final int d_off_i = d_off+i; + final float ai0=a[a_off_i+0*4], ai1=a[a_off_i+1*4], ai2=a[a_off_i+2*4], ai3=a[a_off_i+3*4]; // row-i of a + d.put(d_off_i+0*4 , ai0 * b[b_off+0+0*4] + ai1 * b[b_off+1+0*4] + ai2 * b[b_off+2+0*4] + ai3 * b[b_off+3+0*4] ); + d.put(d_off_i+1*4 , ai0 * b[b_off+0+1*4] + ai1 * b[b_off+1+1*4] + ai2 * b[b_off+2+1*4] + ai3 * b[b_off+3+1*4] ); + d.put(d_off_i+2*4 , ai0 * b[b_off+0+2*4] + ai1 * b[b_off+1+2*4] + ai2 * b[b_off+2+2*4] + ai3 * b[b_off+3+2*4] ); + d.put(d_off_i+3*4 , ai0 * b[b_off+0+3*4] + ai1 * b[b_off+1+3*4] + ai2 * b[b_off+2+3*4] + ai3 * b[b_off+3+3*4] ); } } @@ -375,16 +1496,18 @@ public class FloatUtil { * @param b 4x4 matrix in column-major order * @param d result a*b in column-major order */ - public static final void multMatrixf(final FloatBuffer a, final float[] b, int b_off, FloatBuffer d) { - final int aP = a.position(); - final int dP = d.position(); + public static void multMatrix(final FloatBuffer a, final float[] b, final int b_off, final FloatBuffer d) { + final int a_off = a.position(); + final int d_off = d.position(); for (int i = 0; i < 4; i++) { // one row in column-major order - final float ai0=a.get(aP+i+0*4), ai1=a.get(aP+i+1*4), ai2=a.get(aP+i+2*4), ai3=a.get(aP+i+3*4); // row-i of a - d.put(dP+i+0*4 , ai0 * b[b_off+0+0*4] + ai1 * b[b_off+1+0*4] + ai2 * b[b_off+2+0*4] + ai3 * b[b_off+3+0*4] ); - d.put(dP+i+1*4 , ai0 * b[b_off+0+1*4] + ai1 * b[b_off+1+1*4] + ai2 * b[b_off+2+1*4] + ai3 * b[b_off+3+1*4] ); - d.put(dP+i+2*4 , ai0 * b[b_off+0+2*4] + ai1 * b[b_off+1+2*4] + ai2 * b[b_off+2+2*4] + ai3 * b[b_off+3+2*4] ); - d.put(dP+i+3*4 , ai0 * b[b_off+0+3*4] + ai1 * b[b_off+1+3*4] + ai2 * b[b_off+2+3*4] + ai3 * b[b_off+3+3*4] ); + final int a_off_i = a_off+i; + final int d_off_i = d_off+i; + final float ai0=a.get(a_off_i+0*4), ai1=a.get(a_off_i+1*4), ai2=a.get(a_off_i+2*4), ai3=a.get(a_off_i+3*4); // row-i of a + d.put(d_off_i+0*4 , ai0 * b[b_off+0+0*4] + ai1 * b[b_off+1+0*4] + ai2 * b[b_off+2+0*4] + ai3 * b[b_off+3+0*4] ); + d.put(d_off_i+1*4 , ai0 * b[b_off+0+1*4] + ai1 * b[b_off+1+1*4] + ai2 * b[b_off+2+1*4] + ai3 * b[b_off+3+1*4] ); + d.put(d_off_i+2*4 , ai0 * b[b_off+0+2*4] + ai1 * b[b_off+1+2*4] + ai2 * b[b_off+2+2*4] + ai3 * b[b_off+3+2*4] ); + d.put(d_off_i+3*4 , ai0 * b[b_off+0+3*4] + ai1 * b[b_off+1+3*4] + ai2 * b[b_off+2+3*4] + ai3 * b[b_off+3+3*4] ); } } @@ -393,16 +1516,16 @@ public class FloatUtil { * @param a 4x4 matrix in column-major order (also result) * @param b 4x4 matrix in column-major order */ - public static final void multMatrixf(final FloatBuffer a, final float[] b, int b_off) { - final int aP = a.position(); + public static void multMatrix(final FloatBuffer a, final float[] b, final int b_off) { + final int a_off = a.position(); for (int i = 0; i < 4; i++) { // one row in column-major order - final int aP_i = aP+i; - final float ai0=a.get(aP_i+0*4), ai1=a.get(aP_i+1*4), ai2=a.get(aP_i+2*4), ai3=a.get(aP_i+3*4); // row-i of a - a.put(aP_i+0*4 , ai0 * b[b_off+0+0*4] + ai1 * b[b_off+1+0*4] + ai2 * b[b_off+2+0*4] + ai3 * b[b_off+3+0*4] ); - a.put(aP_i+1*4 , ai0 * b[b_off+0+1*4] + ai1 * b[b_off+1+1*4] + ai2 * b[b_off+2+1*4] + ai3 * b[b_off+3+1*4] ); - a.put(aP_i+2*4 , ai0 * b[b_off+0+2*4] + ai1 * b[b_off+1+2*4] + ai2 * b[b_off+2+2*4] + ai3 * b[b_off+3+2*4] ); - a.put(aP_i+3*4 , ai0 * b[b_off+0+3*4] + ai1 * b[b_off+1+3*4] + ai2 * b[b_off+2+3*4] + ai3 * b[b_off+3+3*4] ); + final int a_off_i = a_off+i; + final float ai0=a.get(a_off_i+0*4), ai1=a.get(a_off_i+1*4), ai2=a.get(a_off_i+2*4), ai3=a.get(a_off_i+3*4); // row-i of a + a.put(a_off_i+0*4 , ai0 * b[b_off+0+0*4] + ai1 * b[b_off+1+0*4] + ai2 * b[b_off+2+0*4] + ai3 * b[b_off+3+0*4] ); + a.put(a_off_i+1*4 , ai0 * b[b_off+0+1*4] + ai1 * b[b_off+1+1*4] + ai2 * b[b_off+2+1*4] + ai3 * b[b_off+3+1*4] ); + a.put(a_off_i+2*4 , ai0 * b[b_off+0+2*4] + ai1 * b[b_off+1+2*4] + ai2 * b[b_off+2+2*4] + ai3 * b[b_off+3+2*4] ); + a.put(a_off_i+3*4 , ai0 * b[b_off+0+3*4] + ai1 * b[b_off+1+3*4] + ai2 * b[b_off+2+3*4] + ai3 * b[b_off+3+3*4] ); } } @@ -412,17 +1535,19 @@ public class FloatUtil { * @param b 4x4 matrix in column-major order * @param d result a*b in column-major order */ - public static final void multMatrixf(final FloatBuffer a, final FloatBuffer b, FloatBuffer d) { - final int aP = a.position(); - final int bP = b.position(); - final int dP = d.position(); + public static void multMatrix(final FloatBuffer a, final FloatBuffer b, final FloatBuffer d) { + final int a_off = a.position(); + final int b_off = b.position(); + final int d_off = d.position(); for (int i = 0; i < 4; i++) { // one row in column-major order - final float ai0=a.get(aP+i+0*4), ai1=a.get(aP+i+1*4), ai2=a.get(aP+i+2*4), ai3=a.get(aP+i+3*4); // row-i of a - d.put(dP+i+0*4 , ai0 * b.get(bP+0+0*4) + ai1 * b.get(bP+1+0*4) + ai2 * b.get(bP+2+0*4) + ai3 * b.get(bP+3+0*4) ); - d.put(dP+i+1*4 , ai0 * b.get(bP+0+1*4) + ai1 * b.get(bP+1+1*4) + ai2 * b.get(bP+2+1*4) + ai3 * b.get(bP+3+1*4) ); - d.put(dP+i+2*4 , ai0 * b.get(bP+0+2*4) + ai1 * b.get(bP+1+2*4) + ai2 * b.get(bP+2+2*4) + ai3 * b.get(bP+3+2*4) ); - d.put(dP+i+3*4 , ai0 * b.get(bP+0+3*4) + ai1 * b.get(bP+1+3*4) + ai2 * b.get(bP+2+3*4) + ai3 * b.get(bP+3+3*4) ); + final int a_off_i = a_off+i; + final int d_off_i = d_off+i; + final float ai0=a.get(a_off_i+0*4), ai1=a.get(a_off_i+1*4), ai2=a.get(a_off_i+2*4), ai3=a.get(a_off_i+3*4); // row-i of a + d.put(d_off_i+0*4 , ai0 * b.get(b_off+0+0*4) + ai1 * b.get(b_off+1+0*4) + ai2 * b.get(b_off+2+0*4) + ai3 * b.get(b_off+3+0*4) ); + d.put(d_off_i+1*4 , ai0 * b.get(b_off+0+1*4) + ai1 * b.get(b_off+1+1*4) + ai2 * b.get(b_off+2+1*4) + ai3 * b.get(b_off+3+1*4) ); + d.put(d_off_i+2*4 , ai0 * b.get(b_off+0+2*4) + ai1 * b.get(b_off+1+2*4) + ai2 * b.get(b_off+2+2*4) + ai3 * b.get(b_off+3+2*4) ); + d.put(d_off_i+3*4 , ai0 * b.get(b_off+0+3*4) + ai1 * b.get(b_off+1+3*4) + ai2 * b.get(b_off+2+3*4) + ai3 * b.get(b_off+3+3*4) ); } } @@ -431,17 +1556,17 @@ public class FloatUtil { * @param a 4x4 matrix in column-major order (also result) * @param b 4x4 matrix in column-major order */ - public static final void multMatrixf(final FloatBuffer a, final FloatBuffer b) { - final int aP = a.position(); - final int bP = b.position(); + public static void multMatrix(final FloatBuffer a, final FloatBuffer b) { + final int a_off = a.position(); + final int b_off = b.position(); for (int i = 0; i < 4; i++) { // one row in column-major order - final int aP_i = aP+i; - final float ai0=a.get(aP_i+0*4), ai1=a.get(aP_i+1*4), ai2=a.get(aP_i+2*4), ai3=a.get(aP_i+3*4); // row-i of a - a.put(aP_i+0*4 , ai0 * b.get(bP+0+0*4) + ai1 * b.get(bP+1+0*4) + ai2 * b.get(bP+2+0*4) + ai3 * b.get(bP+3+0*4) ); - a.put(aP_i+1*4 , ai0 * b.get(bP+0+1*4) + ai1 * b.get(bP+1+1*4) + ai2 * b.get(bP+2+1*4) + ai3 * b.get(bP+3+1*4) ); - a.put(aP_i+2*4 , ai0 * b.get(bP+0+2*4) + ai1 * b.get(bP+1+2*4) + ai2 * b.get(bP+2+2*4) + ai3 * b.get(bP+3+2*4) ); - a.put(aP_i+3*4 , ai0 * b.get(bP+0+3*4) + ai1 * b.get(bP+1+3*4) + ai2 * b.get(bP+2+3*4) + ai3 * b.get(bP+3+3*4) ); + final int a_off_i = a_off+i; + final float ai0=a.get(a_off_i+0*4), ai1=a.get(a_off_i+1*4), ai2=a.get(a_off_i+2*4), ai3=a.get(a_off_i+3*4); // row-i of a + a.put(a_off_i+0*4 , ai0 * b.get(b_off+0+0*4) + ai1 * b.get(b_off+1+0*4) + ai2 * b.get(b_off+2+0*4) + ai3 * b.get(b_off+3+0*4) ); + a.put(a_off_i+1*4 , ai0 * b.get(b_off+0+1*4) + ai1 * b.get(b_off+1+1*4) + ai2 * b.get(b_off+2+1*4) + ai3 * b.get(b_off+3+1*4) ); + a.put(a_off_i+2*4 , ai0 * b.get(b_off+0+2*4) + ai1 * b.get(b_off+1+2*4) + ai2 * b.get(b_off+2+2*4) + ai3 * b.get(b_off+3+2*4) ); + a.put(a_off_i+3*4 , ai0 * b.get(b_off+0+3*4) + ai1 * b.get(b_off+1+3*4) + ai2 * b.get(b_off+2+3*4) + ai3 * b.get(b_off+3+3*4) ); } } @@ -451,16 +1576,38 @@ public class FloatUtil { * @param b 4x4 matrix in column-major order * @param d result a*b in column-major order */ - public static final void multMatrixf(final FloatBuffer a, final FloatBuffer b, float[] d, int d_off) { - final int aP = a.position(); - final int bP = b.position(); + public static void multMatrix(final FloatBuffer a, final FloatBuffer b, final float[] d, final int d_off) { + final int a_off = a.position(); + final int b_off = b.position(); for (int i = 0; i < 4; i++) { // one row in column-major order - final float ai0=a.get(aP+i+0*4), ai1=a.get(aP+i+1*4), ai2=a.get(aP+i+2*4), ai3=a.get(aP+i+3*4); // row-i of a - d[d_off+i+0*4] = ai0 * b.get(bP+0+0*4) + ai1 * b.get(bP+1+0*4) + ai2 * b.get(bP+2+0*4) + ai3 * b.get(bP+3+0*4) ; - d[d_off+i+1*4] = ai0 * b.get(bP+0+1*4) + ai1 * b.get(bP+1+1*4) + ai2 * b.get(bP+2+1*4) + ai3 * b.get(bP+3+1*4) ; - d[d_off+i+2*4] = ai0 * b.get(bP+0+2*4) + ai1 * b.get(bP+1+2*4) + ai2 * b.get(bP+2+2*4) + ai3 * b.get(bP+3+2*4) ; - d[d_off+i+3*4] = ai0 * b.get(bP+0+3*4) + ai1 * b.get(bP+1+3*4) + ai2 * b.get(bP+2+3*4) + ai3 * b.get(bP+3+3*4) ; + final int a_off_i = a_off+i; + final int d_off_i = d_off+i; + final float ai0=a.get(a_off_i+0*4), ai1=a.get(a_off_i+1*4), ai2=a.get(a_off_i+2*4), ai3=a.get(a_off_i+3*4); // row-i of a + d[d_off_i+0*4] = ai0 * b.get(b_off+0+0*4) + ai1 * b.get(b_off+1+0*4) + ai2 * b.get(b_off+2+0*4) + ai3 * b.get(b_off+3+0*4) ; + d[d_off_i+1*4] = ai0 * b.get(b_off+0+1*4) + ai1 * b.get(b_off+1+1*4) + ai2 * b.get(b_off+2+1*4) + ai3 * b.get(b_off+3+1*4) ; + d[d_off_i+2*4] = ai0 * b.get(b_off+0+2*4) + ai1 * b.get(b_off+1+2*4) + ai2 * b.get(b_off+2+2*4) + ai3 * b.get(b_off+3+2*4) ; + d[d_off_i+3*4] = ai0 * b.get(b_off+0+3*4) + ai1 * b.get(b_off+1+3*4) + ai2 * b.get(b_off+2+3*4) + ai3 * b.get(b_off+3+3*4) ; + } + } + + /** + * Multiply matrix: [d] = [a] x [b] + * @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 + */ + public static void multMatrix(final FloatBuffer a, final FloatBuffer b, final float[] d) { + final int a_off = a.position(); + final int b_off = b.position(); + for (int i = 0; i < 4; i++) { + // one row in column-major order + final int a_off_i = a_off+i; + final float ai0=a.get(a_off_i+0*4), ai1=a.get(a_off_i+1*4), ai2=a.get(a_off_i+2*4), ai3=a.get(a_off_i+3*4); // row-i of a + d[i+0*4] = ai0 * b.get(b_off+0+0*4) + ai1 * b.get(b_off+1+0*4) + ai2 * b.get(b_off+2+0*4) + ai3 * b.get(b_off+3+0*4) ; + d[i+1*4] = ai0 * b.get(b_off+0+1*4) + ai1 * b.get(b_off+1+1*4) + ai2 * b.get(b_off+2+1*4) + ai3 * b.get(b_off+3+1*4) ; + d[i+2*4] = ai0 * b.get(b_off+0+2*4) + ai1 * b.get(b_off+1+2*4) + ai2 * b.get(b_off+2+2*4) + ai3 * b.get(b_off+3+2*4) ; + d[i+3*4] = ai0 * b.get(b_off+0+3*4) + ai1 * b.get(b_off+1+3*4) + ai2 * b.get(b_off+2+3*4) + ai3 * b.get(b_off+3+3*4) ; } } @@ -470,14 +1617,17 @@ public class FloatUtil { * @param v_in 4-component column-vector * @param v_out m_in * v_in */ - public static final void multMatrixVecf(float[] m_in, int m_in_off, float[] v_in, int v_in_off, float[] v_out, 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) { for (int i = 0; i < 4; i++) { // (one matrix row in column-major order) X (column vector) + final int i_m_in_off = i+m_in_off; v_out[i + v_out_off] = - v_in[0+v_in_off] * m_in[0*4+i+m_in_off] + - v_in[1+v_in_off] * m_in[1*4+i+m_in_off] + - v_in[2+v_in_off] * m_in[2*4+i+m_in_off] + - v_in[3+v_in_off] * m_in[3*4+i+m_in_off]; + v_in[0+v_in_off] * m_in[0*4+i_m_in_off] + + v_in[1+v_in_off] * m_in[1*4+i_m_in_off] + + v_in[2+v_in_off] * m_in[2*4+i_m_in_off] + + v_in[3+v_in_off] * m_in[3*4+i_m_in_off]; } } @@ -487,7 +1637,7 @@ public class FloatUtil { * @param v_in 4-component column-vector * @param v_out m_in * v_in */ - public static final void multMatrixVecf(float[] m_in, float[] v_in, float[] v_out) { + public static void multMatrixVec(final float[] m_in, final float[] v_in, final float[] v_out) { for (int i = 0; i < 4; i++) { // (one matrix row in column-major order) X (column vector) v_out[i] = @@ -503,15 +1653,16 @@ public class FloatUtil { * @param v_in 4-component column-vector * @param v_out m_in * v_in */ - public static final void multMatrixVecf(FloatBuffer m_in, float[] v_in, int v_in_off, float[] v_out, int v_out_off) { - final int matrixPos = m_in.position(); + public static void multMatrixVec(final FloatBuffer m_in, final float[] v_in, final int v_in_off, final float[] v_out, final int v_out_off) { + final int m_in_off = m_in.position(); for (int i = 0; i < 4; i++) { // (one matrix row in column-major order) X (column vector) + final int i_m_in_off = i+m_in_off; v_out[i+v_out_off] = - v_in[0+v_in_off] * m_in.get(0*4+i+matrixPos) + - v_in[1+v_in_off] * m_in.get(1*4+i+matrixPos) + - v_in[2+v_in_off] * m_in.get(2*4+i+matrixPos) + - v_in[3+v_in_off] * m_in.get(3*4+i+matrixPos); + v_in[0+v_in_off] * m_in.get(0*4+i_m_in_off) + + v_in[1+v_in_off] * m_in.get(1*4+i_m_in_off) + + v_in[2+v_in_off] * m_in.get(2*4+i_m_in_off) + + v_in[3+v_in_off] * m_in.get(3*4+i_m_in_off); } } @@ -520,15 +1671,16 @@ public class FloatUtil { * @param v_in 4-component column-vector * @param v_out m_in * v_in */ - public static final void multMatrixVecf(FloatBuffer m_in, float[] v_in, float[] v_out) { - final int matrixPos = m_in.position(); + public static void multMatrixVec(final FloatBuffer m_in, final float[] v_in, final float[] v_out) { + final int m_in_off = m_in.position(); for (int i = 0; i < 4; i++) { // (one matrix row in column-major order) X (column vector) + final int i_m_in_off = i+m_in_off; v_out[i] = - v_in[0] * m_in.get(0*4+i+matrixPos) + - v_in[1] * m_in.get(1*4+i+matrixPos) + - v_in[2] * m_in.get(2*4+i+matrixPos) + - v_in[3] * m_in.get(3*4+i+matrixPos); + v_in[0] * m_in.get(0*4+i_m_in_off) + + v_in[1] * m_in.get(1*4+i_m_in_off) + + v_in[2] * m_in.get(2*4+i_m_in_off) + + v_in[3] * m_in.get(3*4+i_m_in_off); } } @@ -537,17 +1689,18 @@ public class FloatUtil { * @param v_in 4-component column-vector * @param v_out m_in * v_in */ - public static final void multMatrixVecf(FloatBuffer m_in, FloatBuffer v_in, FloatBuffer v_out) { - final int inPos = v_in.position(); - final int outPos = v_out.position(); - final int matrixPos = m_in.position(); + public static void multMatrixVec(final FloatBuffer m_in, final FloatBuffer v_in, final FloatBuffer v_out) { + final int v_in_off = v_in.position(); + final int v_out_off = v_out.position(); + final int m_in_off = m_in.position(); for (int i = 0; i < 4; i++) { // (one matrix row in column-major order) X (column vector) - v_out.put(i + outPos, - v_in.get(0+inPos) * m_in.get(0*4+i+matrixPos) + - v_in.get(1+inPos) * m_in.get(1*4+i+matrixPos) + - v_in.get(2+inPos) * m_in.get(2*4+i+matrixPos) + - v_in.get(3+inPos) * m_in.get(3*4+i+matrixPos)); + final int i_m_in_off = i+m_in_off; + v_out.put(i + v_out_off, + v_in.get(0+v_in_off) * m_in.get(0*4+i_m_in_off) + + v_in.get(1+v_in_off) * m_in.get(1*4+i_m_in_off) + + v_in.get(2+v_in_off) * m_in.get(2*4+i_m_in_off) + + v_in.get(3+v_in_off) * m_in.get(3*4+i_m_in_off)); } } @@ -562,7 +1715,7 @@ public class FloatUtil { * @param v_out the column-vector storage, at least 3 components long * @param v_out_off offset to storage */ - public static final void copyMatrixColumn(final float[] m_in, final int m_in_off, final int column, final float[] v_out, final int v_out_off) { + public static void 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]; @@ -582,7 +1735,7 @@ public class FloatUtil { * @param v_out the row-vector storage, at least 3 components long * @param v_out_off offset to storage */ - public static final void copyMatrixRow(final float[] m_in, final int m_in_off, final int row, final float[] v_out, final int v_out_off) { + public static void 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]; @@ -602,7 +1755,9 @@ public class FloatUtil { * @param row row number to print * @return matrix row string representation */ - public static StringBuilder matrixRowToString(StringBuilder sb, String f, FloatBuffer a, int aOffset, int rows, int columns, boolean rowMajorOrder, int row) { + public static StringBuilder matrixRowToString(StringBuilder sb, final String f, + final FloatBuffer a, final int aOffset, + final int rows, final int columns, final boolean rowMajorOrder, final int row) { if(null == sb) { sb = new StringBuilder(); } @@ -630,7 +1785,8 @@ public class FloatUtil { * @param row row number to print * @return matrix row string representation */ - public static StringBuilder matrixRowToString(StringBuilder sb, String f, float[] a, int aOffset, int rows, int columns, boolean rowMajorOrder, int row) { + public static StringBuilder matrixRowToString(StringBuilder sb, final String f, + final float[] a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder, final int row) { if(null == sb) { sb = new StringBuilder(); } @@ -657,7 +1813,8 @@ public class FloatUtil { * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL) * @return matrix string representation */ - public static StringBuilder matrixToString(StringBuilder sb, String rowPrefix, String f, FloatBuffer a, int aOffset, int rows, int columns, boolean rowMajorOrder) { + public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f, + final FloatBuffer a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder) { if(null == sb) { sb = new StringBuilder(); } @@ -681,7 +1838,8 @@ public class FloatUtil { * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL) * @return matrix string representation */ - public static StringBuilder matrixToString(StringBuilder sb, String rowPrefix, String f, float[] a, int aOffset, int rows, int columns, boolean rowMajorOrder) { + public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f, + final float[] a, final int aOffset, final int rows, final int columns, final boolean rowMajorOrder) { if(null == sb) { sb = new StringBuilder(); } @@ -707,7 +1865,9 @@ public class FloatUtil { * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL) * @return side by side representation */ - public static StringBuilder matrixToString(StringBuilder sb, String rowPrefix, String f, FloatBuffer a, int aOffset, FloatBuffer b, int bOffset, int rows, int columns, boolean rowMajorOrder) { + public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f, + final FloatBuffer a, final int aOffset, final FloatBuffer b, final int bOffset, + final int rows, final int columns, final boolean rowMajorOrder) { if(null == sb) { sb = new StringBuilder(); } @@ -735,7 +1895,9 @@ public class FloatUtil { * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL) * @return side by side representation */ - public static StringBuilder matrixToString(StringBuilder sb, String rowPrefix, String f, float[] a, int aOffset, float[] b, int bOffset, int rows, int columns, boolean rowMajorOrder) { + public static StringBuilder matrixToString(StringBuilder sb, final String rowPrefix, final String f, + final float[] a, final int aOffset, final float[] b, final int bOffset, + final int rows, final int columns, final boolean rowMajorOrder) { if(null == sb) { sb = new StringBuilder(); } @@ -750,6 +1912,10 @@ public class FloatUtil { return sb; } + // + // Scalar Ops + // + @SuppressWarnings("unused") private static void calculateMachineEpsilonFloat() { final long t0; @@ -973,7 +2139,7 @@ public class FloatUtil { public static float getZBufferEpsilon(final int zBits, final float z, final float zNear) { return z * z / ( zNear * ( 1 << zBits ) - z ); } - + /** * Returns Z buffer value of given parameter, * see <a href="http://www.sjbaker.org/steve/omniv/love_your_z_buffer.html">Love Your Z-Buffer</a>. diff --git a/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java b/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java index 319cbad50..502da42c2 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java +++ b/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java @@ -1038,8 +1038,7 @@ public class Quaternion { final float norm = magnitudeSquared(); if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) { // identity matrix -> srecip = 0f - FloatUtil.makeIdentityf(matrix, mat_offset); - return matrix; + return FloatUtil.makeIdentity(matrix, mat_offset); } final float srecip; if ( FloatUtil.isEqual(1f, norm, FloatUtil.EPSILON) ) { @@ -1106,8 +1105,7 @@ public class Quaternion { final float norm = magnitudeSquared(); if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) { // identity matrix -> srecip = 0f - FloatUtil.makeIdentityf(matrix); - return matrix; + return FloatUtil.makeIdentity(matrix); } final float srecip; if ( FloatUtil.isEqual(1f, norm, FloatUtil.EPSILON) ) { diff --git a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java index 7e4f45795..607d8ef9d 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java @@ -29,7 +29,7 @@ package com.jogamp.opengl.math; import java.util.ArrayList; -public class VectorUtil { +public final class VectorUtil { public static final float[] VEC3_ONE = { 1f, 1f, 1f }; public static final float[] VEC3_ZERO = { 0f, 0f, 0f }; @@ -248,11 +248,33 @@ public class VectorUtil { /** * Return the squared length of a vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i> */ + public static float normSquareVec2(final float[] vec, final int offset) { + float v = vec[0+offset]; + float r = v*v; + v = vec[1+offset]; + return r + v*v; + } + + /** + * Return the squared length of a vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i> + */ public static float normSquareVec3(final float[] vec) { return vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]; } /** + * Return the squared length of a vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i> + */ + public static float normSquareVec3(final float[] vec, final int offset) { + float v = vec[0+offset]; + float r = v*v; + v = vec[1+offset]; + r += v*v; + v = vec[2+offset]; + return r + v*v; + } + + /** * Return the length of a vector, a.k.a the <i>norm</i> or <i>magnitude</i> */ public static float normVec2(final float[] vec) { @@ -347,6 +369,26 @@ public class VectorUtil { } /** + * Normalize a vector in place + * @param vector input vector + * @return normalized output vector + */ + public static float[] normalizeVec3(final float[] vector, final int offset) { + final float lengthSq = normSquareVec3(vector, offset); + if ( FloatUtil.isZero(lengthSq, FloatUtil.EPSILON) ) { + vector[0+offset] = 0f; + vector[1+offset] = 0f; + vector[2+offset] = 0f; + } else { + final float invSqr = 1f / FloatUtil.sqrt(lengthSq); + vector[0+offset] *= invSqr; + vector[1+offset] *= invSqr; + vector[2+offset] *= invSqr; + } + return vector; + } + + /** * Scales a vector by param using given result float[] * @param result vector for the result, may be vector (in-place) * @param vector input vector @@ -471,6 +513,20 @@ public class VectorUtil { } /** + * cross product vec1 x vec2 + * @param v1 vector 1 + * @param v2 vector 2 + * @return the resulting vector + */ + public static float[] crossVec3(final float[] r, final int r_offset, final float[] v1, final int v1_offset, final float[] v2, final int v2_offset) + { + r[0+r_offset] = v1[1+v1_offset] * v2[2+v2_offset] - v1[2+v1_offset] * v2[1+v2_offset]; + r[1+r_offset] = v1[2+v1_offset] * v2[0+v2_offset] - v1[0+v1_offset] * v2[2+v2_offset]; + r[2+r_offset] = v1[0+v1_offset] * v2[1+v2_offset] - v1[1+v1_offset] * v2[0+v2_offset]; + return r; + } + + /** * Multiplication of column-major 4x4 matrix with vector * @param colMatrix column matrix (4x4) * @param vec vector(x,y,z) 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 e4c1445ff..d87bbb6f9 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java +++ b/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java @@ -33,7 +33,6 @@ import com.jogamp.opengl.math.FloatUtil; import com.jogamp.opengl.math.Quaternion; import com.jogamp.opengl.math.Ray; import com.jogamp.opengl.math.VectorUtil; -import com.jogamp.opengl.util.PMVMatrix; /** @@ -680,9 +679,9 @@ public class AABBox { * compute the window bounding box. * <p> * If <code>useCenterZ</code> is <code>true</code>, - * only 4 {@link PMVMatrix#gluProject(float, float, float, int[], int, float[], int) gluProject} + * only 4 {@link FloatUtil#mapObjToWinCoords(float, float, float, float[], int[], int, float[], int, float[], float[]) mapObjToWinCoords} * operations are made on points [1..4] using {@link #getCenter()}'s z-value. - * Otherwise 8 {@link PMVMatrix#gluProject(float, float, float, int[], int, float[], int) gluProject} + * Otherwise 8 {@link FloatUtil#mapObjToWinCoords(float, float, float, float[], int[], int, float[], int, float[], float[]) mapObjToWinCoords} * operation on all 8 points are performed. * </p> * <pre> @@ -691,39 +690,53 @@ public class AABBox { * | | * [1] ------ [3] * </pre> - * @param pmv + * @param mat4PMv P x Mv matrix * @param view * @param useCenterZ - * @param tmpV3 TODO + * @param vec3Tmp0 3 component vector for temp storage + * @param vec4Tmp1 4 component vector for temp storage + * @param vec4Tmp2 4 component vector for temp storage * @return */ - public AABBox mapToWindow(final AABBox result, final PMVMatrix pmv, final int[] view, final boolean useCenterZ, float[] tmpV3) { - // System.err.printf("AABBox.mapToWindow.0: view[%d, %d, %d, %d], this %s%n", view[0], view[1], view[2], view[3], toString()); - float objZ = useCenterZ ? center[2] : getMinZ(); - pmv.gluProject(getMinX(), getMinY(), objZ, view, 0, tmpV3, 0); - // System.err.printf("AABBox.mapToWindow.p1: %f, %f, %f -> %f, %f, %f%n", getMinX(), getMinY(), objZ, tmpV3[0], tmpV3[1], tmpV3[2]); - // System.err.printf("AABBox.mapToWindow.p1: %s%n", pmv.toString()); - result.reset(); - result.resize(tmpV3, 0); - pmv.gluProject(getMinX(), getMaxY(), objZ, view, 0, tmpV3, 0); - // System.err.printf("AABBox.mapToWindow.p2: %f, %f, %f -> %f, %f, %f%n", getMinX(), getMaxY(), objZ, tmpV3[0], tmpV3[1], tmpV3[2]); - result.resize(tmpV3, 0); - pmv.gluProject(getMaxX(), getMinY(), objZ, view, 0, tmpV3, 0); - // System.err.printf("AABBox.mapToWindow.p3: %f, %f, %f -> %f, %f, %f%n", getMaxX(), getMinY(), objZ, tmpV3[0], tmpV3[1], tmpV3[2]); - result.resize(tmpV3, 0); - pmv.gluProject(getMaxX(), getMaxY(), objZ, view, 0, tmpV3, 0); - // System.err.printf("AABBox.mapToWindow.p4: %f, %f, %f -> %f, %f, %f%n", getMaxX(), getMaxY(), objZ, tmpV3[0], tmpV3[1], tmpV3[2]); - result.resize(tmpV3, 0); + 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.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); + + 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.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.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); + } + if( !useCenterZ ) { - objZ = getMaxZ(); - pmv.gluProject(getMinX(), getMinY(), objZ, view, 0, tmpV3, 0); - result.resize(tmpV3, 0); - pmv.gluProject(getMinX(), getMaxY(), objZ, view, 0, tmpV3, 0); - result.resize(tmpV3, 0); - pmv.gluProject(getMaxX(), getMinY(), objZ, view, 0, tmpV3, 0); - result.resize(tmpV3, 0); - pmv.gluProject(getMaxX(), getMaxY(), objZ, view, 0, tmpV3, 0); - result.resize(tmpV3, 0); + final float objZ = getMaxZ(); + FloatUtil.mapObjToWinCoords(getMinX(), getMinY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2); + result.resize(vec3Tmp0, 0); + + FloatUtil.mapObjToWinCoords(getMinX(), getMaxY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2); + result.resize(vec3Tmp0, 0); + + FloatUtil.mapObjToWinCoords(getMaxX(), getMinY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2); + result.resize(vec3Tmp0, 0); + + FloatUtil.mapObjToWinCoords(getMaxX(), getMaxY(), objZ, mat4PMv, view, 0, vec3Tmp0, 0, vec4Tmp1, vec4Tmp2); + result.resize(vec3Tmp0, 0); } if( DEBUG ) { System.err.printf("AABBox.mapToWindow: view[%d, %d], this %s -> %s%n", view[0], view[1], toString(), result.toString()); 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 8b4eba222..87d31becb 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java +++ b/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java @@ -68,7 +68,7 @@ import com.jogamp.common.os.Platform; */ public class Frustum { /** Normalized planes[l, r, b, t, n, f] */ - protected Plane[] planes = new Plane[6]; + protected final Plane[] planes = new Plane[6]; /** * Creates an undefined instance w/o calculating the frustum. diff --git a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java index c6f1f529d..f79efad2f 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java +++ b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java @@ -34,7 +34,6 @@ package com.jogamp.opengl.util; -import java.nio.Buffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; @@ -42,15 +41,12 @@ import javax.media.opengl.GL; import javax.media.opengl.GLException; import javax.media.opengl.fixedfunc.GLMatrixFunc; -import jogamp.opengl.ProjectFloat; - import com.jogamp.common.nio.Buffers; import com.jogamp.common.os.Platform; import com.jogamp.common.util.FloatStack; import com.jogamp.opengl.math.FloatUtil; import com.jogamp.opengl.math.Quaternion; import com.jogamp.opengl.math.Ray; -import com.jogamp.opengl.math.VectorUtil; import com.jogamp.opengl.math.geom.AABBox; import com.jogamp.opengl.math.geom.Frustum; @@ -77,30 +73,28 @@ import com.jogamp.opengl.math.geom.Frustum; * </p> * <a name="storageDetails"><h5>Matrix storage details</h5></a> * <p> - * All matrices use a common FloatBuffer storage - * and are a {@link Buffers#slice2Float(Buffer, float[], int, int) sliced} representation of it. - * The common FloatBuffer and hence all matrices may use NIO direct storage or a {@link #usesBackingArray() backing float array}, - * depending how the instance if {@link #PMVMatrix(boolean) being constructed}. + * All matrices are backed up by a common primitive float-array for performance considerations + * and are a {@link Buffers#slice2Float(float[], int, int) sliced} representation of it. * </p> * <p> * <b>Note:</b> * <ul> - * <li>The matrix is a {@link Buffers#slice2Float(Buffer, float[], int, int) sliced part } of a host matrix and it's start position has been {@link FloatBuffer#mark() marked}.</li> + * <li>The matrix is a {@link Buffers#slice2Float(float[], int, int) sliced part } of a host matrix and it's start position has been {@link FloatBuffer#mark() marked}.</li> * <li>Use {@link FloatBuffer#reset() reset()} to rewind it to it's start position after relative operations, like {@link FloatBuffer#get() get()}.</li> * <li>If using absolute operations like {@link FloatBuffer#get(int) get(int)}, use it's {@link FloatBuffer#reset() reset} {@link FloatBuffer#position() position} as it's offset.</li> * </ul> * </p> */ -public class PMVMatrix implements GLMatrixFunc { +public final class PMVMatrix implements GLMatrixFunc { /** Bit value stating a modified {@link #glGetPMatrixf() projection matrix (P)}, since last {@link #update()} call. */ - public static final int MODIFIED_PROJECTION = 1 << 0; + public static final int MODIFIED_PROJECTION = 1 << 0; /** Bit value stating a modified {@link #glGetMvMatrixf() modelview matrix (Mv)}, since last {@link #update()} call. */ - public static final int MODIFIED_MODELVIEW = 1 << 1; + public static final int MODIFIED_MODELVIEW = 1 << 1; /** Bit value stating a modified {@link #glGetTMatrixf() texture matrix (T)}, since last {@link #update()} call. */ - public static final int MODIFIED_TEXTURE = 1 << 2; + public static final int MODIFIED_TEXTURE = 1 << 2; /** Bit value stating all is modified */ - public static final int MODIFIED_ALL = MODIFIED_PROJECTION | MODIFIED_MODELVIEW | MODIFIED_TEXTURE ; + public static final int MODIFIED_ALL = MODIFIED_PROJECTION | MODIFIED_MODELVIEW | MODIFIED_TEXTURE ; /** Bit value stating a dirty {@link #glGetMviMatrixf() inverse modelview matrix (Mvi)}. */ public static final int DIRTY_INVERSE_MODELVIEW = 1 << 0; @@ -196,97 +190,65 @@ public class PMVMatrix implements GLMatrixFunc { } /** - * Creates an instance of PMVMatrix {@link #PMVMatrix(boolean) PMVMatrix(boolean useBackingArray)}, - * with <code>useBackingArray = true</code>. - */ - public PMVMatrix() { - this(true); - } - - /** * Creates an instance of PMVMatrix. - * - * @param useBackingArray <code>true</code> for non direct NIO Buffers with guaranteed backing array, - * which allows faster access in Java computation. - * <p><code>false</code> for direct NIO buffers w/o a guaranteed backing array. - * In most Java implementations, direct NIO buffers have no backing array - * and hence the Java computation will be throttled down by direct IO get/put - * operations.</p> - * <p>Depending on the application, ie. whether the Java computation or - * JNI invocation and hence native data transfer part is heavier, - * this flag shall be set to <code>true</code> or <code>false</code></p>. + * <p> + * Implementation uses non-direct non-NIO Buffers with guaranteed backing array, + * which allows faster access in Java computation. + * </p> */ - public PMVMatrix(boolean useBackingArray) { - this.usesBackingArray = useBackingArray; - + public PMVMatrix() { // I Identity // T Texture // P Projection // Mv ModelView // Mvi Modelview-Inverse // Mvit Modelview-Inverse-Transpose - if(useBackingArray) { - matrixBufferArray = new float[ 6*16 + ProjectFloat.getRequiredFloatBufferSize() ]; - matrixBuffer = null; - } else { - matrixBufferArray = null; - matrixBuffer = Buffers.newDirectByteBuffer( ( 6*16 + ProjectFloat.getRequiredFloatBufferSize() ) * Buffers.SIZEOF_FLOAT ); - matrixBuffer.mark(); - } - - matrixIdent = Buffers.slice2Float(matrixBuffer, matrixBufferArray, 0*16, 1*16); // I - matrixTex = Buffers.slice2Float(matrixBuffer, matrixBufferArray, 1*16, 1*16); // T - matrixPMvMvit = Buffers.slice2Float(matrixBuffer, matrixBufferArray, 2*16, 4*16); // P + Mv + Mvi + Mvit - matrixPMvMvi = Buffers.slice2Float(matrixBuffer, matrixBufferArray, 2*16, 3*16); // P + Mv + Mvi - matrixPMv = Buffers.slice2Float(matrixBuffer, matrixBufferArray, 2*16, 2*16); // P + Mv - matrixP = Buffers.slice2Float(matrixBuffer, matrixBufferArray, 2*16, 1*16); // P - matrixMv = Buffers.slice2Float(matrixBuffer, matrixBufferArray, 3*16, 1*16); // Mv - matrixMvi = Buffers.slice2Float(matrixBuffer, matrixBufferArray, 4*16, 1*16); // Mvi - matrixMvit = Buffers.slice2Float(matrixBuffer, matrixBufferArray, 5*16, 1*16); // Mvit - - projectFloat = new ProjectFloat(matrixBuffer, matrixBufferArray, 6*16); - - if(null != matrixBuffer) { - matrixBuffer.reset(); - } - FloatUtil.makeIdentityf(matrixIdent); - - tmpVec3f = new float[3]; - tmpMatrix = new float[16]; - matrixRot = new float[16]; - matrixMult = new float[16]; - matrixTrans = new float[16]; - matrixScale = new float[16]; - matrixOrtho = new float[16]; - matrixFrustum = new float[16]; - FloatUtil.makeIdentityf(matrixTrans, 0); - FloatUtil.makeIdentityf(matrixRot, 0); - FloatUtil.makeIdentityf(matrixScale, 0); - FloatUtil.makeIdentityf(matrixOrtho, 0); - FloatUtil.makeZero(matrixFrustum, 0); + matrixArray = new float[5*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 + matrixPMv = Buffers.slice2Float(matrixArray, 0*16, 2*16); // P + Mv + matrixP = Buffers.slice2Float(matrixArray, 0*16, 1*16); // P + matrixMv = Buffers.slice2Float(matrixArray, 1*16, 1*16); // Mv + matrixMvi = Buffers.slice2Float(matrixArray, 2*16, 1*16); // Mvi + matrixMvit = Buffers.slice2Float(matrixArray, 3*16, 1*16); // Mvit + matrixTex = Buffers.slice2Float(matrixArray, 4*16, 1*16); // T + + mat4Tmp1 = new float[16]; + mat4Tmp2 = new float[16]; + mat4Tmp3 = new float[16]; + matrixTxSx = new float[16]; + FloatUtil.makeIdentity(matrixTxSx); // Start w/ zero size to save memory matrixTStack = new FloatStack( 0, 2*16); // growSize: GL-min size (2) matrixPStack = new FloatStack( 0, 2*16); // growSize: GL-min size (2) matrixMvStack= new FloatStack( 0, 16*16); // growSize: half GL-min size (32) - // default values and mode - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glMatrixMode(GL.GL_TEXTURE); - glLoadIdentity(); - modifiedBits = MODIFIED_ALL; - dirtyBits = DIRTY_ALL; - requestMask = 0; - matrixMode = GL_MODELVIEW; + reset(); frustum = null; } - /** @see #PMVMatrix(boolean) */ - public final boolean usesBackingArray() { return usesBackingArray; } + /** + * 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. + */ + public final void reset() { + FloatUtil.makeIdentity(matrixArray, mMv_offset); + FloatUtil.makeIdentity(matrixArray, mP_offset); + FloatUtil.makeIdentity(matrixArray, mTex_offset); + + modifiedBits = MODIFIED_ALL; + dirtyBits = DIRTY_ALL; + requestMask = 0; + matrixMode = GL_MODELVIEW; + } /** Returns the current matrix-mode, one of {@link GLMatrixFunc#GL_MODELVIEW GL_MODELVIEW}, {@link GLMatrixFunc#GL_PROJECTION GL_PROJECTION} or {@link GL#GL_TEXTURE GL_TEXTURE}. */ public final int glGetMatrixMode() { @@ -402,7 +364,7 @@ public class PMVMatrix implements GLMatrixFunc { } /** Returns the frustum, derived from projection * modelview */ - public Frustum glGetFrustum() { + public final Frustum glGetFrustum() { requestMask |= DIRTY_FRUSTUM; updateImpl(false); return frustum; @@ -420,7 +382,7 @@ public class PMVMatrix implements GLMatrixFunc { * {@link GLMatrixFunc#GL_MODELVIEW_MATRIX GL_MODELVIEW_MATRIX}, {@link GLMatrixFunc#GL_PROJECTION_MATRIX GL_PROJECTION_MATRIX} or {@link GLMatrixFunc#GL_TEXTURE_MATRIX GL_TEXTURE_MATRIX}, * or a matrix-mode-name, i.e. * {@link GLMatrixFunc#GL_MODELVIEW GL_MODELVIEW}, {@link GLMatrixFunc#GL_PROJECTION GL_PROJECTION} or {@link GL#GL_TEXTURE GL_TEXTURE} - * @return the named matrix + * @return the named matrix, not a copy! */ public final FloatBuffer glGetMatrixf(final int matrixName) { switch(matrixName) { @@ -438,6 +400,35 @@ public class PMVMatrix implements GLMatrixFunc { } } + + /** + * Multiplies the {@link #glGetPMatrixf() P} and {@link #glGetMvMatrixf() Mv} matrix, i.e. + * <pre> + * mat4PMv = P x Mv + * </pre> + * @param mat4PMv 4x4 matrix storage for result + * @param mat4PMv_offset + * @return given matrix for chaining + */ + public final float[] multPMvMatrixf(final float[/*16*/] mat4PMv, final int mat4PMv_offset) { + FloatUtil.multMatrix(matrixArray, mP_offset, matrixArray, mMv_offset, mat4PMv, mat4PMv_offset); + return mat4PMv; + } + + /** + * Multiplies the {@link #glGetMvMatrixf() Mv} and {@link #glGetPMatrixf() P} matrix, i.e. + * <pre> + * mat4MvP = Mv x P + * </pre> + * @param mat4MvP 4x4 matrix storage for result + * @param mat4MvP_offset + * @return given matrix for chaining + */ + public final float[] multMvPMatrixf(final float[/*16*/] mat4MvP, final int mat4MvP_offset) { + FloatUtil.multMatrix(matrixArray, mMv_offset, matrixArray, mP_offset, mat4MvP, mat4MvP_offset); + return mat4MvP; + } + // // GLMatrixFunc implementation // @@ -593,35 +584,31 @@ public class PMVMatrix implements GLMatrixFunc { @Override public final void glLoadIdentity() { if(matrixMode==GL_MODELVIEW) { - matrixMv.put(matrixIdent); - matrixMv.reset(); + FloatUtil.makeIdentity(matrixArray, mMv_offset); dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ; modifiedBits |= MODIFIED_MODELVIEW; } else if(matrixMode==GL_PROJECTION) { - matrixP.put(matrixIdent); - matrixP.reset(); + FloatUtil.makeIdentity(matrixArray, mP_offset); dirtyBits |= DIRTY_FRUSTUM ; modifiedBits |= MODIFIED_PROJECTION; } else if(matrixMode==GL.GL_TEXTURE) { - matrixTex.put(matrixIdent); - matrixTex.reset(); + FloatUtil.makeIdentity(matrixArray, mTex_offset); modifiedBits |= MODIFIED_TEXTURE; } - matrixIdent.reset(); } @Override public final void glMultMatrixf(final FloatBuffer m) { if(matrixMode==GL_MODELVIEW) { - FloatUtil.multMatrixf(matrixMv, m); + FloatUtil.multMatrix(matrixMv, m); dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ; modifiedBits |= MODIFIED_MODELVIEW; } else if(matrixMode==GL_PROJECTION) { - FloatUtil.multMatrixf(matrixP, m); + FloatUtil.multMatrix(matrixP, m); dirtyBits |= DIRTY_FRUSTUM ; modifiedBits |= MODIFIED_PROJECTION; } else if(matrixMode==GL.GL_TEXTURE) { - FloatUtil.multMatrixf(matrixTex, m); + FloatUtil.multMatrix(matrixTex, m); modifiedBits |= MODIFIED_TEXTURE; } } @@ -629,69 +616,49 @@ public class PMVMatrix implements GLMatrixFunc { @Override public final void glMultMatrixf(final float[] m, final int m_offset) { if(matrixMode==GL_MODELVIEW) { - FloatUtil.multMatrixf(matrixMv, m, m_offset); + FloatUtil.multMatrix(matrixArray, mMv_offset, m, m_offset); dirtyBits |= DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW | DIRTY_FRUSTUM ; modifiedBits |= MODIFIED_MODELVIEW; } else if(matrixMode==GL_PROJECTION) { - FloatUtil.multMatrixf(matrixP, m, m_offset); + FloatUtil.multMatrix(matrixArray, mP_offset, m, m_offset); dirtyBits |= DIRTY_FRUSTUM ; modifiedBits |= MODIFIED_PROJECTION; } else if(matrixMode==GL.GL_TEXTURE) { - FloatUtil.multMatrixf(matrixTex, m, m_offset); + FloatUtil.multMatrix(matrixArray, mTex_offset, m, m_offset); modifiedBits |= MODIFIED_TEXTURE; } } @Override public final void glTranslatef(final float x, final float y, final float z) { - // Translation matrix (Column Order): - // 1 0 0 0 - // 0 1 0 0 - // 0 0 1 0 - // x y z 1 - matrixTrans[0+4*3] = x; - matrixTrans[1+4*3] = y; - matrixTrans[2+4*3] = z; - glMultMatrixf(matrixTrans, 0); + glMultMatrixf(FloatUtil.makeTranslation(matrixTxSx, false, x, y, z), 0); + } + + @Override + public final void glScalef(final float x, final float y, final float z) { + glMultMatrixf(FloatUtil.makeScale(matrixTxSx, false, x, y, z), 0); } @Override public final void glRotatef(final float angdeg, final float x, final float y, final float z) { - final float angrad = angdeg * FloatUtil.PI / 180.0f; - FloatUtil.makeRotationAxis(angrad, x, y, z, matrixRot, 0, tmpVec3f); - glMultMatrixf(matrixRot, 0); + glMultMatrixf(FloatUtil.makeRotationAxis(mat4Tmp1, 0, angdeg * FloatUtil.PI / 180.0f, x, y, z, mat4Tmp2), 0); } /** * Rotate the current matrix with the given {@link Quaternion}'s rotation {@link Quaternion#toMatrix(float[], int) matrix representation}. */ public final void glRotate(final Quaternion quat) { - quat.toMatrix(tmpMatrix, 0); - glMultMatrixf(tmpMatrix, 0); - } - - @Override - public final void glScalef(final float x, final float y, final float z) { - // Scale matrix (Any Order): - // x 0 0 0 - // 0 y 0 0 - // 0 0 z 0 - // 0 0 0 1 - matrixScale[0+4*0] = x; - matrixScale[1+4*1] = y; - matrixScale[2+4*2] = z; - - glMultMatrixf(matrixScale, 0); + glMultMatrixf(quat.toMatrix(mat4Tmp1, 0), 0); } @Override public final void glOrthof(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) { - glMultMatrixf( FloatUtil.makeOrthof(matrixOrtho, 0, false, left, right, bottom, top, zNear, zFar), 0 ); + glMultMatrixf( FloatUtil.makeOrtho(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar), 0 ); } @Override public final void glFrustumf(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) { - glMultMatrixf( FloatUtil.makeFrustumf(matrixFrustum, 0, false, left, right, bottom, top, zNear, zFar), 0 ); + glMultMatrixf( FloatUtil.makeFrustum(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar), 0 ); } // @@ -702,7 +669,7 @@ public class PMVMatrix implements GLMatrixFunc { * {@link #glMultMatrixf(FloatBuffer) Multiply} the {@link #glGetMatrixMode() current matrix} with the perspective/frustum matrix. */ public final void gluPerspective(final float fovy, final float aspect, final float zNear, final float zFar) { - glMultMatrixf( FloatUtil.makePerspective(matrixFrustum, 0, false, fovy*((float)Math.PI)/360.0f, aspect, zNear, zFar), 0 ); + glMultMatrixf( FloatUtil.makePerspective(mat4Tmp1, 0, true, fovy*((float)Math.PI)/360.0f, aspect, zNear, zFar), 0 ); } /** @@ -712,73 +679,124 @@ public class PMVMatrix implements GLMatrixFunc { public final void gluLookAt(final float eyex, final float eyey, final float eyez, final float centerx, final float centery, final float centerz, final float upx, final float upy, final float upz) { - projectFloat.gluLookAt(this, eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz); + mat4Tmp2[0+0] = eyex; + mat4Tmp2[1+0] = eyey; + mat4Tmp2[2+0] = eyez; + mat4Tmp2[0+4] = centerx; + mat4Tmp2[1+4] = centery; + mat4Tmp2[2+4] = centerz; + mat4Tmp2[0+8] = upx; + mat4Tmp2[1+8] = upy; + mat4Tmp2[2+8] = upz; + glMultMatrixf( + FloatUtil.makeLookAt(mat4Tmp1, 0, mat4Tmp2 /* eye */, 0, mat4Tmp2 /* center */, 4, mat4Tmp2 /* up */, 8, mat4Tmp3), 0); } /** * Map object coordinates to window coordinates. + * <p> + * Traditional <code>gluProject</code> implementation. + * </p> * * @param objx * @param objy * @param objz - * @param viewport + * @param viewport 4 component viewport vector * @param viewport_offset - * @param win_pos + * @param win_pos 3 component window coordinate, the result * @param win_pos_offset - * @return + * @return true if successful, otherwise false (z is 1) */ 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 ) { - if(usesBackingArray) { - return projectFloat.gluProject(objx, objy, objz, - matrixMv.array(), matrixMv.position(), - matrixP.array(), matrixP.position(), - viewport, viewport_offset, - win_pos, win_pos_offset); - } else { - return projectFloat.gluProject(objx, objy, objz, - matrixMv, - matrixP, - viewport, viewport_offset, - win_pos, win_pos_offset); - } + return FloatUtil.mapObjToWinCoords(objx, objy, objz, + matrixArray, mMv_offset, + matrixArray, mP_offset, + viewport, viewport_offset, + win_pos, win_pos_offset, + mat4Tmp1, mat4Tmp2); } /** * Map window coordinates to object coordinates. + * <p> + * Traditional <code>gluUnProject</code> implementation. + * </p> * * @param winx * @param winy * @param winz - * @param viewport + * @param viewport 4 component viewport vector * @param viewport_offset - * @param obj_pos + * @param obj_pos 3 component object coordinate, the result * @param obj_pos_offset - * @return true if successful, otherwise false (failed to invert matrix, or becomes z is infinity) + * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z) */ 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) { - if(usesBackingArray) { - return projectFloat.gluUnProject(winx, winy, winz, - matrixMv.array(), matrixMv.position(), - matrixP.array(), matrixP.position(), - viewport, viewport_offset, - obj_pos, obj_pos_offset); - } else { - return projectFloat.gluUnProject(winx, winy, winz, - matrixMv, - matrixP, - viewport, viewport_offset, - obj_pos, obj_pos_offset); - } + return FloatUtil.mapWinToObjCoords(winx, winy, winz, + matrixArray, mMv_offset, + matrixArray, mP_offset, + viewport, viewport_offset, + obj_pos, obj_pos_offset, + mat4Tmp1, mat4Tmp2); + } + + /** + * Map window coordinates to object coordinates. + * <p> + * Traditional <code>gluUnProject4</code> implementation. + * </p> + * + * @param winx + * @param winy + * @param winz + * @param clipw + * @param modelMatrix 4x4 modelview matrix + * @param modelMatrix_offset + * @param projMatrix 4x4 projection matrix + * @param projMatrix_offset + * @param viewport 4 component viewport vector + * @param viewport_offset + * @param near + * @param far + * @param obj_pos 4 component object coordinate, the result + * @param obj_pos_offset + * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z) + */ + public boolean gluUnProject4(final float winx, final float winy, final float winz, final float clipw, + 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, + matrixArray, mMv_offset, + matrixArray, mP_offset, + viewport, viewport_offset, + near, far, + obj_pos, obj_pos_offset, + mat4Tmp1, mat4Tmp2); } + /** + * Make given matrix the <i>pick</i> matrix based on given parameters. + * <p> + * Traditional <code>gluPickMatrix</code> implementation. + * </p> + * @param x + * @param y + * @param deltaX + * @param deltaY + * @param viewport 4 component viewport vector + * @param viewport_offset + */ public final void gluPickMatrix(final float x, final float y, final float deltaX, final float deltaY, final int[] viewport, final int viewport_offset) { - projectFloat.gluPickMatrix(this, x, y, deltaX, deltaY, viewport, viewport_offset); + if( null != FloatUtil.makePick(mat4Tmp1, 0, x, y, deltaX, deltaY, viewport, viewport_offset, mat4Tmp2) ) { + glMultMatrixf(mat4Tmp1, 0); + } } /** @@ -805,13 +823,12 @@ public class PMVMatrix implements GLMatrixFunc { public final boolean gluUnProjectRay(final float winx, final float winy, final float winz0, final float winz1, final int[] viewport, final int viewport_offset, final Ray ray) { - if( gluUnProject(winx, winy, winz0, viewport, viewport_offset, ray.orig, 0) && - gluUnProject(winx, winy, winz1, viewport, viewport_offset, ray.dir, 0) ) { - VectorUtil.normalizeVec3( VectorUtil.subVec3(ray.dir, ray.dir, ray.orig) ); - return true; - } else { - return false; - } + return FloatUtil.mapWinToRay(winx, winy, winz0, winz1, + matrixArray, mMv_offset, + matrixArray, mP_offset, + viewport, viewport_offset, + ray, + mat4Tmp1, mat4Tmp2, mat4Tmp3); } public StringBuilder toString(StringBuilder sb, String f) { @@ -828,10 +845,9 @@ public class PMVMatrix implements GLMatrixFunc { final boolean modMv = 0 != ( MODIFIED_MODELVIEW & modifiedBits ); final boolean modT = 0 != ( MODIFIED_TEXTURE & modifiedBits ); - sb.append("PMVMatrix[backingArray ").append(this.usesBackingArray()); - sb.append(", modified[P ").append(modP).append(", Mv ").append(modMv).append(", T ").append(modT); - sb.append("], dirty/req[Mvi ").append(mviDirty).append("/").append(mviReq).append(", Mvit ").append(mvitDirty).append("/").append(mvitReq).append(", Frustum ").append(frustumDirty).append("/").append(frustumReq); - sb.append("], Projection").append(Platform.NEWLINE); + sb.append("PMVMatrix[modified[P ").append(modP).append(", Mv ").append(modMv).append(", T ").append(modT); + sb.append("], dirty/req[Mvi ").append(mviDirty).append("/").append(mviReq).append(", Mvit ").append(mvitDirty).append("/").append(mvitReq).append(", Frustum ").append(frustumDirty).append("/").append(frustumReq).append("]").append(Platform.NEWLINE); + sb.append(", Projection").append(Platform.NEWLINE); matrixToString(sb, f, matrixP); sb.append(", Modelview").append(Platform.NEWLINE); matrixToString(sb, f, matrixMv); @@ -993,8 +1009,9 @@ public class PMVMatrix implements GLMatrixFunc { if( null == frustum ) { frustum = new Frustum(); } - FloatUtil.multMatrixf(matrixP, matrixMv, tmpMatrix, 0); - frustum.updateByPMV(tmpMatrix, 0); + FloatUtil.multMatrix(matrixArray, mP_offset, matrixArray, mMv_offset, mat4Tmp1, 0); + // FloatUtil.multMatrix(matrixP, matrixMv, mat4Tmp1, 0); + frustum.updateByPMV(mat4Tmp1, 0); dirtyBits &= ~DIRTY_FRUSTUM; mod = true; } @@ -1003,82 +1020,42 @@ public class PMVMatrix implements GLMatrixFunc { return mod; // nothing more requested which may have been dirty } - if(nioBackupArraySupported>=0) { - try { - nioBackupArraySupported = 1; - return setMviMvitNIOBackupArray() || mod; - } catch(UnsupportedOperationException uoe) { - nioBackupArraySupported = -1; - } - } - return setMviMvitNIODirectAccess() || mod; + return setMviMvit() || mod; } // // private // - private int nioBackupArraySupported = 0; // -1 not supported, 0 - TBD, 1 - supported - private final String msgCantComputeInverse = "Invalid source Mv matrix, can't compute inverse"; + private static final String msgCantComputeInverse = "Invalid source Mv matrix, can't compute inverse"; - private final boolean setMviMvitNIOBackupArray() { + private final boolean setMviMvit() { final float[] _matrixMvi = matrixMvi.array(); final int _matrixMviOffset = matrixMvi.position(); boolean res = false; if( 0 != ( dirtyBits & DIRTY_INVERSE_MODELVIEW ) ) { // only if dirt; always requested at this point, see update() - if(!projectFloat.gluInvertMatrixf(matrixMv.array(), matrixMv.position(), _matrixMvi, _matrixMviOffset)) { + if( null == FloatUtil.invertMatrix(matrixArray, mMv_offset, _matrixMvi, _matrixMviOffset, mat4Tmp1) ) { throw new GLException(msgCantComputeInverse); } dirtyBits &= ~DIRTY_INVERSE_MODELVIEW; res = true; } if( 0 != ( requestMask & ( dirtyBits & DIRTY_INVERSE_TRANSPOSED_MODELVIEW ) ) ) { // only if requested & dirty - // transpose matrix - final float[] _matrixMvit = matrixMvit.array(); - final int _matrixMvitOffset = matrixMvit.position(); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - _matrixMvit[_matrixMvitOffset+j+i*4] = _matrixMvi[_matrixMviOffset+i+j*4]; - } - } - dirtyBits &= ~DIRTY_INVERSE_TRANSPOSED_MODELVIEW; - res = true; - } - return res; - } - - private final boolean setMviMvitNIODirectAccess() { - boolean res = false; - if( 0 != ( dirtyBits & DIRTY_INVERSE_MODELVIEW ) ) { // only if dirt; always requested at this point, see update() - if(!projectFloat.gluInvertMatrixf(matrixMv, matrixMvi)) { - throw new GLException(msgCantComputeInverse); - } - dirtyBits &= ~DIRTY_INVERSE_MODELVIEW; - res = true; - } - if( 0 != ( requestMask & ( dirtyBits & DIRTY_INVERSE_TRANSPOSED_MODELVIEW ) ) ) { // only if requested & dirty - // transpose matrix - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - matrixMvit.put(j+i*4, matrixMvi.get(i+j*4)); - } - } + FloatUtil.transposeMatrix(_matrixMvi, _matrixMviOffset, matrixMvit.array(), matrixMvit.position()); dirtyBits &= ~DIRTY_INVERSE_TRANSPOSED_MODELVIEW; res = true; } return res; } - protected final boolean usesBackingArray; - protected final float[] matrixBufferArray; - protected final Buffer matrixBuffer; - protected final FloatBuffer matrixIdent, matrixPMvMvit, matrixPMvMvi, matrixPMv, matrixP, matrixTex, matrixMv, matrixMvi, matrixMvit; - protected final float[] matrixMult, matrixTrans, matrixRot, matrixScale, matrixOrtho, matrixFrustum, tmpVec3f; - protected final float[] tmpMatrix; - protected final FloatStack matrixTStack, matrixPStack, matrixMvStack; - protected final ProjectFloat projectFloat; - protected int matrixMode = GL_MODELVIEW; - protected int modifiedBits = MODIFIED_ALL; - protected int dirtyBits = DIRTY_ALL; // contains the dirty bits, i.e. hinting for update operation - protected int requestMask = 0; // may contain the requested dirty bits: DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW - protected Frustum frustum; + 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; + private final FloatStack matrixTStack, matrixPStack, matrixMvStack; + private int matrixMode = GL_MODELVIEW; + private int modifiedBits = MODIFIED_ALL; + private int dirtyBits = DIRTY_ALL; // contains the dirty bits, i.e. hinting for update operation + private int requestMask = 0; // may contain the requested dirty bits: DIRTY_INVERSE_MODELVIEW | DIRTY_INVERSE_TRANSPOSED_MODELVIEW + private Frustum frustum; } |