diff options
author | Sven Gothel <[email protected]> | 2023-09-20 19:51:55 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-09-20 19:51:55 +0200 |
commit | 5d6e8a367c03644740187e500c6de5d3ac039d5e (patch) | |
tree | a649f559413c51272ee3f4afff1f68ebfea45477 /src/jogl/classes/com/jogamp/opengl/math | |
parent | bbe845846ffc00807395a5070a7352c6bbe7e4ef (diff) |
Bug 1452 - Decouple math functionality to 'com.jogamp.math' to be toolkit agnostic (PMVMatrix, Matrix4f, Vec4f, ..)
Math functionality (PMVMatrix, Matrix4f, Vec4f, ..)
- shall be used toolkit agnostic, e.g. independent from OpenGL
- shall be reused within our upcoming Vulkan implementation
- may also move outside of JOGL, i.e. GlueGen or within its own package to be reused for other purposed.
The 'com.jogamp.opengl.util.PMVMatrix' currently also used to feed in GLUniformData
via the toolkit agnostic SyncAction and SyncBuffer
shall also be split to a toolkit agnostic variant.
An OpenGL PMVMatrix specialization implementing GLMatrixFunc can still exist,
being derived from the toolkit agnostic base implementation.
+++
Initial commit .. compile clean, passing most unit tests.
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl/math')
19 files changed, 0 insertions, 9684 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/math/Binary16.java b/src/jogl/classes/com/jogamp/opengl/math/Binary16.java deleted file mode 100644 index 8e4aa9176..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Binary16.java +++ /dev/null @@ -1,569 +0,0 @@ -/** - * Copyright 2013 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.opengl.math; - -/** - * <p> - * Functions to convert values to/from the <code>binary16</code> format - * specified in <code>IEEE 754 2008</code>. - * </p> - */ - -public final class Binary16 -{ - /** - * The encoded form of negative infinity <code>-∞</code>. - */ - - public static final char NEGATIVE_INFINITY; - - /** - * The encoded form of positive infinity <code>∞</code>. - */ - - public static final char POSITIVE_INFINITY; - - /** - * The encoded form of positive zero <code>0</code>. - */ - - public static final char POSITIVE_ZERO; - - /** - * The encoded form of negative zero <code>-0</code>. - */ - - public static final char NEGATIVE_ZERO; - - /** - * The <i>bias</i> value used to offset the encoded exponent. A given - * exponent <code>e</code> is encoded as <code>{@link #BIAS} + e</code>. - */ - - public static final int BIAS; - - static { - NEGATIVE_INFINITY = 0xFC00; - POSITIVE_INFINITY = 0x7C00; - POSITIVE_ZERO = 0x0000; - NEGATIVE_ZERO = 0x8000; - BIAS = 15; - } - - private static final int MASK_SIGN; - private static final int MASK_EXPONENT; - private static final int MASK_SIGNIFICAND; - - static { - MASK_SIGN = 0x8000; - MASK_EXPONENT = 0x7C00; - MASK_SIGNIFICAND = 0x03FF; - } - - /** - * One possible not-a-number value. - */ - - public static char exampleNaN() - { - final int n = - Binary16.packSetExponentUnbiasedUnchecked(16) - | Binary16.packSetSignificandUnchecked(1); - final char c = (char) n; - return c; - } - - /** - * Return <code>true</code> if the given packed <code>binary16</code> value - * is infinite. - */ - - public static boolean isInfinite( - final char k) - { - if (Binary16.unpackGetExponentUnbiased(k) == 16) { - if (Binary16.unpackGetSignificand(k) == 0) { - return true; - } - } - return false; - } - - /** - * Return <code>true</code> if the given packed <code>binary16</code> value - * is not a number (<code>NaN</code>). - */ - - public static boolean isNaN( - final char k) - { - final int e = Binary16.unpackGetExponentUnbiased(k); - final int s = Binary16.unpackGetSignificand(k); - return (e == 16) && (s > 0); - } - - /** - * <p> - * Convert a double precision floating point value to a packed - * <code>binary16</code> value. - * </p> - * <p> - * For the following specific cases, the function returns: - * </p> - * <ul> - * <li><code>NaN</code> iff <code>isNaN(k)</code></li> - * <li>{@link #POSITIVE_INFINITY} iff - * <code>k == {@link Double#POSITIVE_INFINITY}</code></li> - * <li>{@link #NEGATIVE_INFINITY} iff - * <code>k == {@link Double#NEGATIVE_INFINITY}</code></li> - * <li>{@link #NEGATIVE_ZERO} iff <code>k == -0.0</code></li> - * <li>{@link #POSITIVE_ZERO} iff <code>k == 0.0</code></li> - * </ul> - * <p> - * Otherwise, the <code>binary16</code> value that most closely represents - * <code>k</code> is returned. This may obviously be an infinite value as - * the interval of double precision values is far larger than that of the - * <code>binary16</code> type. - * </p> - * - * @see #unpackDouble(char) - */ - - public static char packDouble( - final double k) - { - if (Double.isNaN(k)) { - return Binary16.exampleNaN(); - } - if (k == Double.POSITIVE_INFINITY) { - return Binary16.POSITIVE_INFINITY; - } - if (k == Double.NEGATIVE_INFINITY) { - return Binary16.NEGATIVE_INFINITY; - } - if (Double.doubleToLongBits(k) == Binary64.NEGATIVE_ZERO_BITS) { - return Binary16.NEGATIVE_ZERO; - } - if (k == 0.0) { - return Binary16.POSITIVE_ZERO; - } - - final long de = Binary64.unpackGetExponentUnbiased(k); - final long ds = Binary64.unpackGetSign(k); - final long dn = Binary64.unpackGetSignificand(k); - final char rsr = Binary16.packSetSignUnchecked((int) ds); - - /** - * Extract the 5 least-significant bits of the exponent. - */ - - final int rem = (int) (de & 0x001F); - final char rer = Binary16.packSetExponentUnbiasedUnchecked(rem); - - /** - * Extract the 10 most-significant bits of the significand. - */ - - final long rnm = dn & 0xFFC0000000000L; - final long rns = rnm >> 42; - final char rnr = Binary16.packSetSignificandUnchecked((int) rns); - - /** - * Combine the results. - */ - - return (char) (rsr | rer | rnr); - } - - /** - * <p> - * Convert a single precision floating point value to a packed - * <code>binary16</code> value. - * </p> - * <p> - * For the following specific cases, the function returns: - * </p> - * <ul> - * <li><code>NaN</code> iff <code>isNaN(k)</code></li> - * <li>{@link #POSITIVE_INFINITY} iff - * <code>k == {@link Float#POSITIVE_INFINITY}</code></li> - * <li>{@link #NEGATIVE_INFINITY} iff - * <code>k == {@link Float#NEGATIVE_INFINITY}</code></li> - * <li>{@link #NEGATIVE_ZERO} iff <code>k == -0.0</code></li> - * <li>{@link #POSITIVE_ZERO} iff <code>k == 0.0</code></li> - * </ul> - * <p> - * Otherwise, the <code>binary16</code> value that most closely represents - * <code>k</code> is returned. This may obviously be an infinite value as - * the interval of single precision values is far larger than that of the - * <code>binary16</code> type. - * </p> - * - * @see #unpackFloat(char) - */ - - public static char packFloat( - final float k) - { - if (Float.isNaN(k)) { - return Binary16.exampleNaN(); - } - if (k == Float.POSITIVE_INFINITY) { - return Binary16.POSITIVE_INFINITY; - } - if (k == Float.NEGATIVE_INFINITY) { - return Binary16.NEGATIVE_INFINITY; - } - if (Float.floatToIntBits(k) == Binary32.NEGATIVE_ZERO_BITS) { - return Binary16.NEGATIVE_ZERO; - } - if (k == 0.0) { - return Binary16.POSITIVE_ZERO; - } - - final long de = Binary32.unpackGetExponentUnbiased(k); - final long ds = Binary32.unpackGetSign(k); - final long dn = Binary32.unpackGetSignificand(k); - final char rsr = Binary16.packSetSignUnchecked((int) ds); - - /** - * Extract the 5 least-significant bits of the exponent. - */ - - final int rem = (int) (de & 0x001F); - final char rer = Binary16.packSetExponentUnbiasedUnchecked(rem); - - /** - * Extract the 10 most-significant bits of the significand. - */ - - final long rnm = dn & 0x7FE000L; - final long rns = rnm >> 13; - final char rnr = Binary16.packSetSignificandUnchecked((int) rns); - - /** - * Combine the results. - */ - - return (char) (rsr | rer | rnr); - } - - /** - * <p> - * Encode the unbiased exponent <code>e</code>. Values should be in the - * range <code>[-15, 16]</code> - values outside of this range will be - * truncated. - * </p> - * - * @see #unpackGetExponentUnbiased(char) - */ - - public static char packSetExponentUnbiasedUnchecked( - final int e) - { - final int eb = e + Binary16.BIAS; - final int es = eb << 10; - final int em = es & Binary16.MASK_EXPONENT; - return (char) em; - } - - /** - * <p> - * Encode the significand <code>s</code>. Values should be in the range - * <code>[0, 1023]</code>. Values outside of this range will be truncated. - * </p> - * - * @see #unpackGetSignificand(char) - */ - - public static char packSetSignificandUnchecked( - final int s) - { - final int sm = s & Binary16.MASK_SIGNIFICAND; - return (char) sm; - } - - /** - * <p> - * Encode the sign bit <code>s</code>. Values should be in the range - * <code>[0, 1]</code>, with <code>0</code> ironically denoting a positive - * value. Values outside of this range will be truncated. - * </p> - * - * @see #unpackGetSign(char) - */ - - public static char packSetSignUnchecked( - final int s) - { - final int ss = s << 15; - final int sm = ss & Binary16.MASK_SIGN; - return (char) sm; - } - - /** - * Show the given raw packed <code>binary16</code> value as a string of - * binary digits. - */ - - public static String toRawBinaryString( - final char k) - { - final StringBuilder b = new StringBuilder(); - int z = k; - for (int i = 0; i < 16; ++i) { - if ((z & 1) == 1) { - b.insert(0, "1"); - } else { - b.insert(0, "0"); - } - z >>= 1; - } - return b.toString(); - } - - /** - * <p> - * Convert a packed <code>binary16</code> value <code>k</code> to a - * double-precision floating point value. - * </p> - * <p> - * The function returns: - * </p> - * <ul> - * <li><code>NaN</code> iff <code>isNaN(k)</code></li> - * <li>{@link Double#POSITIVE_INFINITY} iff - * <code>k == {@link #POSITIVE_INFINITY}</code></li> - * <li>{@link Double#NEGATIVE_INFINITY} iff - * <code>k == {@link #NEGATIVE_INFINITY}</code></li> - * <li><code>-0.0</code> iff <code>k == {@link #NEGATIVE_ZERO}</code></li> - * <li><code>0.0</code> iff <code>k == {@link #POSITIVE_ZERO}</code></li> - * <li><code>(-1.0 * n) * (2 ^ e) * 1.s</code>, for the decoded sign - * <code>n</code> of <code>k</code>, the decoded exponent <code>e</code> of - * <code>k</code>, and the decoded significand <code>s</code> of - * <code>k</code>.</li> - * </ul> - * - * @see #packDouble(double) - */ - - public static double unpackDouble( - final char k) - { - if (Binary16.isNaN(k)) { - return Double.NaN; - } - if (k == Binary16.POSITIVE_INFINITY) { - return Double.POSITIVE_INFINITY; - } - if (k == Binary16.NEGATIVE_INFINITY) { - return Double.NEGATIVE_INFINITY; - } - if (k == Binary16.NEGATIVE_ZERO) { - return -0.0; - } - if (k == Binary16.POSITIVE_ZERO) { - return 0.0; - } - - final long e = Binary16.unpackGetExponentUnbiased(k); - final long s = Binary16.unpackGetSign(k); - final long n = Binary16.unpackGetSignificand(k); - - /** - * Shift the sign bit to the position at which it will appear in the - * resulting value. - */ - - final long rsr = s << 63; - - /** - * 1. Bias the exponent. - * - * 2. Shift the result left to the position at which it will appear in the - * resulting value. - */ - - final long reb = (e + Binary64.BIAS); - final long rer = reb << 52; - - /** - * Shift the significand left to the position at which it will appear in - * the resulting value. - */ - - final long rnr = n << 42; - return Double.longBitsToDouble(rsr | rer | rnr); - } - - /** - * <p> - * Convert a packed <code>binary16</code> value <code>k</code> to a - * single-precision floating point value. - * </p> - * <p> - * The function returns: - * </p> - * <ul> - * <li><code>NaN</code> iff <code>isNaN(k)</code></li> - * <li>{@link Float#POSITIVE_INFINITY} iff - * <code>k == {@link #POSITIVE_INFINITY}</code></li> - * <li>{@link Float#NEGATIVE_INFINITY} iff - * <code>k == {@link #NEGATIVE_INFINITY}</code></li> - * <li><code>-0.0</code> iff <code>k == {@link #NEGATIVE_ZERO}</code></li> - * <li><code>0.0</code> iff <code>k == {@link #POSITIVE_ZERO}</code></li> - * <li><code>(-1.0 * n) * (2 ^ e) * 1.s</code>, for the decoded sign - * <code>n</code> of <code>k</code>, the decoded exponent <code>e</code> of - * <code>k</code>, and the decoded significand <code>s</code> of - * <code>k</code>.</li> - * </ul> - * - * @see #packFloat(float) - */ - - public static float unpackFloat( - final char k) - { - if (Binary16.isNaN(k)) { - return Float.NaN; - } - if (k == Binary16.POSITIVE_INFINITY) { - return Float.POSITIVE_INFINITY; - } - if (k == Binary16.NEGATIVE_INFINITY) { - return Float.NEGATIVE_INFINITY; - } - if (k == Binary16.NEGATIVE_ZERO) { - return -0.0f; - } - if (k == Binary16.POSITIVE_ZERO) { - return 0.0f; - } - - final int e = Binary16.unpackGetExponentUnbiased(k); - final int s = Binary16.unpackGetSign(k); - final int n = Binary16.unpackGetSignificand(k); - - /** - * Shift the sign bit to the position at which it will appear in the - * resulting value. - */ - - final int rsr = s << 31; - - /** - * 1. Bias the exponent. - * - * 2. Shift the result left to the position at which it will appear in the - * resulting value. - */ - - final int reb = (e + Binary32.BIAS); - final int rer = reb << 23; - - /** - * Shift the significand left to the position at which it will appear in - * the resulting value. - */ - - final int rnr = n << 13; - return Float.intBitsToFloat(rsr | rer | rnr); - } - - /** - * <p> - * Extract and unbias the exponent of the given packed <code>binary16</code> - * value. - * </p> - * <p> - * The exponent is encoded <i>biased</i> as a number in the range - * <code>[0, 31]</code>, with <code>0</code> indicating that the number is - * <i>subnormal</i> and <code>[1, 30]</code> denoting the actual exponent - * plus {@link #BIAS}. Infinite and <code>NaN</code> values always have an - * exponent of <code>31</code>. - * </p> - * <p> - * This function will therefore return: - * </p> - * <ul> - * <li> - * <code>0 - {@link #BIAS} = -15</code> iff the input is a <i>subnormal</i> - * number.</li> - * <li>An integer in the range - * <code>[1 - {@link #BIAS}, 30 - {@link #BIAS}] = [-14, 15]</code> iff the - * input is a <i>normal</i> number.</li> - * <li> - * <code>16</code> iff the input is {@link #POSITIVE_INFINITY}, - * {@link #NEGATIVE_INFINITY}, or <code>NaN</code>.</li> - * </ul> - * - * @see #packSetExponentUnbiasedUnchecked(int) - */ - - public static int unpackGetExponentUnbiased( - final char k) - { - final int em = k & Binary16.MASK_EXPONENT; - final int es = em >> 10; - return es - Binary16.BIAS; - } - - /** - * Retrieve the sign bit of the given packed <code>binary16</code> value, as - * an integer in the range <code>[0, 1]</code>. - * - * @see Binary16#packSetSignUnchecked(int) - */ - - public static int unpackGetSign( - final char k) - { - return (k & Binary16.MASK_SIGN) >> 15; - } - - /** - * <p> - * Return the significand of the given packed <code>binary16</code> value as - * an integer in the range <code>[0, 1023]</code>. - * </p> - * - * @see Binary16#packSetSignificandUnchecked(int) - */ - - public static int unpackGetSignificand( - final char k) - { - return k & Binary16.MASK_SIGNIFICAND; - } - - private Binary16() - { - throw new AssertionError("Unreachable code, report this bug!"); - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Binary32.java b/src/jogl/classes/com/jogamp/opengl/math/Binary32.java deleted file mode 100644 index 599b1ff68..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Binary32.java +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright 2013 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.opengl.math; - -/** - * Functions for interrogating <code>binary32</code> (float) values. - */ - -public final class Binary32 -{ - static final int NEGATIVE_ZERO_BITS; - static final int MASK_SIGN; - static final int MASK_EXPONENT; - static final int MASK_SIGNIFICAND; - static final int BIAS; - - static { - NEGATIVE_ZERO_BITS = 0x80000000; - MASK_SIGN = 0x80000000; - MASK_EXPONENT = 0x7ff00000; - MASK_SIGNIFICAND = 0x7fffff; - BIAS = 127; - } - - /** - * <p> - * Extract and unbias the exponent of the given packed <code>float</code> - * value. - * </p> - * <p> - * The exponent is encoded <i>biased</i> as a number in the range - * <code>[0, 255]</code>, with <code>0</code> indicating that the number is - * <i>subnormal</i> and <code>[1, 254]</code> denoting the actual exponent - * plus {@link #BIAS}. Infinite and <code>NaN</code> values always have a - * biased exponent of <code>255</code>. - * </p> - * <p> - * This function will therefore return: - * </p> - * <ul> - * <li> - * <code>0 - {@link #BIAS} = -127</code> iff the input is a <i>subnormal</i> - * number.</li> - * <li>An integer in the range - * <code>[1 - {@link #BIAS}, 254 - {@link #BIAS}] = [-126, 127]</code> iff - * the input is a <i>normal</i> number.</li> - * <li> - * <code>255 - {@link #BIAS} = 128</code> iff the input is - * {@link #POSITIVE_INFINITY}, {@link #NEGATIVE_INFINITY}, or - * <code>NaN</code>.</li> - * </ul> - * - * @see #packSetExponentUnbiasedUnchecked(int) - */ - - public static int unpackGetExponentUnbiased( - final float d) - { - final int b = Float.floatToRawIntBits(d); - final int em = b & Binary32.MASK_EXPONENT; - final int es = em >> 23; - return es - Binary32.BIAS; - } - - /** - * <p> - * Return the sign of the given float value. - * </p> - */ - - public static int unpackGetSign( - final float d) - { - final int b = Float.floatToRawIntBits(d); - return ((b & Binary32.MASK_SIGN) >> 31) & 1; - } - - /** - * <p> - * Return the significand of the given float value. - * </p> - */ - - public static int unpackGetSignificand( - final float d) - { - final int b = Float.floatToRawIntBits(d); - return b & Binary32.MASK_SIGNIFICAND; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Binary64.java b/src/jogl/classes/com/jogamp/opengl/math/Binary64.java deleted file mode 100644 index d4ec636a5..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Binary64.java +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright 2013 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.opengl.math; - -/** - * Functions for interrogating <code>binary64</code> (double) values. - */ - -public final class Binary64 -{ - static final long NEGATIVE_ZERO_BITS; - static final long MASK_SIGN; - static final long MASK_EXPONENT; - static final long MASK_SIGNIFICAND; - static final long BIAS; - - static { - NEGATIVE_ZERO_BITS = 0x8000000000000000L; - MASK_SIGN = 0x8000000000000000L; - MASK_EXPONENT = 0x7ff0000000000000L; - MASK_SIGNIFICAND = 0x000fffffffffffffL; - BIAS = 1023; - } - - /** - * <p> - * Extract and unbias the exponent of the given packed <code>double</code> - * value. - * </p> - * <p> - * The exponent is encoded <i>biased</i> as a number in the range - * <code>[0, 2047]</code>, with <code>0</code> indicating that the number is - * <i>subnormal</i> and <code>[1, 2046]</code> denoting the actual exponent - * plus {@link #BIAS}. Infinite and <code>NaN</code> values always have a - * biased exponent of <code>2047</code>. - * </p> - * <p> - * This function will therefore return: - * </p> - * <ul> - * <li> - * <code>0 - {@link #BIAS} = -1023</code> iff the input is a - * <i>subnormal</i> number.</li> - * <li>An integer in the range - * <code>[1 - {@link #BIAS}, 2046 - {@link #BIAS}] = [-1022, 1023]</code> - * iff the input is a <i>normal</i> number.</li> - * <li> - * <code>2047 - {@link #BIAS} = 1024</code> iff the input is - * {@link #POSITIVE_INFINITY}, {@link #NEGATIVE_INFINITY}, or - * <code>NaN</code>.</li> - * </ul> - * - * @see #packSetExponentUnbiasedUnchecked(int) - */ - - public static long unpackGetExponentUnbiased( - final double d) - { - final long b = Double.doubleToRawLongBits(d); - final long em = b & Binary64.MASK_EXPONENT; - final long es = em >> 52; - return es - Binary64.BIAS; - } - - /** - * <p> - * Return the significand of the given double value. - * </p> - */ - - public static long unpackGetSignificand( - final double d) - { - final long b = Double.doubleToRawLongBits(d); - return b & Binary64.MASK_SIGNIFICAND; - } - - /** - * <p> - * Return the sign of the given double value. - * </p> - */ - - public static long unpackGetSign( - final double d) - { - final long b = Double.doubleToRawLongBits(d); - return ((b & Binary64.MASK_SIGN) >> 63) & 1; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/FixedPoint.java b/src/jogl/classes/com/jogamp/opengl/math/FixedPoint.java deleted file mode 100644 index 31408b079..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/FixedPoint.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - */ - -package com.jogamp.opengl.math; - -public class FixedPoint { - public static final int toFixed(int value) { - if (value < -32768) value = -32768; - if (value > 32767) value = 32767; - return value * 65536; - } - - public static final int toFixed(float value) { - if (value < -32768) value = -32768; - if (value > 32767) value = 32767; - return (int)(value * 65536.0f); - } - - public static final float toFloat(final int value) { - return value/65536.0f; - } - - public static final int mult(final int x1, final int x2) { - return (int) ( ((long)x1*(long)x2)/65536 ); - } - - public static final int div(final int x1, final int x2) { - return (int) ( (((long)x1)<<16)/x2 ); - } -} - diff --git a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java deleted file mode 100644 index 25b5a8ad7..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java +++ /dev/null @@ -1,1628 +0,0 @@ -/** - * Copyright 2010-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.math; - -import java.nio.FloatBuffer; -import java.util.Locale; - -import com.jogamp.opengl.GLException; - -import jogamp.opengl.Debug; - -import com.jogamp.common.os.Platform; - -/** - * Basic Float math utility functions. - * <p> - * Implementation assumes linear matrix layout in column-major order - * matching OpenGL's implementation, illustration: - * <pre> - Row-Major Column-Major (OpenGL): - - | 0 1 2 tx | - | | - | 4 5 6 ty | - M = | | - | 8 9 10 tz | - | | - | 12 13 14 15 | - - R C R C - m[0*4+3] = tx; m[0+4*3] = tx; - m[1*4+3] = ty; m[1+4*3] = ty; - m[2*4+3] = tz; m[2+4*3] = tz; - - RC (std subscript order) RC (std subscript order) - m03 = tx; m03 = tx; - m13 = ty; m13 = ty; - m23 = tz; m23 = tz; - - * </pre> - * </p> - * <p> - * <ul> - * <li><a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix-FAQ</a></li> - * <li><a href="https://en.wikipedia.org/wiki/Matrix_%28mathematics%29">Wikipedia-Matrix</a></li> - * <li><a href="http://www.euclideanspace.com/maths/algebra/matrix/index.htm">euclideanspace.com-Matrix</a></li> - * </ul> - * </p> - * <p> - * Implementation utilizes unrolling of small vertices and matrices wherever possible - * while trying to access memory in a linear fashion for performance reasons, see: - * <ul> - * <li><a href="https://lessthanoptimal.github.io/Java-Matrix-Benchmark/">java-matrix-benchmark</a></li> - * <li><a href="https://github.com/lessthanoptimal/ejml">EJML Efficient Java Matrix Library</a></li> - * </ul> - * </p> - */ -public final class FloatUtil { - public static final boolean DEBUG = Debug.debugExplicit("Math"); - - // - // Matrix Ops - // Only a subset will remain here, try using Matrix4f and perhaps PMVMatrix, SyncMatrix4f16 or SyncMatrices4f16 - // - - /** - * Make matrix an identity matrix - * @param m 4x4 matrix in column-major order (also result) - * @return given matrix for chaining - */ - 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 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 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 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 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 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 - * @param top - * @param zNear - * @param zFar - * @return given matrix for chaining - * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear} - * or {@code left == right}, or {@code bottom == top}. - */ - 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) throws GLException { - if( zNear <= 0.0f || zFar <= zNear ) { - throw new GLException("Requirements zNear > 0 and zFar > zNear, but zNear "+zNear+", zFar "+zFar); - } - if( left == right || top == bottom) { - throw new GLException("GL_INVALID_VALUE: top,bottom and left,right must not be equal"); - } - 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 zNear2 = 2.0f*zNear; - final float dx=right-left; - final float dy=top-bottom; - final float dz=zFar-zNear; - final float A=(right+left)/dx; - final float B=(top+bottom)/dy; - final float C=-1.0f*(zFar+zNear)/dz; - final float D=-2.0f*(zFar*zNear)/dz; - - m[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; - - m[m_offset+2+4*3] = D; - m[m_offset+3+4*3] = 0f; - - return m; - } - - /** - * Make given matrix the perspective {@link #makeFrustum(float[], int, boolean, float, float, float, float, float, float) frustum} - * matrix based on given parameters. - * <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 frustum fields are set. - * @param fovy_rad angle in radians - * @param aspect aspect ratio width / height - * @param zNear - * @param zFar - * @return given matrix for chaining - * @throws GLException if {@code zNear <= 0} or {@code zFar <= zNear} - * @see #makeFrustum(float[], int, boolean, float, float, float, float, float, float) - */ - public static float[] makePerspective(final float[] m, final int m_off, final boolean initM, - final float fovy_rad, final float aspect, final float zNear, final float zFar) throws GLException { - final float top = tan(fovy_rad/2f) * zNear; // use tangent of half-fov ! - final float bottom = -1.0f * top; // -1f * fovhvTan.top * zNear - final float left = aspect * bottom; // aspect * -1f * fovhvTan.top * zNear - final float right = aspect * top; // aspect * fovhvTan.top * zNear - return 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 + 0 * 4 + 1] = mat4Tmp[0+up2_off]; // up2 - m[m_offset + 0 * 4 + 2] = -mat4Tmp[0]; // forward - m[m_offset + 0 * 4 + 3] = 0; - - m[m_offset + 1 * 4 + 0] = mat4Tmp[1+side_off]; // side - m[m_offset + 1 * 4 + 1] = mat4Tmp[1+up2_off]; // up2 - m[m_offset + 1 * 4 + 2] = -mat4Tmp[1]; // forward - m[m_offset + 1 * 4 + 3] = 0; - - m[m_offset + 2 * 4 + 0] = mat4Tmp[2+side_off]; // side - m[m_offset + 2 * 4 + 1] = mat4Tmp[2+up2_off]; // up2 - m[m_offset + 2 * 4 + 2] = -mat4Tmp[2]; // forward - m[m_offset + 2 * 4 + 3] = 0; - - m[m_offset + 3 * 4 + 0] = 0; - m[m_offset + 3 * 4 + 1] = 0; - m[m_offset + 3 * 4 + 2] = 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> - * To effectively use the generated pick matrix for picking, - * call {@link #makePick(float[], int, float, float, float, float, int[], int, float[]) makePick} - * and multiply a {@link #makePerspective(float[], int, boolean, float, float, float, float) custom perspective matrix} - * by this pick matrix. Then you may load the result onto the perspective matrix stack. - * </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 the center x-component of a picking region in window coordinates - * @param y the center y-component of a picking region in window coordinates - * @param deltaX the width of the picking region in window coordinates. - * @param deltaY the height of the picking region in window coordinates. - * @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 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, 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, mat4Tmp); - 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 - * @return given result matrix <i>mres</i> for chaining - */ - public static float[] transposeMatrix(final float[] msrc, final float[] mres) { - mres[0] = msrc[0*4]; - mres[1] = msrc[1*4]; - mres[2] = msrc[2*4]; - mres[3] = msrc[3*4]; - - final int i4_1 = 1*4; - mres[0+i4_1] = msrc[1+0*4]; - mres[1+i4_1] = msrc[1+1*4]; - mres[2+i4_1] = msrc[1+2*4]; - mres[3+i4_1] = msrc[1+3*4]; - - final int i4_2 = 2*4; - mres[0+i4_2] = msrc[2+0*4]; - mres[1+i4_2] = msrc[2+1*4]; - mres[2+i4_2] = msrc[2+2*4]; - mres[3+i4_2] = msrc[2+3*4]; - - final int i4_3 = 3*4; - mres[0+i4_3] = msrc[3+0*4]; - mres[1+i4_3] = msrc[3+1*4]; - mres[2+i4_3] = msrc[3+2*4]; - mres[3+i4_3] = msrc[3+3*4]; - - return mres; - } - - /** - * Returns the determinant of the given matrix - * @param m 4x4 matrix in column-major order, the source - * @return the matrix determinant - */ - public static float matrixDeterminant(final float[] m) { - float a11 = m[ 1+4*1 ]; - float a21 = m[ 2+4*1 ]; - float a31 = m[ 3+4*1 ]; - float a12 = m[ 1+4*2 ]; - float a22 = m[ 2+4*2 ]; - float a32 = m[ 3+4*2 ]; - float a13 = m[ 1+4*3 ]; - float a23 = m[ 2+4*3 ]; - float a33 = m[ 3+4*3 ]; - - float ret = 0; - ret += m[ 0 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); - a11 = m[ 1+4*0 ]; - a21 = m[ 2+4*0 ]; - a31 = m[ 3+4*0 ]; - ret -= m[ 0+4*1 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); - a12 = m[ 1+4*1 ]; - a22 = m[ 2+4*1 ]; - a32 = m[ 3+4*1 ]; - ret += m[ 0+4*2 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); - a13 = m[ 1+4*2 ]; - a23 = m[ 2+4*2 ]; - a33 = m[ 3+4*2 ]; - ret -= m[ 0+4*3 ] * ( + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31)); - return ret; - } - /** - * 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) - * @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 float[] mres) { - final float scale; - { - float max = Math.abs(msrc[0]); - - for( int i = 1; i < 16; i++ ) { - final float a = Math.abs(msrc[i]); - if( a > max ) max = a; - } - if( 0 == max ) { - return null; - } - scale = 1.0f/max; - } - - final float a11 = msrc[0+4*0]*scale; - final float a21 = msrc[1+4*0]*scale; - final float a31 = msrc[2+4*0]*scale; - final float a41 = msrc[3+4*0]*scale; - final float a12 = msrc[0+4*1]*scale; - final float a22 = msrc[1+4*1]*scale; - final float a32 = msrc[2+4*1]*scale; - final float a42 = msrc[3+4*1]*scale; - final float a13 = msrc[0+4*2]*scale; - final float a23 = msrc[1+4*2]*scale; - final float a33 = msrc[2+4*2]*scale; - final float a43 = msrc[3+4*2]*scale; - final float a14 = msrc[0+4*3]*scale; - final float a24 = msrc[1+4*3]*scale; - final float a34 = msrc[2+4*3]*scale; - final float a44 = msrc[3+4*3]*scale; - - final float m11 = + a22*(a33*a44 - a34*a43) - a23*(a32*a44 - a34*a42) + a24*(a32*a43 - a33*a42); - final float m12 = -( + a21*(a33*a44 - a34*a43) - a23*(a31*a44 - a34*a41) + a24*(a31*a43 - a33*a41)); - final float m13 = + a21*(a32*a44 - a34*a42) - a22*(a31*a44 - a34*a41) + a24*(a31*a42 - a32*a41); - final float m14 = -( + a21*(a32*a43 - a33*a42) - a22*(a31*a43 - a33*a41) + a23*(a31*a42 - a32*a41)); - final float m21 = -( + a12*(a33*a44 - a34*a43) - a13*(a32*a44 - a34*a42) + a14*(a32*a43 - a33*a42)); - final float m22 = + a11*(a33*a44 - a34*a43) - a13*(a31*a44 - a34*a41) + a14*(a31*a43 - a33*a41); - final float m23 = -( + a11*(a32*a44 - a34*a42) - a12*(a31*a44 - a34*a41) + a14*(a31*a42 - a32*a41)); - final float m24 = + a11*(a32*a43 - a33*a42) - a12*(a31*a43 - a33*a41) + a13*(a31*a42 - a32*a41); - final float m31 = + a12*(a23*a44 - a24*a43) - a13*(a22*a44 - a24*a42) + a14*(a22*a43 - a23*a42); - final float m32 = -( + a11*(a23*a44 - a24*a43) - a13*(a21*a44 - a24*a41) + a14*(a21*a43 - a23*a41)); - final float m33 = + a11*(a22*a44 - a24*a42) - a12*(a21*a44 - a24*a41) + a14*(a21*a42 - a22*a41); - final float m34 = -( + a11*(a22*a43 - a23*a42) - a12*(a21*a43 - a23*a41) + a13*(a21*a42 - a22*a41)); - final float m41 = -( + a12*(a23*a34 - a24*a33) - a13*(a22*a34 - a24*a32) + a14*(a22*a33 - a23*a32)); - final float m42 = + a11*(a23*a34 - a24*a33) - a13*(a21*a34 - a24*a31) + a14*(a21*a33 - a23*a31); - final float m43 = -( + a11*(a22*a34 - a24*a32) - a12*(a21*a34 - a24*a31) + a14*(a21*a32 - a22*a31)); - final float m44 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31); - - final float det = (a11*m11 + a12*m12 + a13*m13 + a14*m14)/scale; - if( 0 == det ) { - return null; - } - final float invdet = 1.0f / det; - - mres[0+4*0] = m11 * invdet; - mres[1+4*0] = m12 * invdet; - mres[2+4*0] = m13 * invdet; - mres[3+4*0] = m14 * invdet; - mres[0+4*1] = m21 * invdet; - mres[1+4*1] = m22 * invdet; - mres[2+4*1] = m23 * invdet; - mres[3+4*1] = m24 * invdet; - mres[0+4*2] = m31 * invdet; - mres[1+4*2] = m32 * invdet; - mres[2+4*2] = m33 * invdet; - mres[3+4*2] = m34 * invdet; - mres[0+4*3] = m41 * invdet; - mres[1+4*3] = m42 * invdet; - mres[2+4*3] = m43 * invdet; - mres[3+4*3] = m44 * invdet; - 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 mapObjToWin(final float objx, final float objy, final float objz, - final float[] modelMatrix, final int modelMatrix_offset, - final float[] projMatrix, final int projMatrix_offset, - final int[] viewport, final int viewport_offset, - final float[] win_pos, final int win_pos_offset, - final float[/*4*/] vec4Tmp1, final float[/*4*/] vec4Tmp2) { - vec4Tmp1[0] = objx; - vec4Tmp1[1] = objy; - vec4Tmp1[2] = objz; - 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 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 mapWinToObj(final float winx, final float winy, final float winz, - final float[] modelMatrix, final int modelMatrix_offset, - final float[] projMatrix, final int projMatrix_offset, - final int[] viewport, final int viewport_offset, - final float[] obj_pos, final int obj_pos_offset, - final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) { - // mat4Tmp1 = P x Mv - multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0); - - // mat4Tmp1 = Inv(P x Mv) - if ( null == invertMatrix(mat4Tmp1, mat4Tmp1) ) { - 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>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 mapWinToObj4(final float winx, final float winy, final float winz, final float clipw, - final float[] modelMatrix, final int modelMatrix_offset, - final float[] projMatrix, final int projMatrix_offset, - final int[] viewport, final int viewport_offset, - final float near, final float far, - final float[] obj_pos, final int obj_pos_offset, - final float[/*16*/] mat4Tmp1, final float[/*16*/] mat4Tmp2) { - // mat4Tmp1 = P x Mv - multMatrix(projMatrix, projMatrix_offset, modelMatrix, modelMatrix_offset, mat4Tmp1, 0); - - // mat4Tmp1 = Inv(P x Mv) - if ( null == invertMatrix(mat4Tmp1, mat4Tmp1) ) { - return false; - } - - mat4Tmp2[0] = winx; - mat4Tmp2[1] = winy; - mat4Tmp2[2] = winz; - mat4Tmp2[3] = clipw; - - // 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; - } - - 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; - } - - /** - * 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, final float[] d, final int d_off) { - final float b00 = b[b_off+0+0*4]; - final float b10 = b[b_off+1+0*4]; - final float b20 = b[b_off+2+0*4]; - final float b30 = b[b_off+3+0*4]; - final float b01 = b[b_off+0+1*4]; - final float b11 = b[b_off+1+1*4]; - final float b21 = b[b_off+2+1*4]; - final float b31 = b[b_off+3+1*4]; - final float b02 = b[b_off+0+2*4]; - final float b12 = b[b_off+1+2*4]; - final float b22 = b[b_off+2+2*4]; - final float b32 = b[b_off+3+2*4]; - final float b03 = b[b_off+0+3*4]; - final float b13 = b[b_off+1+3*4]; - final float b23 = b[b_off+2+3*4]; - final float b33 = b[b_off+3+3*4]; - - float ai0=a[a_off+ 0*4]; // row-0 of a - float ai1=a[a_off+ 1*4]; - float ai2=a[a_off+ 2*4]; - float ai3=a[a_off+ 3*4]; - d[d_off+ 0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - d[d_off+ 1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - d[d_off+ 2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - d[d_off+ 3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[a_off+1+0*4]; // row-1 of a - ai1=a[a_off+1+1*4]; - ai2=a[a_off+1+2*4]; - ai3=a[a_off+1+3*4]; - d[d_off+1+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - d[d_off+1+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - d[d_off+1+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - d[d_off+1+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[a_off+2+0*4]; // row-2 of a - ai1=a[a_off+2+1*4]; - ai2=a[a_off+2+2*4]; - ai3=a[a_off+2+3*4]; - d[d_off+2+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - d[d_off+2+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - d[d_off+2+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - d[d_off+2+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[a_off+3+0*4]; // row-3 of a - ai1=a[a_off+3+1*4]; - ai2=a[a_off+3+2*4]; - ai3=a[a_off+3+3*4]; - d[d_off+3+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - d[d_off+3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - d[d_off+3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - d[d_off+3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - } - - /** - * 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 - * @return given result matrix <i>d</i> for chaining - */ - public static float[] multMatrix(final float[] a, final float[] b, final float[] d) { - final float b00 = b[0+0*4]; - final float b10 = b[1+0*4]; - final float b20 = b[2+0*4]; - final float b30 = b[3+0*4]; - final float b01 = b[0+1*4]; - final float b11 = b[1+1*4]; - final float b21 = b[2+1*4]; - final float b31 = b[3+1*4]; - final float b02 = b[0+2*4]; - final float b12 = b[1+2*4]; - final float b22 = b[2+2*4]; - final float b32 = b[3+2*4]; - final float b03 = b[0+3*4]; - final float b13 = b[1+3*4]; - final float b23 = b[2+3*4]; - final float b33 = b[3+3*4]; - - float ai0=a[ 0*4]; // row-0 of a - float ai1=a[ 1*4]; - float ai2=a[ 2*4]; - float ai3=a[ 3*4]; - d[ 0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - d[ 1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - d[ 2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - d[ 3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[1+0*4]; // row-1 of a - ai1=a[1+1*4]; - ai2=a[1+2*4]; - ai3=a[1+3*4]; - d[1+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - d[1+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - d[1+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - d[1+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[2+0*4]; // row-2 of a - ai1=a[2+1*4]; - ai2=a[2+2*4]; - ai3=a[2+3*4]; - d[2+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - d[2+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - d[2+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - d[2+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[3+0*4]; // row-3 of a - ai1=a[3+1*4]; - ai2=a[3+2*4]; - ai3=a[3+3*4]; - d[3+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - d[3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - d[3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - d[3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - return d; - } - - /** - * 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 int a_off, final float[] b, final int b_off) { - final float b00 = b[b_off+0+0*4]; - final float b10 = b[b_off+1+0*4]; - final float b20 = b[b_off+2+0*4]; - final float b30 = b[b_off+3+0*4]; - final float b01 = b[b_off+0+1*4]; - final float b11 = b[b_off+1+1*4]; - final float b21 = b[b_off+2+1*4]; - final float b31 = b[b_off+3+1*4]; - final float b02 = b[b_off+0+2*4]; - final float b12 = b[b_off+1+2*4]; - final float b22 = b[b_off+2+2*4]; - final float b32 = b[b_off+3+2*4]; - final float b03 = b[b_off+0+3*4]; - final float b13 = b[b_off+1+3*4]; - final float b23 = b[b_off+2+3*4]; - final float b33 = b[b_off+3+3*4]; - - float ai0=a[a_off+ 0*4]; // row-0 of a - float ai1=a[a_off+ 1*4]; - float ai2=a[a_off+ 2*4]; - float ai3=a[a_off+ 3*4]; - a[a_off+ 0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - a[a_off+ 1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - a[a_off+ 2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - a[a_off+ 3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[a_off+1+0*4]; // row-1 of a - ai1=a[a_off+1+1*4]; - ai2=a[a_off+1+2*4]; - ai3=a[a_off+1+3*4]; - a[a_off+1+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - a[a_off+1+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - a[a_off+1+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - a[a_off+1+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[a_off+2+0*4]; // row-2 of a - ai1=a[a_off+2+1*4]; - ai2=a[a_off+2+2*4]; - ai3=a[a_off+2+3*4]; - a[a_off+2+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - a[a_off+2+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - a[a_off+2+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - a[a_off+2+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[a_off+3+0*4]; // row-3 of a - ai1=a[a_off+3+1*4]; - ai2=a[a_off+3+2*4]; - ai3=a[a_off+3+3*4]; - a[a_off+3+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - a[a_off+3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - a[a_off+3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - a[a_off+3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - } - - /** - * Multiply matrix: [a] = [a] x [b] - * @param a 4x4 matrix in column-major order (also result) - * @param b 4x4 matrix in column-major order - * @return given result matrix <i>a</i> for chaining - */ - public static float[] multMatrix(final float[] a, final float[] b) { - final float b00 = b[0+0*4]; - final float b10 = b[1+0*4]; - final float b20 = b[2+0*4]; - final float b30 = b[3+0*4]; - final float b01 = b[0+1*4]; - final float b11 = b[1+1*4]; - final float b21 = b[2+1*4]; - final float b31 = b[3+1*4]; - final float b02 = b[0+2*4]; - final float b12 = b[1+2*4]; - final float b22 = b[2+2*4]; - final float b32 = b[3+2*4]; - final float b03 = b[0+3*4]; - final float b13 = b[1+3*4]; - final float b23 = b[2+3*4]; - final float b33 = b[3+3*4]; - - float ai0=a[ 0*4]; // row-0 of a - float ai1=a[ 1*4]; - float ai2=a[ 2*4]; - float ai3=a[ 3*4]; - a[ 0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - a[ 1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - a[ 2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - a[ 3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[1+0*4]; // row-1 of a - ai1=a[1+1*4]; - ai2=a[1+2*4]; - ai3=a[1+3*4]; - a[1+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - a[1+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - a[1+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - a[1+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[2+0*4]; // row-2 of a - ai1=a[2+1*4]; - ai2=a[2+2*4]; - ai3=a[2+3*4]; - a[2+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - a[2+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - a[2+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - a[2+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - ai0=a[3+0*4]; // row-3 of a - ai1=a[3+1*4]; - ai2=a[3+2*4]; - ai3=a[3+3*4]; - a[3+0*4] = ai0 * b00 + ai1 * b10 + ai2 * b20 + ai3 * b30 ; - a[3+1*4] = ai0 * b01 + ai1 * b11 + ai2 * b21 + ai3 * b31 ; - a[3+2*4] = ai0 * b02 + ai1 * b12 + ai2 * b22 + ai3 * b32 ; - a[3+3*4] = ai0 * b03 + ai1 * b13 + ai2 * b23 + ai3 * b33 ; - - return a; - } - - /** - * 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) ; - } - } - - /** - * 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 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 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) ); - } - } - - /** - * @param m_in 4x4 matrix in column-major order - * @param m_in_off - * @param v_in 4-component column-vector - * @param v_out m_in * v_in - */ - public static void multMatrixVec(final float[] m_in, final int m_in_off, - final float[] v_in, final int v_in_off, - final float[] v_out, final int v_out_off) { - // (one matrix row in column-major order) X (column vector) - v_out[0 + v_out_off] = v_in[0+v_in_off] * m_in[0*4+m_in_off ] + v_in[1+v_in_off] * m_in[1*4+m_in_off ] + - v_in[2+v_in_off] * m_in[2*4+m_in_off ] + v_in[3+v_in_off] * m_in[3*4+m_in_off ]; - - final int m_in_off_1 = 1+m_in_off; - v_out[1 + v_out_off] = v_in[0+v_in_off] * m_in[0*4+m_in_off_1] + v_in[1+v_in_off] * m_in[1*4+m_in_off_1] + - v_in[2+v_in_off] * m_in[2*4+m_in_off_1] + v_in[3+v_in_off] * m_in[3*4+m_in_off_1]; - - final int m_in_off_2 = 2+m_in_off; - v_out[2 + v_out_off] = v_in[0+v_in_off] * m_in[0*4+m_in_off_2] + v_in[1+v_in_off] * m_in[1*4+m_in_off_2] + - v_in[2+v_in_off] * m_in[2*4+m_in_off_2] + v_in[3+v_in_off] * m_in[3*4+m_in_off_2]; - - final int m_in_off_3 = 3+m_in_off; - v_out[3 + v_out_off] = v_in[0+v_in_off] * m_in[0*4+m_in_off_3] + v_in[1+v_in_off] * m_in[1*4+m_in_off_3] + - v_in[2+v_in_off] * m_in[2*4+m_in_off_3] + v_in[3+v_in_off] * m_in[3*4+m_in_off_3]; - } - - /** - * @param m_in 4x4 matrix in column-major order - * @param m_in_off - * @param v_in 4-component column-vector - * @param v_out m_in * v_in - */ - public static void multMatrixVec(final float[] m_in, final int m_in_off, - final float[] v_in, final float[] v_out) { - // (one matrix row in column-major order) X (column vector) - v_out[0] = v_in[0] * m_in[0*4+m_in_off ] + v_in[1] * m_in[1*4+m_in_off ] + - v_in[2] * m_in[2*4+m_in_off ] + v_in[3] * m_in[3*4+m_in_off ]; - - final int m_in_off_1 = 1+m_in_off; - v_out[1] = v_in[0] * m_in[0*4+m_in_off_1] + v_in[1] * m_in[1*4+m_in_off_1] + - v_in[2] * m_in[2*4+m_in_off_1] + v_in[3] * m_in[3*4+m_in_off_1]; - - final int m_in_off_2 = 2+m_in_off; - v_out[2] = v_in[0] * m_in[0*4+m_in_off_2] + v_in[1] * m_in[1*4+m_in_off_2] + - v_in[2] * m_in[2*4+m_in_off_2] + v_in[3] * m_in[3*4+m_in_off_2]; - - final int m_in_off_3 = 3+m_in_off; - v_out[3] = v_in[0] * m_in[0*4+m_in_off_3] + v_in[1] * m_in[1*4+m_in_off_3] + - v_in[2] * m_in[2*4+m_in_off_3] + v_in[3] * m_in[3*4+m_in_off_3]; - } - - /** - * @param m_in 4x4 matrix in column-major order - * @param m_in_off - * @param v_in 4-component column-vector - * @param v_out m_in * v_in - * @return given result vector <i>v_out</i> for chaining - */ - public static float[] multMatrixVec(final float[] m_in, final float[] v_in, final float[] v_out) { - // (one matrix row in column-major order) X (column vector) - v_out[0] = v_in[0] * m_in[0*4 ] + v_in[1] * m_in[1*4 ] + - v_in[2] * m_in[2*4 ] + v_in[3] * m_in[3*4 ]; - - v_out[1] = v_in[0] * m_in[0*4+1] + v_in[1] * m_in[1*4+1] + - v_in[2] * m_in[2*4+1] + v_in[3] * m_in[3*4+1]; - - v_out[2] = v_in[0] * m_in[0*4+2] + v_in[1] * m_in[1*4+2] + - v_in[2] * m_in[2*4+2] + v_in[3] * m_in[3*4+2]; - - v_out[3] = v_in[0] * m_in[0*4+3] + v_in[1] * m_in[1*4+3] + - v_in[2] * m_in[2*4+3] + v_in[3] * m_in[3*4+3]; - - return v_out; - } - - /** - * @param m_in 4x4 matrix in column-major order - * @param v_in 4-component column-vector - * @param v_out m_in * v_in - */ - 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_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); - } - } - - /** - * Affine 3f-vector transformation by 4x4 matrix - * - * 4x4 matrix multiplication with 3-component vector, - * using {@code 1} for for {@code v_in[3]} and dropping {@code v_out[3]}, - * which shall be {@code 1}. - * - * @param m_in 4x4 matrix in column-major order - * @param m_in_off - * @param v_in 3-component column-vector - * @param v_out m_in * v_in, 3-component column-vector - * @return given result vector <i>v_out</i> for chaining - */ - public static float[] multMatrixVec3(final float[] m_in, final float[] v_in, final float[] v_out) { - // (one matrix row in column-major order) X (column vector) - v_out[0] = v_in[0] * m_in[0*4 ] + v_in[1] * m_in[1*4 ] + - v_in[2] * m_in[2*4 ] + 1f * m_in[3*4 ]; - - v_out[1] = v_in[0] * m_in[0*4+1] + v_in[1] * m_in[1*4+1] + - v_in[2] * m_in[2*4+1] + 1f * m_in[3*4+1]; - - v_out[2] = v_in[0] * m_in[0*4+2] + v_in[1] * m_in[1*4+2] + - v_in[2] * m_in[2*4+2] + 1f * m_in[3*4+2]; - - return v_out; - } - - /** - * @param sb optional passed StringBuilder instance to be used - * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter} - * @param a mxn matrix (rows x columns) - * @param aOffset offset to <code>a</code>'s current position - * @param rows - * @param columns - * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL) - * @param row row number to print - * @return matrix row string representation - */ - 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(); - } - final int a0 = aOffset + a.position(); - if(rowMajorOrder) { - for(int c=0; c<columns; c++) { - sb.append( String.format((Locale)null, f+", ", a.get( a0 + row*columns + c ) ) ); - } - } else { - for(int r=0; r<columns; r++) { - sb.append( String.format((Locale)null, f+", ", a.get( a0 + row + r*rows ) ) ); - } - } - return sb; - } - - /** - * @param sb optional passed StringBuilder instance to be used - * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter} - * @param a mxn matrix (rows x columns) - * @param aOffset offset to <code>a</code>'s current position - * @param rows - * @param columns - * @param rowMajorOrder if true floats are layed out in row-major-order, otherwise column-major-order (OpenGL) - * @param row row number to print - * @return matrix row string representation - */ - 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(); - } - if(rowMajorOrder) { - for(int c=0; c<columns; c++) { - sb.append( String.format((Locale)null, f+", ", a[ aOffset + row*columns + c ] ) ); - } - } else { - for(int r=0; r<columns; r++) { - sb.append( String.format((Locale)null, f+", ", a[ aOffset + row + r*rows ] ) ); - } - } - return sb; - } - - /** - * @param sb optional passed StringBuilder instance to be used - * @param rowPrefix optional prefix for each row - * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter} - * @param a mxn matrix (rows x columns) - * @param aOffset offset to <code>a</code>'s current position - * @param rows - * @param columns - * @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, 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(); - } - final String prefix = ( null == rowPrefix ) ? "" : rowPrefix; - sb.append(prefix).append("{ "); - for(int i=0; i<rows; i++) { - if( 0 < i ) { - sb.append(prefix).append(" "); - } - matrixRowToString(sb, f, a, aOffset, rows, columns, rowMajorOrder, i); - sb.append(System.lineSeparator()); - } - sb.append(prefix).append("}").append(System.lineSeparator()); - return sb; - } - - /** - * @param sb optional passed StringBuilder instance to be used - * @param rowPrefix optional prefix for each row - * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter} - * @param a mxn matrix (rows x columns) - * @param aOffset offset to <code>a</code>'s current position - * @param rows - * @param columns - * @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, 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(); - } - final String prefix = ( null == rowPrefix ) ? "" : rowPrefix; - sb.append(prefix).append("{ "); - for(int i=0; i<rows; i++) { - if( 0 < i ) { - sb.append(prefix).append(" "); - } - matrixRowToString(sb, f, a, aOffset, rows, columns, rowMajorOrder, i); - sb.append(System.lineSeparator()); - } - sb.append(prefix).append("}").append(System.lineSeparator()); - return sb; - } - - // - // Scalar Ops - // - - @SuppressWarnings("unused") - private static void calculateMachineEpsilonFloat() { - final long t0; - if( DEBUG_EPSILON ) { - t0 = Platform.currentTimeMillis(); - } - float machEps = 1.0f; - int i=0; - do { - machEps /= 2.0f; - i++; - } while (1.0f + (machEps / 2.0f) != 1.0f); - machEpsilon = machEps; - if( DEBUG_EPSILON ) { - final long t1 = Platform.currentTimeMillis(); - System.err.println("MachineEpsilon: "+machEpsilon+", in "+i+" iterations within "+(t1-t0)+" ms"); - } - } - private static volatile boolean machEpsilonAvail = false; - private static float machEpsilon = 0f; - private static final boolean DEBUG_EPSILON = false; - - /** - * Return computed machine Epsilon value. - * <p> - * The machine Epsilon value is computed once. - * </p> - * <p> - * On a reference machine the result was {@link #EPSILON} in 23 iterations. - * </p> - * @see #EPSILON - */ - public static float getMachineEpsilon() { - if( !machEpsilonAvail ) { - synchronized(FloatUtil.class) { - if( !machEpsilonAvail ) { - machEpsilonAvail = true; - calculateMachineEpsilonFloat(); - } - } - } - return machEpsilon; - } - - public static final float E = 2.7182818284590452354f; - - /** The value PI, i.e. 180 degrees in radians. */ - public static final float PI = 3.14159265358979323846f; - - /** The value 2PI, i.e. 360 degrees in radians. */ - public static final float TWO_PI = 2f * PI; - - /** The value PI/2, i.e. 90 degrees in radians. */ - public static final float HALF_PI = PI / 2f; - - /** The value PI/4, i.e. 45 degrees in radians. */ - public static final float QUARTER_PI = PI / 4f; - - /** The value PI^2. */ - public final static float SQUARED_PI = PI * PI; - - /** Converts arc-degree to radians */ - public static float adegToRad(final float arc_degree) { - return arc_degree * PI / 180.0f; - } - - /** Converts radians to arc-degree */ - public static float radToADeg(final float rad) { - return rad * 180.0f / PI; - } - - /** - * Epsilon for floating point {@value}, as once computed via {@link #getMachineEpsilon()} on an AMD-64 CPU. - * <p> - * Definition of machine epsilon guarantees that: - * <pre> - * 1.0f + EPSILON != 1.0f - * </pre> - * In other words: <i>machEps</i> is the maximum relative error of the chosen rounding procedure. - * </p> - * <p> - * A number can be considered zero if it is in the range (or in the set): - * <pre> - * <b>MaybeZeroSet</b> e ]-<i>machEps</i> .. <i>machEps</i>[ <i>(exclusive)</i> - * </pre> - * While comparing floating point values, <i>machEps</i> allows to clip the relative error: - * <pre> - * boolean isZero = afloat < EPSILON; - * boolean isNotZero = afloat >= EPSILON; - * - * boolean isEqual = abs(bfloat - afloat) < EPSILON; - * boolean isNotEqual = abs(bfloat - afloat) >= EPSILON; - * </pre> - * </p> - * @see #isEqual(float, float, float) - * @see #isZero(float, float) - */ - public static final float EPSILON = 1.1920929E-7f; // Float.MIN_VALUE == 1.4e-45f ; double EPSILON 2.220446049250313E-16d - - /** - * Inversion Epsilon, used with equals method to determine if two inverted matrices are close enough to be considered equal. - * <p> - * Using {@value}, which is ~100 times {@link FloatUtil#EPSILON}. - * </p> - */ - public static final float INV_DEVIANCE = 1.0E-5f; // FloatUtil.EPSILON == 1.1920929E-7f; double ALLOWED_DEVIANCE: 1.0E-8f - - /** - * Return true if both values are equal w/o regarding an epsilon. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * </p> - * @see #isEqual(float, float, float) - */ - public static boolean isEqualRaw(final float a, final float b) { - // Values are equal (Inf, Nan .. ) - return Float.floatToIntBits(a) == Float.floatToIntBits(b); - } - - /** - * Return true if both values are equal, i.e. their absolute delta < <code>epsilon</code>. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * </p> - * @see #EPSILON - */ - public static boolean isEqual(final float a, final float b, final float epsilon) { - if ( Math.abs(a - b) < epsilon ) { - return true; - } else { - // Values are equal (Inf, Nan .. ) - return Float.floatToIntBits(a) == Float.floatToIntBits(b); - } - } - - /** - * Return true if both values are equal, i.e. their absolute delta < {@link #EPSILON}. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * </p> - * @see #EPSILON - */ - public static boolean isEqual(final float a, final float b) { - if ( Math.abs(a - b) < EPSILON ) { - return true; - } else { - // Values are equal (Inf, Nan .. ) - return Float.floatToIntBits(a) == Float.floatToIntBits(b); - } - } - - /** - * Return true if both values are equal, i.e. their absolute delta < {@link #EPSILON}. - * <p> - * Implementation does not consider corner cases like {@link #isEqual(float, float, float)}. - * </p> - * @see #EPSILON - */ - public static boolean isEqual2(final float a, final float b) { - return Math.abs(a - b) < EPSILON; - } - - /** - * Return true if both values are equal w/o regarding an epsilon. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * <li>NaN > 0</li> - * <li>+Inf > -Inf</li> - * </ul> - * </p> - * @see #compare(float, float, float) - */ - public static int compare(final float a, final float b) { - if (a < b) { - return -1; // Neither is NaN, a is smaller - } - if (a > b) { - return 1; // Neither is NaN, a is larger - } - final int aBits = Float.floatToIntBits(a); - final int bBits = Float.floatToIntBits(b); - if( aBits == bBits ) { - return 0; // Values are equal (Inf, Nan .. ) - } else if( aBits < bBits ) { - return -1; // (-0.0, 0.0) or (!NaN, NaN) - } else { - return 1; // ( 0.0, -0.0) or ( NaN, !NaN) - } - } - - /** - * Return true if both values are equal, i.e. their absolute delta < <code>epsilon</code>. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * <li>NaN > 0</li> - * <li>+Inf > -Inf</li> - * </ul> - * </p> - * @see #EPSILON - */ - public static int compare(final float a, final float b, final float epsilon) { - if ( Math.abs(a - b) < epsilon ) { - return 0; - } else { - return compare(a, b); - } - } - - /** - * Return true if value is zero, i.e. it's absolute value < <code>epsilon</code>. - * @see #EPSILON - */ - public static boolean isZero(final float a, final float epsilon) { - return Math.abs(a) < epsilon; - } - - /** - * Return true if value is zero, i.e. it's absolute value < {@link #EPSILON}. - * @see #EPSILON - */ - public static boolean isZero(final float a) { - return Math.abs(a) < FloatUtil.EPSILON; - } - - /** - * Invokes {@link Math#abs(float)} - * @param a float to process - * @return absolute value of {@code a} - * @deprecated use {@link Math#abs(float)} directly - */ - @Deprecated - public static float abs(final float a) { return java.lang.Math.abs(a); } - - public static float pow(final float a, final float b) { return (float) java.lang.Math.pow(a, b); } - - public static float sin(final float a) { return (float) java.lang.Math.sin(a); } - - public static float asin(final float a) { return (float) java.lang.Math.asin(a); } - - public static float cos(final float a) { return (float) java.lang.Math.cos(a); } - - public static float acos(final float a) { return (float) java.lang.Math.acos(a); } - - public static float tan(final float a) { return (float) java.lang.Math.tan(a); } - - public static float atan(final float a) { return (float) java.lang.Math.atan(a); } - - public static float atan2(final float y, final float x) { return (float) java.lang.Math.atan2(y, x); } - - public static float sqrt(final float a) { return (float) java.lang.Math.sqrt(a); } - - /** - * Returns resolution of Z buffer of given parameter, - * see <a href="http://www.sjbaker.org/steve/omniv/love_your_z_buffer.html">Love Your Z-Buffer</a>. - * <pre> - * return z * z / ( zNear * (1<<zBits) - z ) - * </pre> - * Examples: - * <pre> - * 1.5256461E-4 = 16 zBits, -0.2 zDist, 0.1 zNear - * 6.1033297E-6 = 16 zBits, -1.0 zDist, 0.1 zNear - * </pre> - * @param zBits number of bits of Z precision, i.e. z-buffer depth - * @param z distance from the eye to the object - * @param zNear distance from eye to near clip plane - * @return smallest resolvable Z separation at this range. - */ - 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>. - * <pre> - * float a = zFar / ( zFar - zNear ) - * float b = zFar * zNear / ( zNear - zFar ) - * return (int) ( (1<<zBits) * ( a + b / z ) ) - * </pre> - * @param zBits number of bits of Z precision, i.e. z-buffer depth - * @param z distance from the eye to the object - * @param zNear distance from eye to near clip plane - * @param zFar distance from eye to far clip plane - * @return z buffer value - */ - public static int getZBufferValue(final int zBits, final float z, final float zNear, final float zFar) { - final float a = zFar / ( zFar - zNear ); - final float b = zFar * zNear / ( zNear - zFar ); - return (int) ( (1<<zBits) * ( a + b / z ) ); - } - - /** - * Returns orthogonal distance - * (1f/zNear-1f/orthoZ) / (1f/zNear-1f/zFar); - */ - public static float getOrthoWinZ(final float orthoZ, final float zNear, final float zFar) { - return (1f/zNear-1f/orthoZ) / (1f/zNear-1f/zFar); - } - -}
\ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/opengl/math/FovHVHalves.java b/src/jogl/classes/com/jogamp/opengl/math/FovHVHalves.java deleted file mode 100644 index 5d7907f2f..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/FovHVHalves.java +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Copyright 2014 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.math; - -/** - * Horizontal and vertical field of view (FOV) halves, - * allowing a non-centered projection. - * <p> - * The values might be either in tangent or radians. - * </p> - */ -public final class FovHVHalves { - /** Half horizontal FOV from center to left, either in {@link #inTangents} or radians. */ - public final float left; - /** Half horizontal FOV from center to right, either in {@link #inTangents} or radians. */ - public final float right; - /** Half vertical FOV from center to top, either in {@link #inTangents} or radians. */ - public final float top; - /** Half vertical FOV from center to bottom, either in {@link #inTangents} or radians. */ - public final float bottom; - /** If true, values are in tangent, otherwise radians.*/ - public final boolean inTangents; - - /** - * Constructor for one {@link FovHVHalves} instance. - * <p> - * It is recommended to pass and store values in tangent - * if used for perspective FOV calculations, since it will avoid conversion to tangent later on. - * </p> - * @param left half horizontal FOV, left side, in tangent or radians - * @param right half horizontal FOV, right side, in tangent or radians - * @param top half vertical FOV, top side, in tangent or radians - * @param bottom half vertical FOV, bottom side, in tangent or radians - * @param inTangents if true, values are in tangent, otherwise radians - */ - public FovHVHalves(final float left, final float right, final float top, final float bottom, final boolean inTangents) { - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; - this.inTangents = inTangents; - } - - /** - * Returns a symmetrical centered {@link FovHVHalves} instance in {@link #inTangents}, using: - * <pre> - halfHorizFovTan = tan( horizontalFov / 2f ); - halfVertFovTan = tan( verticalFov / 2f ); - * </pre> - * @param horizontalFov whole horizontal FOV in radians - * @param verticalFov whole vertical FOV in radians - */ - public static FovHVHalves byRadians(final float horizontalFov, final float verticalFov) { - final float halfHorizFovTan = FloatUtil.tan(horizontalFov/2f); - final float halfVertFovTan = FloatUtil.tan(verticalFov/2f); - return new FovHVHalves(halfHorizFovTan, halfHorizFovTan, halfVertFovTan, halfVertFovTan, true); - } - - /** - * Returns a symmetrical centered {@link FovHVHalves} instance in {@link #inTangents}, using: - * <pre> - top = bottom = tan( verticalFov / 2f ); - left = right = aspect * top; - * </pre> - * - * @param verticalFov vertical FOV in radians - * @param aspect aspect ration width / height - */ - public static FovHVHalves byFovyRadianAndAspect(final float verticalFov, final float aspect) { - final float halfVertFovTan = FloatUtil.tan(verticalFov/2f); - final float halfHorizFovTan = aspect * halfVertFovTan; - return new FovHVHalves(halfHorizFovTan, halfHorizFovTan, - halfVertFovTan, halfVertFovTan, true); - } - - /** - * Returns a custom symmetry {@link FovHVHalves} instance {@link #inTangents}, using: - * <pre> - left = tan( horizontalFov * horizCenterFromLeft ) - right = tan( horizontalFov * ( 1f - horizCenterFromLeft ) ) - top = tan( verticalFov * vertCenterFromTop ) - bottom = tan( verticalFov * (1f - vertCenterFromTop ) ) - * </pre> - * @param horizontalFov whole horizontal FOV in radians - * @param horizCenterFromLeft horizontal center from left in [0..1] - * @param verticalFov whole vertical FOV in radians - * @param vertCenterFromTop vertical center from top in [0..1] - */ - public static FovHVHalves byRadians(final float horizontalFov, final float horizCenterFromLeft, - final float verticalFov, final float vertCenterFromTop) { - return new FovHVHalves(FloatUtil.tan(horizontalFov * horizCenterFromLeft), - FloatUtil.tan(horizontalFov * ( 1f - horizCenterFromLeft )), - FloatUtil.tan(verticalFov * vertCenterFromTop), - FloatUtil.tan(verticalFov * (1f - vertCenterFromTop )), - true); - } - - /** - * Returns a custom symmetry {@link FovHVHalves} instance {@link #inTangents}, - * via computing the <code>horizontalFov</code> using: - * <pre> - halfVertFovTan = tan( verticalFov / 2f ); - halfHorizFovTan = aspect * halfVertFovTan; - horizontalFov = atan( halfHorizFovTan ) * 2f; - return {@link #byRadians(float, float, float, float) byRadians}(horizontalFov, horizCenterFromLeft, verticalFov, vertCenterFromTop) - * </pre> - * @param verticalFov whole vertical FOV in radians - * @param vertCenterFromTop vertical center from top in [0..1] - * @param aspect aspect ration width / height - * @param horizCenterFromLeft horizontal center from left in [0..1] - */ - public static FovHVHalves byFovyRadianAndAspect(final float verticalFov, final float vertCenterFromTop, - final float aspect, final float horizCenterFromLeft) { - final float halfVertFovTan = FloatUtil.tan(verticalFov/2f); - final float halfHorizFovTan = aspect * halfVertFovTan; - final float horizontalFov = FloatUtil.atan(halfHorizFovTan) * 2f; - return byRadians(horizontalFov, horizCenterFromLeft, verticalFov, vertCenterFromTop); - } - - /** - * Returns this instance <i>in tangent</i> values. - * <p> - * If this instance is {@link #inTangents} already, method returns this instance, - * otherwise a newly created instance w/ converted values to tangent. - * </p> - */ - public final FovHVHalves toTangents() { - if( inTangents ) { - return this; - } else { - return new FovHVHalves(FloatUtil.tan(left), FloatUtil.tan(right), FloatUtil.tan(top), FloatUtil.tan(bottom), true); - } - } - - /** Returns the full horizontal FOV, i.e. {@link #left} + {@link #right}, either in {@link #inTangents} or radians. */ - public final float horzFov() { return left+right; } - - /** Returns the full vertical FOV, i.e. {@link #top} + {@link #bottom}, either in {@link #inTangents} or radians. */ - public final float vertFov() { return top+bottom; } - - public final String toString() { - return "FovHVH["+(inTangents?"tangents":"radians")+": "+left+" l, "+right+" r, "+top+" t, "+bottom+" b]"; - } - public final String toStringInDegrees() { - final float f = 180.0f / FloatUtil.PI; - final String storedAs = inTangents?"tangents":"radians"; - if( inTangents ) { - final float aleft = FloatUtil.atan(left); - final float aright = FloatUtil.atan(right); - final float atop = FloatUtil.atan(top); - final float abottom = FloatUtil.atan(bottom); - return "FovHVH[degrees: "+aleft*f+" l, "+aright*f+" r, "+atop*f+" t, "+abottom*f+" b, stored-as: "+storedAs+"]"; - } else { - return "FovHVH[degrees: "+left*f+" l, "+right*f+" r, "+top*f+" t, "+bottom*f+" b, stored-as: "+storedAs+"]"; - } - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java b/src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java deleted file mode 100644 index 5d1d8e968..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Matrix4f.java +++ /dev/null @@ -1,2153 +0,0 @@ -/** - * Copyright 2014-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.opengl.math; - -import java.nio.FloatBuffer; - -import com.jogamp.opengl.math.geom.AABBox; -import com.jogamp.opengl.math.geom.Frustum; -import com.jogamp.opengl.math.geom.Frustum.Plane; - -/** - * Basic 4x4 float matrix implementation using fields for intensive use-cases (host operations). - * <p> - * Implementation covers {@link FloatUtil} matrix functionality, exposed in an object oriented manner. - * </p> - * <p> - * Unlike {@link com.jogamp.opengl.util.PMVMatrix PMVMatrix}, this class only represents one single matrix - * without a complete {@link com.jogamp.opengl.fixedfunc.GLMatrixFunc GLMatrixFunc} implementation. - * </p> - * <p> - * For array operations the layout is expected in column-major order - * matching OpenGL's implementation, illustration: - * <pre> - Row-Major Column-Major (OpenGL): - - | 0 1 2 tx | - | | - | 4 5 6 ty | - M = | | - | 8 9 10 tz | - | | - | 12 13 14 15 | - - R C R C - m[0*4+3] = tx; m[0+4*3] = tx; - m[1*4+3] = ty; m[1+4*3] = ty; - m[2*4+3] = tz; m[2+4*3] = tz; - - RC (std subscript order) RC (std subscript order) - m03 = tx; m03 = tx; - m13 = ty; m13 = ty; - m23 = tz; m23 = tz; - - * </pre> - * </p> - * <p> - * <ul> - * <li><a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix-FAQ</a></li> - * <li><a href="https://en.wikipedia.org/wiki/Matrix_%28mathematics%29">Wikipedia-Matrix</a></li> - * <li><a href="http://www.euclideanspace.com/maths/algebra/matrix/index.htm">euclideanspace.com-Matrix</a></li> - * </ul> - * </p> - * <p> - * Implementation utilizes unrolling of small vertices and matrices wherever possible - * while trying to access memory in a linear fashion for performance reasons, see: - * <ul> - * <li><a href="https://lessthanoptimal.github.io/Java-Matrix-Benchmark/">java-matrix-benchmark</a></li> - * <li><a href="https://github.com/lessthanoptimal/ejml">EJML Efficient Java Matrix Library</a></li> - * </ul> - * </p> - * @see com.jogamp.opengl.util.PMVMatrix - * @see FloatUtil - */ -public class Matrix4f { - - /** - * Creates a new identity matrix. - */ - public Matrix4f() { - m00 = m11 = m22 = m33 = 1.0f; - // remaining fields have default init to zero - } - - /** - * Creates a new matrix copying the values of the given {@code src} matrix. - */ - public Matrix4f(final Matrix4f src) { - load(src); - } - - /** - * Creates a new matrix based on given float[4*4] column major order. - * @param m 4x4 matrix in column-major order - */ - public Matrix4f(final float[] m) { - load(m); - } - - /** - * Creates a new matrix based on given float[4*4] column major order. - * @param m 4x4 matrix in column-major order - * @param m_off offset for matrix {@code m} - */ - public Matrix4f(final float[] m, final int m_off) { - load(m, m_off); - } - - /** - * Creates a new matrix based on given {@link FloatBuffer} 4x4 column major order. - * @param m 4x4 matrix in column-major order - */ - public Matrix4f(final FloatBuffer m) { - load(m); - } - - // - // Write to Matrix via set(..) or load(..) - // - - /** Sets the {@code i}th component with float {@code v} 0 <= i < 16 */ - public void set(final int i, final float v) { - switch (i) { - case 0+4*0: m00 = v; break; - case 1+4*0: m10 = v; break; - case 2+4*0: m20 = v; break; - case 3+4*0: m30 = v; break; - - case 0+4*1: m01 = v; break; - case 1+4*1: m11 = v; break; - case 2+4*1: m21 = v; break; - case 3+4*1: m31 = v; break; - - case 0+4*2: m02 = v; break; - case 1+4*2: m12 = v; break; - case 2+4*2: m22 = v; break; - case 3+4*2: m32 = v; break; - - case 0+4*3: m03 = v; break; - case 1+4*3: m13 = v; break; - case 2+4*3: m23 = v; break; - case 3+4*3: m33 = v; break; - default: throw new IndexOutOfBoundsException(); - } - } - - /** - * Set this matrix to identity. - * <pre> - Translation matrix (Column Order): - 1 0 0 0 - 0 1 0 0 - 0 0 1 0 - 0 0 0 1 - * </pre> - * @return this matrix for chaining - */ - public final Matrix4f loadIdentity() { - m00 = m11 = m22 = m33 = 1.0f; - m01 = m02 = m03 = - m10 = m12 = m13 = - m20 = m21 = m23 = - m30 = m31 = m32 = 0.0f; - return this; - } - - /** - * Load the values of the given matrix {@code b} to this matrix. - * @param src the source values - * @return this matrix for chaining - */ - public Matrix4f load(final Matrix4f src) { - m00 = src.m00; m10 = src.m10; m20 = src.m20; m30 = src.m30; - m01 = src.m01; m11 = src.m11; m21 = src.m21; m31 = src.m31; - m02 = src.m02; m12 = src.m12; m22 = src.m22; m32 = src.m32; - m03 = src.m03; m13 = src.m13; m23 = src.m23; m33 = src.m33; - return this; - } - - /** - * Load the values of the given matrix {@code src} to this matrix. - * @param src 4x4 matrix float[16] in column-major order - * @return this matrix for chaining - */ - public Matrix4f load(final float[] src) { - m00 = src[0+0*4]; // column 0 - m10 = src[1+0*4]; - m20 = src[2+0*4]; - m30 = src[3+0*4]; - m01 = src[0+1*4]; // column 1 - m11 = src[1+1*4]; - m21 = src[2+1*4]; - m31 = src[3+1*4]; - m02 = src[0+2*4]; // column 2 - m12 = src[1+2*4]; - m22 = src[2+2*4]; - m32 = src[3+2*4]; - m03 = src[0+3*4]; // column 3 - m13 = src[1+3*4]; - m23 = src[2+3*4]; - m33 = src[3+3*4]; - return this; - } - - /** - * Load the values of the given matrix {@code src} to this matrix. - * @param src 4x4 matrix float[16] in column-major order - * @param src_off offset for matrix {@code src} - * @return this matrix for chaining - */ - public Matrix4f load(final float[] src, final int src_off) { - m00 = src[src_off+0+0*4]; - m10 = src[src_off+1+0*4]; - m20 = src[src_off+2+0*4]; - m30 = src[src_off+3+0*4]; - m01 = src[src_off+0+1*4]; - m11 = src[src_off+1+1*4]; - m21 = src[src_off+2+1*4]; - m31 = src[src_off+3+1*4]; - m02 = src[src_off+0+2*4]; - m12 = src[src_off+1+2*4]; - m22 = src[src_off+2+2*4]; - m32 = src[src_off+3+2*4]; - m03 = src[src_off+0+3*4]; - m13 = src[src_off+1+3*4]; - m23 = src[src_off+2+3*4]; - m33 = src[src_off+3+3*4]; - return this; - } - - /** - * Load the values of the given matrix {@code src} to this matrix. - * <p> - * Implementation uses relative {@link FloatBuffer#get()}, - * hence caller may want to issue {@link FloatBuffer#reset()} thereafter. - * </p> - * @param src 4x4 matrix {@link FloatBuffer} in column-major order - * @return this matrix for chaining - */ - public Matrix4f load(final FloatBuffer src) { - m00 = src.get(); - m10 = src.get(); - m20 = src.get(); - m30 = src.get(); - m01 = src.get(); - m11 = src.get(); - m21 = src.get(); - m31 = src.get(); - m02 = src.get(); - m12 = src.get(); - m22 = src.get(); - m32 = src.get(); - m03 = src.get(); - m13 = src.get(); - m23 = src.get(); - m33 = src.get(); - return this; - } - - // - // Read out Matrix via get(..) - // - - /** Gets the {@code i}th component, 0 <= i < 16 */ - public float get(final int i) { - switch (i) { - case 0+4*0: return m00; - case 1+4*0: return m10; - case 2+4*0: return m20; - case 3+4*0: return m30; - - case 0+4*1: return m01; - case 1+4*1: return m11; - case 2+4*1: return m21; - case 3+4*1: return m31; - - case 0+4*2: return m02; - case 1+4*2: return m12; - case 2+4*2: return m22; - case 3+4*2: return m32; - - case 0+4*3: return m03; - case 1+4*3: return m13; - case 2+4*3: return m23; - case 3+4*3: return m33; - - default: throw new IndexOutOfBoundsException(); - } - } - - /** - * Get the named column of the given column-major matrix to v_out. - * @param column named column to copy - * @param v_out the column-vector storage - * @return given result vector <i>v_out</i> for chaining - */ - public Vec4f getColumn(final int column, final Vec4f v_out) { - v_out.set( get(0+column*4), - get(1+column*4), - get(2+column*4), - get(3+column*4) ); - return v_out; - } - - /** - * Get the named column of the given column-major matrix to v_out. - * @param column named column to copy - * @param v_out the column-vector storage - * @return given result vector <i>v_out</i> for chaining - */ - public Vec3f getColumn(final int column, final Vec3f v_out) { - v_out.set( get(0+column*4), - get(1+column*4), - get(2+column*4) ); - return v_out; - } - - /** - * Get the named row of the given column-major matrix to v_out. - * @param row named row to copy - * @param v_out the row-vector storage - * @return given result vector <i>v_out</i> for chaining - */ - public Vec4f getRow(final int row, final Vec4f v_out) { - v_out.set( get(row+0*4), - get(row+1*4), - get(row+2*4), - get(row+3*4) ); - return v_out; - } - - /** - * Get the named row of the given column-major matrix to v_out. - * @param row named row to copy - * @param v_out the row-vector storage - * @return given result vector <i>v_out</i> for chaining - */ - public Vec3f getRow(final int row, final Vec3f v_out) { - v_out.set( get(row+0*4), - get(row+1*4), - get(row+2*4) ); - return v_out; - } - - /** - * Get this matrix into the given float[16] array at {@code dst_off} in column major order. - * - * @param dst float[16] array storage in column major order - * @param dst_off offset - * @return {@code dst} for chaining - */ - public float[] get(final float[] dst, final int dst_off) { - dst[dst_off+0+0*4] = m00; - dst[dst_off+1+0*4] = m10; - dst[dst_off+2+0*4] = m20; - dst[dst_off+3+0*4] = m30; - dst[dst_off+0+1*4] = m01; - dst[dst_off+1+1*4] = m11; - dst[dst_off+2+1*4] = m21; - dst[dst_off+3+1*4] = m31; - dst[dst_off+0+2*4] = m02; - dst[dst_off+1+2*4] = m12; - dst[dst_off+2+2*4] = m22; - dst[dst_off+3+2*4] = m32; - dst[dst_off+0+3*4] = m03; - dst[dst_off+1+3*4] = m13; - dst[dst_off+2+3*4] = m23; - dst[dst_off+3+3*4] = m33; - return dst; - } - - /** - * Get this matrix into the given float[16] array in column major order. - * - * @param dst float[16] array storage in column major order - * @return {@code dst} for chaining - */ - public float[] get(final float[] dst) { - dst[0+0*4] = m00; - dst[1+0*4] = m10; - dst[2+0*4] = m20; - dst[3+0*4] = m30; - dst[0+1*4] = m01; - dst[1+1*4] = m11; - dst[2+1*4] = m21; - dst[3+1*4] = m31; - dst[0+2*4] = m02; - dst[1+2*4] = m12; - dst[2+2*4] = m22; - dst[3+2*4] = m32; - dst[0+3*4] = m03; - dst[1+3*4] = m13; - dst[2+3*4] = m23; - dst[3+3*4] = m33; - return dst; - } - - /** - * Get this matrix into the given {@link FloatBuffer} in column major order. - * <p> - * Implementation uses relative {@link FloatBuffer#put(float)}, - * hence caller may want to issue {@link FloatBuffer#reset()} thereafter. - * </p> - * - * @param dst {@link FloatBuffer} array storage in column major order - * @return {@code dst} for chaining - */ - public FloatBuffer get(final FloatBuffer dst) { - dst.put( m00 ); - dst.put( m10 ); - dst.put( m20 ); - dst.put( m30 ); - dst.put( m01 ); - dst.put( m11 ); - dst.put( m21 ); - dst.put( m31 ); - dst.put( m02 ); - dst.put( m12 ); - dst.put( m22 ); - dst.put( m32 ); - dst.put( m03 ); - dst.put( m13 ); - dst.put( m23 ); - dst.put( m33 ); - return dst; - } - - // - // Basic matrix operations - // - - /** - * Returns the determinant of this matrix - * @return the matrix determinant - */ - public float determinant() { - float ret = 0; - ret += m00 * ( + m11*(m22*m33 - m23*m32) - m12*(m21*m33 - m23*m31) + m13*(m21*m32 - m22*m31)); - ret -= m01 * ( + m10*(m22*m33 - m23*m32) - m12*(m20*m33 - m23*m30) + m13*(m20*m32 - m22*m30)); - ret += m02 * ( + m10*(m21*m33 - m23*m31) - m11*(m20*m33 - m23*m30) + m13*(m20*m31 - m21*m30)); - ret -= m03 * ( + m10*(m21*m32 - m22*m31) - m11*(m20*m32 - m22*m30) + m12*(m20*m31 - m21*m30)); - return ret; - } - - /** - * Transpose this matrix. - * - * @return this matrix for chaining - */ - public final Matrix4f transpose() { - float tmp; - - tmp = m10; - m10 = m01; - m01 = tmp; - - tmp = m20; - m20 = m02; - m02 = tmp; - - tmp = m30; - m30 = m03; - m03 = tmp; - - tmp = m21; - m21 = m12; - m12 = tmp; - - tmp = m31; - m31 = m13; - m13 = tmp; - - tmp = m32; - m32 = m23; - m23 = tmp; - - return this; - } - - /** - * Transpose the given {@code src} matrix into this matrix. - * - * @param src source 4x4 matrix - * @return this matrix (result) for chaining - */ - public final Matrix4f transpose(final Matrix4f src) { - if( src == this ) { - return transpose(); - } - m00 = src.m00; - m10 = src.m01; - m20 = src.m02; - m30 = src.m03; - - m01 = src.m10; - m11 = src.m11; - m21 = src.m12; - m31 = src.m13; - - m02 = src.m20; - m12 = src.m21; - m22 = src.m22; - m32 = src.m23; - - m03 = src.m30; - m13 = src.m31; - m23 = src.m32; - m33 = src.m33; - return this; - } - - /** - * Invert this matrix. - * @return false if this matrix is singular and inversion not possible, otherwise true - */ - public boolean invert() { - final float scale; - try { - scale = mulScale(); - } catch(final ArithmeticException aex) { - return false; // max was 0 - } - final float a00 = m00*scale; - final float a10 = m10*scale; - final float a20 = m20*scale; - final float a30 = m30*scale; - - final float a01 = m01*scale; - final float a11 = m11*scale; - final float a21 = m21*scale; - final float a31 = m31*scale; - - final float a02 = m02*scale; - final float a12 = m12*scale; - final float a22 = m22*scale; - final float a32 = m32*scale; - - final float a03 = m03*scale; - final float a13 = m13*scale; - final float a23 = m23*scale; - final float a33 = m33*scale; - - final float b00 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31); - final float b01 = -( + a10*(a22*a33 - a23*a32) - a12*(a20*a33 - a23*a30) + a13*(a20*a32 - a22*a30)); - final float b02 = + a10*(a21*a33 - a23*a31) - a11*(a20*a33 - a23*a30) + a13*(a20*a31 - a21*a30); - final float b03 = -( + a10*(a21*a32 - a22*a31) - a11*(a20*a32 - a22*a30) + a12*(a20*a31 - a21*a30)); - - final float b10 = -( + a01*(a22*a33 - a23*a32) - a02*(a21*a33 - a23*a31) + a03*(a21*a32 - a22*a31)); - final float b11 = + a00*(a22*a33 - a23*a32) - a02*(a20*a33 - a23*a30) + a03*(a20*a32 - a22*a30); - final float b12 = -( + a00*(a21*a33 - a23*a31) - a01*(a20*a33 - a23*a30) + a03*(a20*a31 - a21*a30)); - final float b13 = + a00*(a21*a32 - a22*a31) - a01*(a20*a32 - a22*a30) + a02*(a20*a31 - a21*a30); - - final float b20 = + a01*(a12*a33 - a13*a32) - a02*(a11*a33 - a13*a31) + a03*(a11*a32 - a12*a31); - final float b21 = -( + a00*(a12*a33 - a13*a32) - a02*(a10*a33 - a13*a30) + a03*(a10*a32 - a12*a30)); - final float b22 = + a00*(a11*a33 - a13*a31) - a01*(a10*a33 - a13*a30) + a03*(a10*a31 - a11*a30); - final float b23 = -( + a00*(a11*a32 - a12*a31) - a01*(a10*a32 - a12*a30) + a02*(a10*a31 - a11*a30)); - - final float b30 = -( + a01*(a12*a23 - a13*a22) - a02*(a11*a23 - a13*a21) + a03*(a11*a22 - a12*a21)); - final float b31 = + a00*(a12*a23 - a13*a22) - a02*(a10*a23 - a13*a20) + a03*(a10*a22 - a12*a20); - final float b32 = -( + a00*(a11*a23 - a13*a21) - a01*(a10*a23 - a13*a20) + a03*(a10*a21 - a11*a20)); - final float b33 = + a00*(a11*a22 - a12*a21) - a01*(a10*a22 - a12*a20) + a02*(a10*a21 - a11*a20); - - final float det = (a00*b00 + a01*b01 + a02*b02 + a03*b03) / scale; - if( 0 == det ) { - return false; - } - final float invdet = 1.0f / det; - - m00 = b00 * invdet; - m10 = b01 * invdet; - m20 = b02 * invdet; - m30 = b03 * invdet; - - m01 = b10 * invdet; - m11 = b11 * invdet; - m21 = b12 * invdet; - m31 = b13 * invdet; - - m02 = b20 * invdet; - m12 = b21 * invdet; - m22 = b22 * invdet; - m32 = b23 * invdet; - - m03 = b30 * invdet; - m13 = b31 * invdet; - m23 = b32 * invdet; - m33 = b33 * invdet; - return true; - } - - /** - * Invert the {@code src} matrix values into this matrix - * @param src the source matrix, which values are to be inverted - * @return false if {@code src} matrix is singular and inversion not possible, otherwise true - */ - public boolean invert(final Matrix4f src) { - final float scale; - try { - scale = src.mulScale(); - } catch(final ArithmeticException aex) { - return false; // max was 0 - } - final float a00 = src.m00*scale; - final float a10 = src.m10*scale; - final float a20 = src.m20*scale; - final float a30 = src.m30*scale; - - final float a01 = src.m01*scale; - final float a11 = src.m11*scale; - final float a21 = src.m21*scale; - final float a31 = src.m31*scale; - - final float a02 = src.m02*scale; - final float a12 = src.m12*scale; - final float a22 = src.m22*scale; - final float a32 = src.m32*scale; - - final float a03 = src.m03*scale; - final float a13 = src.m13*scale; - final float a23 = src.m23*scale; - final float a33 = src.m33*scale; - - final float b00 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31); - final float b01 = -( + a10*(a22*a33 - a23*a32) - a12*(a20*a33 - a23*a30) + a13*(a20*a32 - a22*a30)); - final float b02 = + a10*(a21*a33 - a23*a31) - a11*(a20*a33 - a23*a30) + a13*(a20*a31 - a21*a30); - final float b03 = -( + a10*(a21*a32 - a22*a31) - a11*(a20*a32 - a22*a30) + a12*(a20*a31 - a21*a30)); - - final float b10 = -( + a01*(a22*a33 - a23*a32) - a02*(a21*a33 - a23*a31) + a03*(a21*a32 - a22*a31)); - final float b11 = + a00*(a22*a33 - a23*a32) - a02*(a20*a33 - a23*a30) + a03*(a20*a32 - a22*a30); - final float b12 = -( + a00*(a21*a33 - a23*a31) - a01*(a20*a33 - a23*a30) + a03*(a20*a31 - a21*a30)); - final float b13 = + a00*(a21*a32 - a22*a31) - a01*(a20*a32 - a22*a30) + a02*(a20*a31 - a21*a30); - - final float b20 = + a01*(a12*a33 - a13*a32) - a02*(a11*a33 - a13*a31) + a03*(a11*a32 - a12*a31); - final float b21 = -( + a00*(a12*a33 - a13*a32) - a02*(a10*a33 - a13*a30) + a03*(a10*a32 - a12*a30)); - final float b22 = + a00*(a11*a33 - a13*a31) - a01*(a10*a33 - a13*a30) + a03*(a10*a31 - a11*a30); - final float b23 = -( + a00*(a11*a32 - a12*a31) - a01*(a10*a32 - a12*a30) + a02*(a10*a31 - a11*a30)); - - final float b30 = -( + a01*(a12*a23 - a13*a22) - a02*(a11*a23 - a13*a21) + a03*(a11*a22 - a12*a21)); - final float b31 = + a00*(a12*a23 - a13*a22) - a02*(a10*a23 - a13*a20) + a03*(a10*a22 - a12*a20); - final float b32 = -( + a00*(a11*a23 - a13*a21) - a01*(a10*a23 - a13*a20) + a03*(a10*a21 - a11*a20)); - final float b33 = + a00*(a11*a22 - a12*a21) - a01*(a10*a22 - a12*a20) + a02*(a10*a21 - a11*a20); - - final float det = (a00*b00 + a01*b01 + a02*b02 + a03*b03) / scale; - - if( 0 == det ) { - return false; - } - final float invdet = 1.0f / det; - - m00 = b00 * invdet; - m10 = b01 * invdet; - m20 = b02 * invdet; - m30 = b03 * invdet; - - m01 = b10 * invdet; - m11 = b11 * invdet; - m21 = b12 * invdet; - m31 = b13 * invdet; - - m02 = b20 * invdet; - m12 = b21 * invdet; - m22 = b22 * invdet; - m32 = b23 * invdet; - - m03 = b30 * invdet; - m13 = b31 * invdet; - m23 = b32 * invdet; - m33 = b33 * invdet; - return true; - } - - private final float mulScale() { - /** - // No Hotspot intrinsic Math.* optimization for at least Math.max(), - // hence this chunk is slower. - float max = Math.abs(m00); - - max = Math.max(max, Math.abs(m01)); - max = Math.max(max, Math.abs(m02)); - ... etc - */ - float a = Math.abs(m00); - float max = a; - a = Math.abs(m01); if( a > max ) max = a; - a = Math.abs(m02); if( a > max ) max = a; - a = Math.abs(m03); if( a > max ) max = a; - - a = Math.abs(m10); if( a > max ) max = a; - a = Math.abs(m11); if( a > max ) max = a; - a = Math.abs(m12); if( a > max ) max = a; - a = Math.abs(m13); if( a > max ) max = a; - - a = Math.abs(m20); if( a > max ) max = a; - a = Math.abs(m21); if( a > max ) max = a; - a = Math.abs(m22); if( a > max ) max = a; - a = Math.abs(m23); if( a > max ) max = a; - - a = Math.abs(m30); if( a > max ) max = a; - a = Math.abs(m31); if( a > max ) max = a; - a = Math.abs(m32); if( a > max ) max = a; - a = Math.abs(m33); if( a > max ) max = a; - - return 1.0f/max; - } - - /** - * Multiply matrix: [this] = [this] x [b] - * @param b 4x4 matrix - * @return this matrix for chaining - * @see #mul(Matrix4f, Matrix4f) - */ - public final Matrix4f mul(final Matrix4f b) { - // return mul(new Matrix4f(this), b); // <- roughly half speed - float ai0=m00; // row-0, m[0+0*4] - float ai1=m01; - float ai2=m02; - float ai3=m03; - m00 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ; - m01 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ; - m02 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ; - m03 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ; - - ai0=m10; //row-1, m[1+0*4] - ai1=m11; - ai2=m12; - ai3=m13; - m10 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ; - m11 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ; - m12 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ; - m13 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ; - - ai0=m20; // row-2, m[2+0*4] - ai1=m21; - ai2=m22; - ai3=m23; - m20 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ; - m21 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ; - m22 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ; - m23 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ; - - ai0=m30; // row-3, m[3+0*4] - ai1=m31; - ai2=m32; - ai3=m33; - m30 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ; - m31 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ; - m32 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ; - m33 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ; - return this; - } - - /** - * Multiply matrix: [this] = [a] x [b] - * @param a 4x4 matrix, can't be this matrix - * @param b 4x4 matrix, can't be this matrix - * @return this matrix for chaining - * @see #mul(Matrix4f) - */ - public final Matrix4f mul(final Matrix4f a, final Matrix4f b) { - // row-0, m[0+0*4] - m00 = a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20 + a.m03 * b.m30 ; - m01 = a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21 + a.m03 * b.m31 ; - m02 = a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22 + a.m03 * b.m32 ; - m03 = a.m00 * b.m03 + a.m01 * b.m13 + a.m02 * b.m23 + a.m03 * b.m33 ; - - //row-1, m[1+0*4] - m10 = a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20 + a.m13 * b.m30 ; - m11 = a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31 ; - m12 = a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32 ; - m13 = a.m10 * b.m03 + a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33 ; - - // row-2, m[2+0*4] - m20 = a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20 + a.m23 * b.m30 ; - m21 = a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31 ; - m22 = a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32 ; - m23 = a.m20 * b.m03 + a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33 ; - - // row-3, m[3+0*4] - m30 = a.m30 * b.m00 + a.m31 * b.m10 + a.m32 * b.m20 + a.m33 * b.m30 ; - m31 = a.m30 * b.m01 + a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31 ; - m32 = a.m30 * b.m02 + a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32 ; - m33 = a.m30 * b.m03 + a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33 ; - - return this; - } - - /** - * @param v_in 4-component column-vector, can be v_out for in-place transformation - * @param v_out this * v_in - * @returns v_out for chaining - */ - public final Vec4f mulVec4f(final Vec4f v_in, final Vec4f v_out) { - // (one matrix row in column-major order) X (column vector) - final float x = v_in.x(), y = v_in.y(), z = v_in.z(), w = v_in.w(); - v_out.set( x * m00 + y * m01 + z * m02 + w * m03, - x * m10 + y * m11 + z * m12 + w * m13, - x * m20 + y * m21 + z * m22 + w * m23, - x * m30 + y * m31 + z * m32 + w * m33 ); - return v_out; - } - - /** - * @param v_inout 4-component column-vector input and output, i.e. in-place transformation - * @returns v_inout for chaining - */ - public final Vec4f mulVec4f(final Vec4f v_inout) { - // (one matrix row in column-major order) X (column vector) - final float x = v_inout.x(), y = v_inout.y(), z = v_inout.z(), w = v_inout.w(); - v_inout.set( x * m00 + y * m01 + z * m02 + w * m03, - x * m10 + y * m11 + z * m12 + w * m13, - x * m20 + y * m21 + z * m22 + w * m23, - x * m30 + y * m31 + z * m32 + w * m33 ); - return v_inout; - } - - /** - * Affine 3f-vector transformation by 4x4 matrix - * - * 4x4 matrix multiplication with 3-component vector, - * using {@code 1} for for {@code v_in.w()} and dropping {@code v_out.w()}, - * which shall be {@code 1}. - * - * @param v_in 3-component column-vector {@link Vec3f}, can be v_out for in-place transformation - * @param v_out m_in * v_in, 3-component column-vector {@link Vec3f} - * @returns v_out for chaining - */ - public final Vec3f mulVec3f(final Vec3f v_in, final Vec3f v_out) { - // (one matrix row in column-major order) X (column vector) - final float x = v_in.x(), y = v_in.y(), z = v_in.z(); - v_out.set( x * m00 + y * m01 + z * m02 + 1f * m03, - x * m10 + y * m11 + z * m12 + 1f * m13, - x * m20 + y * m21 + z * m22 + 1f * m23 ); - return v_out; - } - - /** - * Affine 3f-vector transformation by 4x4 matrix - * - * 4x4 matrix multiplication with 3-component vector, - * using {@code 1} for for {@code v_inout.w()} and dropping {@code v_inout.w()}, - * which shall be {@code 1}. - * - * @param v_inout 3-component column-vector {@link Vec3f} input and output, i.e. in-place transformation - * @returns v_inout for chaining - */ - public final Vec3f mulVec3f(final Vec3f v_inout) { - // (one matrix row in column-major order) X (column vector) - final float x = v_inout.x(), y = v_inout.y(), z = v_inout.z(); - v_inout.set( x * m00 + y * m01 + z * m02 + 1f * m03, - x * m10 + y * m11 + z * m12 + 1f * m13, - x * m20 + y * m21 + z * m22 + 1f * m23 ); - return v_inout; - } - - // - // Matrix setTo...(), affine + basic - // - - /** - * Set this matrix to translation. - * <pre> - Translation matrix (Column Order): - 1 0 0 0 - 0 1 0 0 - 0 0 1 0 - x y z 1 - * </pre> - * @param x x-axis translate - * @param y y-axis translate - * @param z z-axis translate - * @return this matrix for chaining - */ - public final Matrix4f setToTranslation(final float x, final float y, final float z) { - m00 = m11 = m22 = m33 = 1.0f; - m03 = x; - m13 = y; - m23 = z; - m01 = m02 = - m10 = m12 = - m20 = m21 = - m30 = m31 = m32 = 0.0f; - return this; - } - - /** - * Set this matrix to translation. - * <pre> - Translation matrix (Column Order): - 1 0 0 0 - 0 1 0 0 - 0 0 1 0 - x y z 1 - * </pre> - * @param t translate Vec3f - * @return this matrix for chaining - */ - public final Matrix4f setToTranslation(final Vec3f t) { - return setToTranslation(t.x(), t.y(), t.z()); - } - - /** - * Set this matrix to scale. - * <pre> - Scale matrix (Any Order): - x 0 0 0 - 0 y 0 0 - 0 0 z 0 - 0 0 0 1 - * </pre> - * @param x x-axis scale - * @param y y-axis scale - * @param z z-axis scale - * @return this matrix for chaining - */ - public final Matrix4f setToScale(final float x, final float y, final float z) { - m33 = 1.0f; - m00 = x; - m11 = y; - m22 = z; - m01 = m02 = m03 = - m10 = m12 = m13 = - m20 = m21 = m23 = - m30 = m31 = m32 = 0.0f; - return this; - } - - /** - * Set this matrix to scale. - * <pre> - Scale matrix (Any Order): - x 0 0 0 - 0 y 0 0 - 0 0 z 0 - 0 0 0 1 - * </pre> - * @param s scale Vec3f - * @return this matrix for chaining - */ - public final Matrix4f setToScale(final Vec3f s) { - return setToScale(s.x(), s.y(), s.z()); - } - - /** - * Set this matrix to rotation 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> - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a> - * @param ang_rad angle in radians - * @param x x of rotation axis - * @param y y of rotation axis - * @param z z of rotation axis - * @return this matrix for chaining - */ - public final Matrix4f setToRotationAxis(final float ang_rad, float x, float y, float z) { - final float c = FloatUtil.cos(ang_rad); - final float ic= 1.0f - c; - final float s = FloatUtil.sin(ang_rad); - - final Vec3f tmp = new Vec3f(x, y, z).normalize(); - x = tmp.x(); y = tmp.y(); z = tmp.z(); - - final float xy = x*y; - final float xz = x*z; - final float xs = x*s; - final float ys = y*s; - final float yz = y*z; - final float zs = z*s; - m00 = x*x*ic+c; - m10 = xy*ic+zs; - m20 = xz*ic-ys; - m30 = 0; - - m01 = xy*ic-zs; - m11 = y*y*ic+c; - m21 = yz*ic+xs; - m31 = 0; - - m02 = xz*ic+ys; - m12 = yz*ic-xs; - m22 = z*z*ic+c; - m32 = 0; - - m03 = 0f; - m13 = 0f; - m23 = 0f; - m33 = 1f; - - return this; - } - - /** - * Set this matrix to rotation from the given axis and angle in radians. - * <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> - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a> - * @param ang_rad angle in radians - * @param axis rotation axis - * @return this matrix for chaining - */ - public final Matrix4f setToRotationAxis(final float ang_rad, final Vec3f axis) { - return setToRotationAxis(ang_rad, axis.x(), axis.y(), axis.z()); - } - - /** - * Set this matrix to rotation from the given Euler rotation angles in radians. - * <p> - * The rotations are applied in the given order: - * <ul> - * <li>y - heading</li> - * <li>z - attitude</li> - * <li>x - bank</li> - * </ul> - * </p> - * @param bankX the Euler pitch angle in radians. (rotation about the X axis) - * @param headingY the Euler yaw angle in radians. (rotation about the Y axis) - * @param attitudeZ the Euler roll angle in radians. (rotation about the Z axis) - * @return this matrix for chaining - * <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>, - * consider using {@link #setToRotation(Quaternion)}. - * </p> - * @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> - * @see #setToRotation(Quaternion) - */ - public Matrix4f setToRotationEuler(final float bankX, final float headingY, final float attitudeZ) { - // Assuming the angles are in radians. - final float ch = FloatUtil.cos(headingY); - final float sh = FloatUtil.sin(headingY); - final float ca = FloatUtil.cos(attitudeZ); - final float sa = FloatUtil.sin(attitudeZ); - final float cb = FloatUtil.cos(bankX); - final float sb = FloatUtil.sin(bankX); - - m00 = ch*ca; - m10 = sa; - m20 = -sh*ca; - m30 = 0; - - m01 = sh*sb - ch*sa*cb; - m11 = ca*cb; - m21 = sh*sa*cb + ch*sb; - m31 = 0; - - m02 = ch*sa*sb + sh*cb; - m12 = -ca*sb; - m22 = -sh*sa*sb + ch*cb; - m32 = 0; - - m03 = 0; - m13 = 0; - m23 = 0; - m33 = 1; - - return this; - } - - /** - * Set this matrix to rotation from the given Euler rotation angles in radians. - * <p> - * The rotations are applied in the given order: - * <ul> - * <li>y - heading</li> - * <li>z - attitude</li> - * <li>x - bank</li> - * </ul> - * </p> - * @param angradXYZ euler angle vector in radians holding x-bank, y-heading and z-attitude - * @return this quaternion 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>, - * consider using {@link #setToRotation(Quaternion)}. - * </p> - * @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> - * @see #setToRotation(Quaternion) - */ - public Matrix4f setToRotationEuler(final Vec3f angradXYZ) { - return setToRotationEuler(angradXYZ.x(), angradXYZ.y(), angradXYZ.z()); - } - - /** - * Set this matrix to rotation using the given Quaternion. - * <p> - * Implementation Details: - * <ul> - * <li> makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * <li> The fields [m00 .. m22] define the rotation</li> - * </ul> - * </p> - * - * @param q the Quaternion representing the rotation - * @return this matrix for chaining - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54">Matrix-FAQ Q54</a> - * @see Quaternion#toMatrix(float[]) - * @see #getRotation() - */ - public final Matrix4f setToRotation(final Quaternion q) { - // pre-multiply scaled-reciprocal-magnitude to reduce multiplications - final float norm = q.magnitudeSquared(); - if ( FloatUtil.isZero(norm) ) { - // identity matrix -> srecip = 0f - loadIdentity(); - return this; - } - final float srecip; - if ( FloatUtil.isEqual(1f, norm) ) { - srecip = 2f; - } else { - srecip = 2.0f / norm; - } - - final float x = q.x(); - final float y = q.y(); - final float z = q.z(); - final float w = q.w(); - - final float xs = srecip * x; - final float ys = srecip * y; - final float zs = srecip * z; - - final float xx = x * xs; - final float xy = x * ys; - final float xz = x * zs; - final float xw = xs * w; - final float yy = y * ys; - final float yz = y * zs; - final float yw = ys * w; - final float zz = z * zs; - final float zw = zs * w; - - m00 = 1f - ( yy + zz ); - m01 = ( xy - zw ); - m02 = ( xz + yw ); - m03 = 0f; - - m10 = ( xy + zw ); - m11 = 1f - ( xx + zz ); - m12 = ( yz - xw ); - m13 = 0f; - - m20 = ( xz - yw ); - m21 = ( yz + xw ); - m22 = 1f - ( xx + yy ); - m23 = 0f; - - m30 = m31 = m32 = 0f; - m33 = 1f; - return this; - } - - /** - * Returns the rotation [m00 .. m22] fields converted to a Quaternion. - * @param res resulting Quaternion - * @return the resulting Quaternion for chaining. - * @see Quaternion#setFromMatrix(float, float, float, float, float, float, float, float, float) - * @see #setToRotation(Quaternion) - */ - public final Quaternion getRotation(final Quaternion res) { - res.setFromMatrix(m00, m01, m02, m10, m11, m12, m20, m21, m22); - return res; - } - - /** - * Set this matrix to orthogonal projection. - * <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> - * @param left - * @param right - * @param bottom - * @param top - * @param zNear - * @param zFar - * @return this matrix for chaining - */ - public Matrix4f setToOrtho(final float left, final float right, - final float bottom, final float top, - final float zNear, final float zFar) { - { - // m00 = m11 = m22 = m33 = 1f; - m10 = m20 = m30 = 0f; - m01 = m21 = m31 = 0f; - m02 = m12 = m32 = 0f; - // m03 = m13 = m23 = 0f; - } - final float dx=right-left; - final float dy=top-bottom; - final float dz=zFar-zNear; - final float tx=-1.0f*(right+left)/dx; - final float ty=-1.0f*(top+bottom)/dy; - final float tz=-1.0f*(zFar+zNear)/dz; - - m00 = 2.0f/dx; - m11 = 2.0f/dy; - m22 = -2.0f/dz; - - m03 = tx; - m13 = ty; - m23 = tz; - m33 = 1f; - - return this; - } - - /** - * Set this matrix to frustum. - * <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> - * @param left - * @param right - * @param bottom - * @param top - * @param zNear - * @param zFar - * @return this matrix for chaining - * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear} - * or {@code left == right}, or {@code bottom == top}. - */ - public Matrix4f setToFrustum(final float left, final float right, - final float bottom, final float top, - final float zNear, final float zFar) throws IllegalArgumentException { - if( zNear <= 0.0f || zFar <= zNear ) { - throw new IllegalArgumentException("Requirements zNear > 0 and zFar > zNear, but zNear "+zNear+", zFar "+zFar); - } - if( left == right || top == bottom) { - throw new IllegalArgumentException("GL_INVALID_VALUE: top,bottom and left,right must not be equal"); - } - { - // m00 = m11 = m22 = m33 = 1f; - m10 = m20 = m30 = 0f; - m01 = m21 = m31 = 0f; - m03 = m13 = 0f; - } - final float zNear2 = 2.0f*zNear; - final float dx=right-left; - final float dy=top-bottom; - final float dz=zFar-zNear; - final float A=(right+left)/dx; - final float B=(top+bottom)/dy; - final float C=-1.0f*(zFar+zNear)/dz; - final float D=-2.0f*(zFar*zNear)/dz; - - m00 = zNear2/dx; - m11 = zNear2/dy; - - m02 = A; - m12 = B; - m22 = C; - m32 = -1.0f; - - m23 = D; - m33 = 0f; - - return this; - } - - /** - * Set this matrix to perspective {@link #setToFrustum(float, float, float, float, float, float) frustum} projection. - * - * @param fovy_rad angle in radians - * @param aspect aspect ratio width / height - * @param zNear - * @param zFar - * @return this matrix for chaining - * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear} - * @see #setToFrustum(float, float, float, float, float, float) - */ - public Matrix4f setToPerspective(final float fovy_rad, final float aspect, final float zNear, final float zFar) throws IllegalArgumentException { - final float top = FloatUtil.tan(fovy_rad/2f) * zNear; // use tangent of half-fov ! - final float bottom = -1.0f * top; // -1f * fovhvTan.top * zNear - final float left = aspect * bottom; // aspect * -1f * fovhvTan.top * zNear - final float right = aspect * top; // aspect * fovhvTan.top * zNear - return setToFrustum(left, right, bottom, top, zNear, zFar); - } - - /** - * Set this matrix to perspective {@link #setToFrustum(float, float, float, float, float, float) frustum} projection. - * - * @param fovhv {@link FovHVHalves} field of view in both directions, may not be centered, either in radians or tangent - * @param zNear - * @param zFar - * @return this matrix for chaining - * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear} - * @see #setToFrustum(float, float, float, float, float, float) - * @see Frustum#updateByFovDesc(Matrix4f, com.jogamp.opengl.math.geom.Frustum.FovDesc) - */ - public Matrix4f setToPerspective(final FovHVHalves fovhv, final float zNear, final float zFar) throws IllegalArgumentException { - final FovHVHalves fovhvTan = fovhv.toTangents(); // use tangent of half-fov ! - final float top = fovhvTan.top * zNear; - final float bottom = -1.0f * fovhvTan.bottom * zNear; - final float left = -1.0f * fovhvTan.left * zNear; - final float right = fovhvTan.right * zNear; - return setToFrustum(left, right, bottom, top, zNear, zFar); - } - - /** - * Calculate the frustum planes in world coordinates - * using this premultiplied P*MV (column major order) matrix. - * <p> - * Frustum plane's normals will point to the inside of the viewing frustum, - * as required by this class. - * </p> - * <p> - * Usually called by {@link Frustum#updateFrustumPlanes(Matrix4f)}. - * </p> - */ - public void updateFrustumPlanes(final Frustum frustum) { - // Left: a = m41 + m11, b = m42 + m12, c = m43 + m13, d = m44 + m14 - [1..4] column-major - // Left: a = m30 + m00, b = m31 + m01, c = m32 + m02, d = m33 + m03 - [0..3] column-major - { - final Frustum.Plane p = frustum.getPlanes()[Frustum.LEFT]; - final Vec3f p_n = p.n; - p_n.set( m30 + m00, - m31 + m01, - m32 + m02 ); - p.d = m33 + m03; - } - - // Right: a = m41 - m11, b = m42 - m12, c = m43 - m13, d = m44 - m14 - [1..4] column-major - // Right: a = m30 - m00, b = m31 - m01, c = m32 - m02, d = m33 - m03 - [0..3] column-major - { - final Frustum.Plane p = frustum.getPlanes()[Frustum.RIGHT]; - final Vec3f p_n = p.n; - p_n.set( m30 - m00, - m31 - m01, - m32 - m02 ); - p.d = m33 - m03; - } - - // Bottom: a = m41m21, b = m42m22, c = m43m23, d = m44m24 - [1..4] column-major - // Bottom: a = m30m10, b = m31m11, c = m32m12, d = m33m13 - [0..3] column-major - { - final Frustum.Plane p = frustum.getPlanes()[Frustum.BOTTOM]; - final Vec3f p_n = p.n; - p_n.set( m30 + m10, - m31 + m11, - m32 + m12 ); - p.d = m33 + m13; - } - - // Top: a = m41 - m21, b = m42 - m22, c = m43 - m23, d = m44 - m24 - [1..4] column-major - // Top: a = m30 - m10, b = m31 - m11, c = m32 - m12, d = m33 - m13 - [0..3] column-major - { - final Frustum.Plane p = frustum.getPlanes()[Frustum.TOP]; - final Vec3f p_n = p.n; - p_n.set( m30 - m10, - m31 - m11, - m32 - m12 ); - p.d = m33 - m13; - } - - // Near: a = m41m31, b = m42m32, c = m43m33, d = m44m34 - [1..4] column-major - // Near: a = m30m20, b = m31m21, c = m32m22, d = m33m23 - [0..3] column-major - { - final Frustum.Plane p = frustum.getPlanes()[Frustum.NEAR]; - final Vec3f p_n = p.n; - p_n.set( m30 + m20, - m31 + m21, - m32 + m22 ); - p.d = m33 + m23; - } - - // Far: a = m41 - m31, b = m42 - m32, c = m43 - m33, d = m44 - m34 - [1..4] column-major - // Far: a = m30 - m20, b = m31 - m21, c = m32m22, d = m33m23 - [0..3] column-major - { - final Frustum.Plane p = frustum.getPlanes()[Frustum.FAR]; - final Vec3f p_n = p.n; - p_n.set( m30 - m20, - m31 - m21, - m32 - m22 ); - p.d = m33 - m23; - } - - // Normalize all planes - for (int i = 0; i < 6; ++i) { - final Plane p = frustum.getPlanes()[i]; - final Vec3f p_n = p.n; - final float invLen = 1f / p_n.length(); - p_n.scale(invLen); - p.d *= invLen; - } - } - - /** - * Set this matrix to 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>projection or modelview</i> multiplication, i.e. - * <b>M</b> = <b>M</b> x <b>R</b>, - * with <b>M</b> being the <i>projection or modelview</i> matrix. - * </pre> - * </p> - * @param eye 3 component eye vector - * @param center 3 component center vector - * @param up 3 component up vector - * @param tmp temporary Matrix4f used for multiplication - * @return this matrix for chaining - */ - public Matrix4f setToLookAt(final Vec3f eye, final Vec3f center, final Vec3f up, final Matrix4f tmp) { - // normalized forward! - final Vec3f fwd = new Vec3f( center.x() - eye.x(), - center.y() - eye.y(), - center.z() - eye.z() ).normalize(); - - /* Side = forward x up, normalized */ - final Vec3f side = fwd.cross(up).normalize(); - - /* Recompute up as: up = side x forward */ - final Vec3f up2 = side.cross(fwd); - - m00 = side.x(); - m10 = up2.x(); - m20 = -fwd.x(); - m30 = 0; - - m01 = side.y(); - m11 = up2.y(); - m21 = -fwd.y(); - m31 = 0; - - m02 = side.z(); - m12 = up2.z(); - m22 = -fwd.z(); - m32 = 0; - - m03 = 0; - m13 = 0; - m23 = 0; - m33 = 1; - - return mul( tmp.setToTranslation( -eye.x(), -eye.y(), -eye.z() ) ); - } - - /** - * Set this matrix to 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> - * To effectively use the generated pick matrix for picking, - * call {@link #setToPick(float, float, float, float, Recti, Matrix4f) setToPick(..)} - * and multiply a {@link #setToPerspective(float, float, float, float) custom perspective matrix} - * by this pick matrix. Then you may load the result onto the perspective matrix stack. - * </p> - * @param x the center x-component of a picking region in window coordinates - * @param y the center y-component of a picking region in window coordinates - * @param deltaX the width of the picking region in window coordinates. - * @param deltaY the height of the picking region in window coordinates. - * @param viewport Rect4i viewport - * @param mat4Tmp temp storage - * @return this matrix for chaining or {@code null} if either delta value is <= zero. - */ - public Matrix4f setToPick(final float x, final float y, final float deltaX, final float deltaY, - final Recti viewport, final Matrix4f mat4Tmp) { - if (deltaX <= 0 || deltaY <= 0) { - return null; - } - /* Translate and scale the picked region to the entire window */ - setToTranslation( ( viewport.width() - 2 * ( x - viewport.x() ) ) / deltaX, - ( viewport.height() - 2 * ( y - viewport.y() ) ) / deltaY, - 0); - mat4Tmp.setToScale( viewport.width() / deltaX, viewport.height() / deltaY, 1.0f ); - return mul(mat4Tmp); - } - - // - // Matrix affine operations using setTo..() - // - - /** - * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(float, float, float, float) axis-rotation matrix}. - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a> - * @param angrad angle in radians - * @param x x of rotation axis - * @param y y of rotation axis - * @param z z of rotation axis - * @param tmp temporary Matrix4f used for multiplication - * @return this matrix for chaining - */ - public final Matrix4f rotate(final float ang_rad, final float x, final float y, final float z, final Matrix4f tmp) { - return mul( tmp.setToRotationAxis(ang_rad, x, y, z) ); - } - - /** - * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(float, Vec3f) axis-rotation matrix}. - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a> - * @param angrad angle in radians - * @param axis rotation axis - * @param tmp temporary Matrix4f used for multiplication - * @return this matrix for chaining - */ - public final Matrix4f rotate(final float ang_rad, final Vec3f axis, final Matrix4f tmp) { - return mul( tmp.setToRotationAxis(ang_rad, axis) ); - } - - /** - * Rotate this matrix with the given {@link Quaternion}, i.e. multiply by {@link #setToRotation(Quaternion) Quaternion's rotation matrix}. - * @param tmp temporary Matrix4f used for multiplication - * @return this matrix for chaining - */ - public final Matrix4f rotate(final Quaternion quat, final Matrix4f tmp) { - return mul( tmp.setToRotation(quat) ); - } - - /** - * Translate this matrix, i.e. multiply by {@link #setToTranslation(float, float, float) translation matrix}. - * @param x x translation - * @param y y translation - * @param z z translation - * @param tmp temporary Matrix4f used for multiplication - * @return this matrix for chaining - */ - public final Matrix4f translate(final float x, final float y, final float z, final Matrix4f tmp) { - return mul( tmp.setToTranslation(x, y, z) ); - } - - /** - * Translate this matrix, i.e. multiply by {@link #setToTranslation(Vec3f) translation matrix}. - * @param t translation Vec3f - * @param tmp temporary Matrix4f used for multiplication - * @return this matrix for chaining - */ - public final Matrix4f translate(final Vec3f t, final Matrix4f tmp) { - return mul( tmp.setToTranslation(t) ); - } - - /** - * Scale this matrix, i.e. multiply by {@link #setToScale(float, float, float) scale matrix}. - * @param x x scale - * @param y y scale - * @param z z scale - * @param tmp temporary Matrix4f used for multiplication - * @return this matrix for chaining - */ - public final Matrix4f scale(final float x, final float y, final float z, final Matrix4f tmp) { - return mul( tmp.setToScale(x, y, z) ); - } - - /** - * Scale this matrix, i.e. multiply by {@link #setToScale(float, float, float) scale matrix}. - * @param s scale for x-, y- and z-axis - * @param tmp temporary Matrix4f used for multiplication - * @return this matrix for chaining - */ - public final Matrix4f scale(final float s, final Matrix4f tmp) { - return mul( tmp.setToScale(s, s, s) ); - } - - // - // Matrix Stack - // - - /** - * Push the matrix to it's stack, while preserving this matrix values. - * @see #pop() - */ - public final void push() { - stack.push(this); - } - - /** - * Pop the current matrix from it's stack, replacing this matrix values. - * @see #push() - */ - public final void pop() { - stack.pop(this); - } - - // - // equals - // - - /** - * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * @param o comparison value - * @param epsilon consider using {@link FloatUtil#EPSILON} - * @return true if all components differ less than {@code epsilon}, otherwise false. - */ - public boolean isEqual(final Matrix4f o, final float epsilon) { - if( this == o ) { - return true; - } else { - return FloatUtil.isEqual(m00, o.m00, epsilon) && - FloatUtil.isEqual(m01, o.m01, epsilon) && - FloatUtil.isEqual(m02, o.m02, epsilon) && - FloatUtil.isEqual(m03, o.m03, epsilon) && - FloatUtil.isEqual(m10, o.m10, epsilon) && - FloatUtil.isEqual(m11, o.m11, epsilon) && - FloatUtil.isEqual(m12, o.m12, epsilon) && - FloatUtil.isEqual(m13, o.m13, epsilon) && - FloatUtil.isEqual(m20, o.m20, epsilon) && - FloatUtil.isEqual(m21, o.m21, epsilon) && - FloatUtil.isEqual(m22, o.m22, epsilon) && - FloatUtil.isEqual(m23, o.m23, epsilon) && - FloatUtil.isEqual(m30, o.m30, epsilon) && - FloatUtil.isEqual(m31, o.m31, epsilon) && - FloatUtil.isEqual(m32, o.m32, epsilon) && - FloatUtil.isEqual(m33, o.m33, epsilon); - } - } - - /** - * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * @param o comparison value - * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false. - */ - public boolean isEqual(final Matrix4f o) { - return isEqual(o, FloatUtil.EPSILON); - } - - @Override - public boolean equals(final Object o) { - if( o instanceof Matrix4f ) { - return isEqual((Matrix4f)o, FloatUtil.EPSILON); - } else { - return false; - } - } - - // - // Static multi Matrix ops - // - - /** - * Map object coordinates to window coordinates. - * <p> - * Traditional <code>gluProject</code> implementation. - * </p> - * - * @param obj object position, 3 component vector - * @param mMv modelview matrix - * @param mP projection matrix - * @param viewport Rect4i viewport - * @param winPos 3 component window coordinate, the result - * @return true if successful, otherwise false (z is 1) - */ - public static boolean mapObjToWin(final Vec3f obj, final Matrix4f mMv, final Matrix4f mP, - final Recti viewport, final Vec3f winPos) - { - final Vec4f vec4Tmp1 = new Vec4f(obj, 1f); - - // vec4Tmp2 = Mv * o - // rawWinPos = P * vec4Tmp2 - // rawWinPos = P * ( Mv * o ) - // rawWinPos = P * Mv * o - final Vec4f vec4Tmp2 = mMv.mulVec4f(vec4Tmp1, new Vec4f()); - final Vec4f rawWinPos = mP.mulVec4f(vec4Tmp2, vec4Tmp1); - - if (rawWinPos.w() == 0.0f) { - return false; - } - - final float s = ( 1.0f / rawWinPos.w() ) * 0.5f; - - // Map x, y and z to range 0-1 (w is ignored) - rawWinPos.scale(s).add(0.5f, 0.5f, 0.5f, 0f); - - // Map x,y to viewport - winPos.set( rawWinPos.x() * viewport.width() + viewport.x(), - rawWinPos.y() * viewport.height() + viewport.y(), - rawWinPos.z() ); - - return true; - } - - /** - * Map object coordinates to window coordinates. - * <p> - * Traditional <code>gluProject</code> implementation. - * </p> - * - * @param obj object position, 3 component vector - * @param mPMv [projection] x [modelview] matrix, i.e. P x Mv - * @param viewport Rect4i viewport - * @param winPos 3 component window coordinate, the result - * @return true if successful, otherwise false (z is 1) - */ - public static boolean mapObjToWin(final Vec3f obj, final Matrix4f mPMv, - final Recti viewport, final Vec3f winPos) - { - final Vec4f vec4Tmp2 = new Vec4f(obj, 1f); - - // rawWinPos = P * Mv * o - final Vec4f rawWinPos = mPMv.mulVec4f(vec4Tmp2, new Vec4f()); - - if (rawWinPos.w() == 0.0f) { - return false; - } - - final float s = ( 1.0f / rawWinPos.w() ) * 0.5f; - - // Map x, y and z to range 0-1 (w is ignored) - rawWinPos.scale(s).add(0.5f, 0.5f, 0.5f, 0f); - - // Map x,y to viewport - winPos.set( rawWinPos.x() * viewport.width() + viewport.x(), - rawWinPos.y() * viewport.height() + viewport.y(), - rawWinPos.z() ); - - return true; - } - - /** - * Map window coordinates to object coordinates. - * <p> - * Traditional <code>gluUnProject</code> implementation. - * </p> - * - * @param winx - * @param winy - * @param winz - * @param mMv 4x4 modelview matrix - * @param mP 4x4 projection matrix - * @param viewport Rect4i viewport - * @param objPos 3 component object coordinate, the result - * @param mat4Tmp 16 component matrix for temp storage - * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z) - */ - public static boolean mapWinToObj(final float winx, final float winy, final float winz, - final Matrix4f mMv, final Matrix4f mP, - final Recti viewport, - final Vec3f objPos, - final Matrix4f mat4Tmp) - { - // invPMv = Inv(P x Mv) - final Matrix4f invPMv = mat4Tmp.mul(mP, mMv); - if( !invPMv.invert() ) { - return false; - } - - final Vec4f winPos = new Vec4f(winx, winy, winz, 1f); - - // Map x and y from window coordinates - winPos.add(-viewport.x(), -viewport.y(), 0f, 0f).scale(1f/viewport.width(), 1f/viewport.height(), 1f, 1f); - - // Map to range -1 to 1 - winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f); - - // rawObjPos = Inv(P x Mv) * winPos - final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f()); - - if ( rawObjPos.w() == 0.0f ) { - return false; - } - objPos.set( rawObjPos.scale( 1f / rawObjPos.w() ) ); - - return true; - } - - /** - * Map window coordinates to object coordinates. - * <p> - * Traditional <code>gluUnProject</code> implementation. - * </p> - * - * @param winx - * @param winy - * @param winz - * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv), if null method returns false - * @param viewport Rect4i viewport - * @param objPos 3 component object coordinate, the result - * @return true if successful, otherwise false (null invert matrix, or becomes infinity due to zero z) - */ - public static boolean mapWinToObj(final float winx, final float winy, final float winz, - final Matrix4f invPMv, - final Recti viewport, - final Vec3f objPos) - { - if( null == invPMv ) { - return false; - } - final Vec4f winPos = new Vec4f(winx, winy, winz, 1f); - - // Map x and y from window coordinates - winPos.add(-viewport.x(), -viewport.y(), 0f, 0f).scale(1f/viewport.width(), 1f/viewport.height(), 1f, 1f); - - // Map to range -1 to 1 - winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f); - - // rawObjPos = Inv(P x Mv) * winPos - final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f()); - - if ( rawObjPos.w() == 0.0f ) { - return false; - } - objPos.set( rawObjPos.scale( 1f / rawObjPos.w() ) ); - - return true; - } - - /** - * Map two window coordinates to two object coordinates, - * distinguished by their z component. - * <p> - * Traditional <code>gluUnProject</code> implementation. - * </p> - * - * @param winx - * @param winy - * @param winz1 - * @param winz2 - * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv), if null method returns false - * @param viewport Rect4i viewport vector - * @param objPos1 3 component object coordinate, the result - * @return true if successful, otherwise false (null invert matrix, or becomes infinity due to zero z) - */ - public static boolean mapWinToObj(final float winx, final float winy, final float winz1, final float winz2, - final Matrix4f invPMv, - final Recti viewport, - final Vec3f objPos1, final Vec3f objPos2) - { - if( null == invPMv ) { - return false; - } - final Vec4f winPos = new Vec4f(winx, winy, winz1, 1f); - - // Map x and y from window coordinates - winPos.add(-viewport.x(), -viewport.y(), 0f, 0f).scale(1f/viewport.width(), 1f/viewport.height(), 1f, 1f); - - // Map to range -1 to 1 - winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f); - - // rawObjPos = Inv(P x Mv) * winPos1 - final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f()); - - if ( rawObjPos.w() == 0.0f ) { - return false; - } - objPos1.set( rawObjPos.scale( 1f / rawObjPos.w() ) ); - - // - // winz2 - // - // Map Z to range -1 to 1 - winPos.setZ( winz2 * 2f - 1f ); - - // rawObjPos = Inv(P x Mv) * winPos2 - invPMv.mulVec4f(winPos, rawObjPos); - - if ( rawObjPos.w() == 0.0f ) { - return false; - } - objPos2.set( rawObjPos.scale( 1f / rawObjPos.w() ) ); - - return true; - } - - /** - * Map window coordinates to object coordinates. - * <p> - * Traditional <code>gluUnProject4</code> implementation. - * </p> - * - * @param winx - * @param winy - * @param winz - * @param clipw - * @param mMv 4x4 modelview matrix - * @param mP 4x4 projection matrix - * @param viewport Rect4i viewport vector - * @param near - * @param far - * @param obj_pos 4 component object coordinate, the result - * @param mat4Tmp 16 component matrix for temp storage - * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z) - */ - public static boolean mapWinToObj4(final float winx, final float winy, final float winz, final float clipw, - final Matrix4f mMv, final Matrix4f mP, - final Recti viewport, - final float near, final float far, - final Vec4f objPos, - final Matrix4f mat4Tmp) - { - // invPMv = Inv(P x Mv) - final Matrix4f invPMv = mat4Tmp.mul(mP, mMv); - if( !invPMv.invert() ) { - return false; - } - - final Vec4f winPos = new Vec4f(winx, winy, winz, clipw); - - // Map x and y from window coordinates - winPos.add(-viewport.x(), -viewport.y(), -near, 0f).scale(1f/viewport.width(), 1f/viewport.height(), 1f/(far-near), 1f); - - // Map to range -1 to 1 - winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f); - - // objPos = Inv(P x Mv) * winPos - invPMv.mulVec4f(winPos, objPos); - - if ( objPos.w() == 0.0f ) { - return false; - } - return true; - } - - /** - * Map window coordinates to object coordinates. - * <p> - * Traditional <code>gluUnProject4</code> implementation. - * </p> - * - * @param winx - * @param winy - * @param winz - * @param clipw - * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv), if null method returns false - * @param viewport Rect4i viewport vector - * @param near - * @param far - * @param obj_pos 4 component object coordinate, the result - * @return true if successful, otherwise false (null invert matrix, or becomes infinity due to zero z) - */ - public static boolean mapWinToObj4(final float winx, final float winy, final float winz, final float clipw, - final Matrix4f invPMv, - final Recti viewport, - final float near, final float far, - final Vec4f objPos) - { - if( null == invPMv ) { - return false; - } - final Vec4f winPos = new Vec4f(winx, winy, winz, clipw); - - // Map x and y from window coordinates - winPos.add(-viewport.x(), -viewport.y(), -near, 0f).scale(1f/viewport.width(), 1f/viewport.height(), 1f/(far-near), 1f); - - // Map to range -1 to 1 - winPos.scale(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f); - - // objPos = Inv(P x Mv) * winPos - invPMv.mulVec4f(winPos, objPos); - - if ( objPos.w() == 0.0f ) { - return false; - } - return true; - } - - /** - * Map two window coordinates w/ shared X/Y and distinctive Z - * to a {@link Ray}. The resulting {@link Ray} maybe used for <i>picking</i> - * using a {@link AABBox#getRayIntersection(Vec3f, Ray, float, boolean)}. - * <p> - * Notes for picking <i>winz0</i> and <i>winz1</i>: - * <ul> - * <li>see {@link FloatUtil#getZBufferEpsilon(int, float, float)}</li> - * <li>see {@link FloatUtil#getZBufferValue(int, float, float, float)}</li> - * <li>see {@link FloatUtil#getOrthoWinZ(float, float, float)}</li> - * </ul> - * </p> - * @param winx - * @param winy - * @param winz0 - * @param winz1 - * @param mMv 4x4 modelview matrix - * @param mP 4x4 projection matrix - * @param viewport Rect4i viewport - * @param ray storage for the resulting {@link Ray} - * @param mat4Tmp1 16 component matrix for temp storage - * @param mat4Tmp2 16 component matrix for temp storage - * @return true if successful, otherwise false (failed to invert matrix, or becomes z is infinity) - */ - public static boolean mapWinToRay(final float winx, final float winy, final float winz0, final float winz1, - final Matrix4f mMv, final Matrix4f mP, - final Recti viewport, - final Ray ray, - final Matrix4f mat4Tmp1, final Matrix4f mat4Tmp2) { - // invPMv = Inv(P x Mv) - final Matrix4f invPMv = mat4Tmp1.mul(mP, mMv); - if( !invPMv.invert() ) { - return false; - } - - if( mapWinToObj(winx, winy, winz0, winz1, invPMv, viewport, ray.orig, ray.dir) ) { - ray.dir.sub(ray.orig).normalize(); - return true; - } else { - return false; - } - } - - /** - * 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(Vec3f, Ray, float, boolean)}. - * <p> - * Notes for picking <i>winz0</i> and <i>winz1</i>: - * <ul> - * <li>see {@link FloatUtil#getZBufferEpsilon(int, float, float)}</li> - * <li>see {@link FloatUtil#getZBufferValue(int, float, float, float)}</li> - * <li>see {@link FloatUtil#getOrthoWinZ(float, float, float)}</li> - * </ul> - * </p> - * @param winx - * @param winy - * @param winz0 - * @param winz1 - * @param invPMv inverse [projection] x [modelview] matrix, i.e. Inv(P x Mv), if null method returns false - * @param viewport Rect4i viewport - * @param ray storage for the resulting {@link Ray} - * @return true if successful, otherwise false (null invert matrix, or becomes z is infinity) - */ - public static boolean mapWinToRay(final float winx, final float winy, final float winz0, final float winz1, - final Matrix4f invPMv, - final Recti viewport, - final Ray ray) { - if( mapWinToObj(winx, winy, winz0, winz1, invPMv, viewport, ray.orig, ray.dir) ) { - ray.dir.sub(ray.orig).normalize(); - return true; - } else { - return false; - } - } - - // - // String and internals - // - - /** - * @param sb optional passed StringBuilder instance to be used - * @param rowPrefix optional prefix for each row - * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter} - * @return matrix string representation - */ - public StringBuilder toString(final StringBuilder sb, final String rowPrefix, final String f) { - final float[] tmp = new float[16]; - this.get(tmp); - return FloatUtil.matrixToString(sb, rowPrefix, f,tmp, 0, 4, 4, false /* rowMajorOrder */); - } - - @Override - public String toString() { - return toString(null, null, "%10.5f").toString(); - } - - private float m00, m10, m20, m30; - private float m01, m11, m21, m31; - private float m02, m12, m22, m32; - private float m03, m13, m23, m33; - - final Stack stack = new Stack(0, 16*16); // start w/ zero size, growSize is half GL-min size (32) - - private static class Stack { - private int position; - private float[] buffer; - private final int growSize; - - /** - * @param initialSize initial size - * @param growSize grow size if {@link #position()} is reached, maybe <code>0</code> - * in which case an {@link IndexOutOfBoundsException} is thrown. - */ - public Stack(final int initialSize, final int growSize) { - this.position = 0; - this.growSize = growSize; - this.buffer = new float[initialSize]; - } - - private final void growIfNecessary(final int length) throws IndexOutOfBoundsException { - if( position + length > buffer.length ) { - if( 0 >= growSize ) { - throw new IndexOutOfBoundsException("Out of fixed stack size: "+this); - } - final float[] newBuffer = - new float[buffer.length + growSize]; - System.arraycopy(buffer, 0, newBuffer, 0, position); - buffer = newBuffer; - } - } - - public final Matrix4f push(final Matrix4f src) throws IndexOutOfBoundsException { - growIfNecessary(16); - src.get(buffer, position); - position += 16; - return src; - } - - public final Matrix4f pop(final Matrix4f dest) throws IndexOutOfBoundsException { - position -= 16; - dest.load(buffer, position); - return dest; - } - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java b/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java deleted file mode 100644 index 0d04c69cc..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Quaternion.java +++ /dev/null @@ -1,1188 +0,0 @@ -/** - * Copyright 2010-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.math; - -/** - * Quaternion implementation supporting - * <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q34">Gimbal-Lock</a> free rotations. - * <p> - * All matrix operation provided are in column-major order, - * as specified in the OpenGL fixed function pipeline, i.e. compatibility profile. - * See {@link FloatUtil}. - * </p> - * <p> - * See <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html">Matrix-FAQ</a> - * </p> - * <p> - * See <a href="http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/index.htm">euclideanspace.com-Quaternion</a> - * </p> - */ -public class Quaternion { - private float x, y, z, w; - - /** - * Quaternion Epsilon, used with equals method to determine if two Quaternions are close enough to be considered equal. - * <p> - * Using {@value}, which is ~10 times {@link FloatUtil#EPSILON}. - * </p> - */ - public static final float ALLOWED_DEVIANCE = 1.0E-6f; // FloatUtil.EPSILON == 1.1920929E-7f; double ALLOWED_DEVIANCE: 1.0E-8f - - public Quaternion() { - x = y = z = 0; w = 1; - } - - public Quaternion(final Quaternion q) { - set(q); - } - - public Quaternion(final float x, final float y, final float z, final float w) { - set(x, y, z, w); - } - - /** - * See {@link #magnitude()} for special handling of {@link FloatUtil#EPSILON epsilon}, - * which is not applied here. - * @return the squared magnitude of this quaternion. - */ - public final float magnitudeSquared() { - return w*w + x*x + y*y + z*z; - } - - /** - * Return the magnitude of this quaternion, i.e. sqrt({@link #magnitudeSquared()}) - * <p> - * A magnitude of zero shall equal {@link #isIdentity() identity}, - * as performed by {@link #normalize()}. - * </p> - * <p> - * Implementation Details: - * <ul> - * <li> returns 0f if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * <li> returns 1f if {@link #magnitudeSquared()} is {@link FloatUtil#isEqual(float, float, float) equals 1f} using {@link FloatUtil#EPSILON epsilon}</li> - * </ul> - * </p> - */ - public final float magnitude() { - final float magnitudeSQ = magnitudeSquared(); - if ( FloatUtil.isZero(magnitudeSQ) ) { - return 0f; - } - if ( FloatUtil.isEqual(1f, magnitudeSQ) ) { - return 1f; - } - return FloatUtil.sqrt(magnitudeSQ); - } - - public final float w() { - return w; - } - - public final void setW(final float w) { - this.w = w; - } - - public final float x() { - return x; - } - - public final void setX(final float x) { - this.x = x; - } - - public final float y() { - return y; - } - - public final void setY(final float y) { - this.y = y; - } - - public final float z() { - return z; - } - - public final void setZ(final float z) { - this.z = z; - } - - /** - * Returns the dot product of this quaternion with the given x,y,z and w components. - */ - public final float dot(final float x, final float y, final float z, final float w) { - return this.x * x + this.y * y + this.z * z + this.w * w; - } - - /** - * Returns the dot product of this quaternion with the given quaternion - */ - public final float dot(final Quaternion quat) { - return dot(quat.x(), quat.y(), quat.z(), quat.w()); - } - - /** - * Returns <code>true</code> if this quaternion has identity. - * <p> - * Implementation uses {@link FloatUtil#EPSILON epsilon} to compare - * {@link #w() W} {@link FloatUtil#isEqual(float, float) against 1f} and - * {@link #x() X}, {@link #y() Y} and {@link #z() Z} - * {@link FloatUtil#isZero(float) against zero}. - * </p> - */ - public final boolean isIdentity() { - return FloatUtil.isEqual(1f, w) && VectorUtil.isZero(x, y, z); - // return w == 1f && x == 0f && y == 0f && z == 0f; - } - - /*** - * Set this quaternion to identity (x=0,y=0,z=0,w=1) - * @return this quaternion for chaining. - */ - public final Quaternion setIdentity() { - x = y = z = 0f; w = 1f; - return this; - } - - /** - * Normalize a quaternion required if to be used as a rotational quaternion. - * <p> - * Implementation Details: - * <ul> - * <li> {@link #setIdentity()} if {@link #magnitude()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * </ul> - * </p> - * @return this quaternion for chaining. - */ - public final Quaternion normalize() { - final float norm = magnitude(); - if ( FloatUtil.isZero(norm, FloatUtil.EPSILON) ) { - setIdentity(); - } else { - final float invNorm = 1f/norm; - w *= invNorm; - x *= invNorm; - y *= invNorm; - z *= invNorm; - } - return this; - } - - /** - * Conjugates this quaternion <code>[-x, -y, -z, w]</code>. - * @return this quaternion for chaining. - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q49">Matrix-FAQ Q49</a> - */ - public Quaternion conjugate() { - x = -x; - y = -y; - z = -z; - return this; - } - - /** - * Invert the quaternion If rotational, will produce a the inverse rotation - * <p> - * Implementation Details: - * <ul> - * <li> {@link #conjugate() conjugates} if {@link #magnitudeSquared()} is is {@link FloatUtil#isEqual(float, float, float) equals 1f} using {@link FloatUtil#EPSILON epsilon}</li> - * </ul> - * </p> - * @return this quaternion for chaining. - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q50">Matrix-FAQ Q50</a> - */ - public final Quaternion invert() { - final float magnitudeSQ = magnitudeSquared(); - if ( FloatUtil.isEqual(1.0f, magnitudeSQ) ) { - conjugate(); - } else { - final float invmsq = 1f/magnitudeSQ; - w *= invmsq; - x = -x * invmsq; - y = -y * invmsq; - z = -z * invmsq; - } - return this; - } - - /** - * Set all values of this quaternion using the given src. - * @return this quaternion for chaining. - */ - public final Quaternion set(final Quaternion src) { - this.x = src.x; - this.y = src.y; - this.z = src.z; - this.w = src.w; - return this; - } - - /** - * Set all values of this quaternion using the given components. - * @return this quaternion for chaining. - */ - public final Quaternion set(final float x, final float y, final float z, final float w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - return this; - } - - /** - * Add a quaternion - * - * @param q quaternion - * @return this quaternion for chaining. - * @see <a href="http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm#add">euclideanspace.com-QuaternionAdd</a> - */ - public final Quaternion add(final Quaternion q) { - x += q.x; - y += q.y; - z += q.z; - w += q.w; - return this; - } - - /** - * Subtract a quaternion - * - * @param q quaternion - * @return this quaternion for chaining. - * @see <a href="http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm#add">euclideanspace.com-QuaternionAdd</a> - */ - public final Quaternion subtract(final Quaternion q) { - x -= q.x; - y -= q.y; - z -= q.z; - w -= q.w; - return this; - } - - /** - * Multiply this quaternion by the param quaternion - * - * @param q a quaternion to multiply with - * @return this quaternion for chaining. - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q53">Matrix-FAQ Q53</a> - * @see <a href="http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm#mul">euclideanspace.com-QuaternionMul</a> - */ - public final Quaternion mult(final Quaternion q) { - return set( w * q.x + x * q.w + y * q.z - z * q.y, - w * q.y - x * q.z + y * q.w + z * q.x, - w * q.z + x * q.y - y * q.x + z * q.w, - w * q.w - x * q.x - y * q.y - z * q.z ); - } - - /** - * Scale this quaternion by a constant - * - * @param n a float constant - * @return this quaternion for chaining. - * @see <a href="http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm#scale">euclideanspace.com-QuaternionScale</a> - */ - public final Quaternion scale(final float n) { - x *= n; - y *= n; - z *= n; - w *= n; - return this; - } - - /** - * Rotate this quaternion by the given angle and axis. - * <p> - * The axis must be a normalized vector. - * </p> - * <p> - * A rotational quaternion is made from the given angle and axis. - * </p> - * - * @param angle in radians - * @param axisX x-coord of rotation axis - * @param axisY y-coord of rotation axis - * @param axisZ z-coord of rotation axis - * @return this quaternion for chaining. - */ - public Quaternion rotateByAngleNormalAxis(final float angle, final float axisX, final float axisY, final float axisZ) { - if( VectorUtil.isZero(axisX, axisY, axisZ, FloatUtil.EPSILON) ) { - // no change - return this; - } - final float halfAngle = 0.5f * angle; - final float sin = FloatUtil.sin(halfAngle); - final float qw = FloatUtil.cos(halfAngle); - final float qx = sin * axisX; - final float qy = sin * axisY; - final float qz = sin * axisZ; - return set( x * qw + y * qz - z * qy + w * qx, - -x * qz + y * qw + z * qx + w * qy, - x * qy - y * qx + z * qw + w * qz, - -x * qx - y * qy - z * qz + w * qw); - } - - /** - * Rotate this quaternion by the given angle and axis. - * <p> - * The axis must be a normalized vector. - * </p> - * <p> - * A rotational quaternion is made from the given angle and axis. - * </p> - * - * @param angle in radians - * @param axis Vec3f coord of rotation axis - * @return this quaternion for chaining. - */ - public Quaternion rotateByAngleNormalAxis(final float angle, final Vec3f axis) { - return rotateByAngleNormalAxis(angle, axis.x(), axis.y(), axis.z()); - } - - /** - * Rotate this quaternion around X axis with the given angle in radians - * - * @param angle in radians - * @return this quaternion for chaining. - */ - public Quaternion rotateByAngleX(final float angle) { - final float halfAngle = 0.5f * angle; - final float sin = FloatUtil.sin(halfAngle); - final float cos = FloatUtil.cos(halfAngle); - return set( x * cos + w * sin, - y * cos + z * sin, - -y * sin + z * cos, - -x * sin + w * cos); - } - - /** - * Rotate this quaternion around Y axis with the given angle in radians - * - * @param angle in radians - * @return this quaternion for chaining. - */ - public Quaternion rotateByAngleY(final float angle) { - final float halfAngle = 0.5f * angle; - final float sin = FloatUtil.sin(halfAngle); - final float cos = FloatUtil.cos(halfAngle); - return set( x * cos - z * sin, - y * cos + w * sin, - x * sin + z * cos, - -y * sin + w * cos); - } - - /** - * Rotate this quaternion around Z axis with the given angle in radians - * - * @param angle in radians - * @return this quaternion for chaining. - */ - public Quaternion rotateByAngleZ(final float angle) { - final float halfAngle = 0.5f * angle; - final float sin = FloatUtil.sin(halfAngle); - final float cos = FloatUtil.cos(halfAngle); - return set( x * cos + y * sin, - -x * sin + y * cos, - z * cos + w * sin, - -z * sin + w * cos); - } - - /** - * Rotates this quaternion from the given Euler rotation array <code>angradXYZ</code> in radians. - * <p> - * The <code>angradXYZ</code> array is laid out in natural order: - * <ul> - * <li>x - bank</li> - * <li>y - heading</li> - * <li>z - attitude</li> - * </ul> - * </p> - * For details see {@link #rotateByEuler(float, float, float)}. - * @param angradXYZ euler angle array in radians - * @return this quaternion for chaining. - * @see #rotateByEuler(float, float, float) - */ - public final Quaternion rotateByEuler(final Vec3f angradXYZ) { - return rotateByEuler(angradXYZ.x(), angradXYZ.y(), angradXYZ.z()); - } - - /** - * Rotates this quaternion from the given Euler rotation angles in radians. - * <p> - * The rotations are applied in the given order and using chained rotation per axis: - * <ul> - * <li>y - heading - {@link #rotateByAngleY(float)}</li> - * <li>z - attitude - {@link #rotateByAngleZ(float)}</li> - * <li>x - bank - {@link #rotateByAngleX(float)}</li> - * </ul> - * </p> - * <p> - * Implementation Details: - * <ul> - * <li> NOP if all angles are {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * <li> result is {@link #normalize()}ed</li> - * </ul> - * </p> - * @param bankX the Euler pitch angle in radians. (rotation about the X axis) - * @param headingY the Euler yaw angle in radians. (rotation about the Y axis) - * @param attitudeZ the Euler roll angle in radians. (rotation about the Z axis) - * @return this quaternion for chaining. - * @see #rotateByAngleY(float) - * @see #rotateByAngleZ(float) - * @see #rotateByAngleX(float) - * @see #setFromEuler(float, float, float) - */ - public final Quaternion rotateByEuler(final float bankX, final float headingY, final float attitudeZ) { - if ( VectorUtil.isZero(bankX, headingY, attitudeZ, FloatUtil.EPSILON) ) { - return this; - } else { - // setFromEuler muls: ( 8 + 4 ) , + quat muls 24 = 36 - // this: 8 + 8 + 8 + 4 = 28 muls - return rotateByAngleY(headingY).rotateByAngleZ(attitudeZ).rotateByAngleX(bankX).normalize(); - } - } - - /*** - * Rotate the given vector by this quaternion - * @param vecIn vector to be rotated - * @param vecOut result storage for rotated vector, maybe equal to vecIn for in-place rotation - * - * @return the given vecOut store for chaining - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q63">Matrix-FAQ Q63</a> - */ - public final Vec3f rotateVector(final Vec3f vecIn, final Vec3f vecOut) { - if( vecIn.isZero() ) { - vecOut.set(0, 0, 0); - } else { - final float vecX = vecIn.x(); - final float vecY = vecIn.y(); - final float vecZ = vecIn.z(); - final float x_x = x*x; - final float y_y = y*y; - final float z_z = z*z; - final float w_w = w*w; - - vecOut.setX( w_w * vecX - + x_x * vecX - - z_z * vecX - - y_y * vecX - + 2f * ( y*w*vecZ - z*w*vecY + y*x*vecY + z*x*vecZ ) ); - ; - - vecOut.setY( y_y * vecY - - z_z * vecY - + w_w * vecY - - x_x * vecY - + 2f * ( x*y*vecX + z*y*vecZ + w*z*vecX - x*w*vecZ ) );; - - vecOut.setZ( z_z * vecZ - - y_y * vecZ - - x_x * vecZ - + w_w * vecZ - + 2f * ( x*z*vecX + y*z*vecY - w*y*vecX + w*x*vecY ) ); - } - return vecOut; - } - - /** - * Set this quaternion to a spherical linear interpolation - * between the given start and end quaternions by the given change amount. - * <p> - * Note: Method <i>does not</i> normalize this quaternion! - * </p> - * - * @param a start quaternion - * @param b end quaternion - * @param changeAmnt float between 0 and 1 representing interpolation. - * @return this quaternion for chaining. - * @see <a href="http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/">euclideanspace.com-QuaternionSlerp</a> - */ - public final Quaternion setSlerp(final Quaternion a, final Quaternion b, final float changeAmnt) { - // System.err.println("Slerp.0: A "+a+", B "+b+", t "+changeAmnt); - if (changeAmnt == 0.0f) { - set(a); - } else if (changeAmnt == 1.0f) { - set(b); - } else { - float bx = b.x; - float by = b.y; - float bz = b.z; - float bw = b.w; - - // Calculate angle between them (quat dot product) - float cosHalfTheta = a.x * bx + a.y * by + a.z * bz + a.w * bw; - - final float scale0, scale1; - - if( cosHalfTheta >= 0.95f ) { - // quaternions are close, just use linear interpolation - scale0 = 1.0f - changeAmnt; - scale1 = changeAmnt; - // System.err.println("Slerp.1: Linear Interpol; cosHalfTheta "+cosHalfTheta); - } else if ( cosHalfTheta <= -0.99f ) { - // the quaternions are nearly opposite, - // we can pick any axis normal to a,b to do the rotation - scale0 = 0.5f; - scale1 = 0.5f; - // System.err.println("Slerp.2: Any; cosHalfTheta "+cosHalfTheta); - } else { - // System.err.println("Slerp.3: cosHalfTheta "+cosHalfTheta); - if( cosHalfTheta <= -FloatUtil.EPSILON ) { // FIXME: .. or shall we use the upper bound 'cosHalfTheta < FloatUtil.EPSILON' ? - // Negate the second quaternion and the result of the dot product (Inversion) - bx *= -1f; - by *= -1f; - bz *= -1f; - bw *= -1f; - cosHalfTheta *= -1f; - // System.err.println("Slerp.4: Inverted cosHalfTheta "+cosHalfTheta); - } - final float halfTheta = FloatUtil.acos(cosHalfTheta); - final float sinHalfTheta = FloatUtil.sqrt(1.0f - cosHalfTheta*cosHalfTheta); - // if theta = 180 degrees then result is not fully defined - // we could rotate around any axis normal to qa or qb - if ( Math.abs(sinHalfTheta) < 0.001f ){ // fabs is floating point absolute - scale0 = 0.5f; - scale1 = 0.5f; - // throw new InternalError("XXX"); // FIXME should not be reached due to above inversion ? - } else { - // Calculate the scale for q1 and q2, according to the angle and - // it's sine value - scale0 = FloatUtil.sin((1f - changeAmnt) * halfTheta) / sinHalfTheta; - scale1 = FloatUtil.sin(changeAmnt * halfTheta) / sinHalfTheta; - } - } - - x = a.x * scale0 + bx * scale1; - y = a.y * scale0 + by * scale1; - z = a.z * scale0 + bz * scale1; - w = a.w * scale0 + bw * scale1; - } - // System.err.println("Slerp.X: Result "+this); - return this; - } - - /** - * Set this quaternion to equal the rotation required - * to point the z-axis at <i>direction</i> and the y-axis to <i>up</i>. - * <p> - * Implementation generates a 3x3 matrix - * and is equal with ProjectFloat's lookAt(..).<br/> - * </p> - * Implementation Details: - * <ul> - * <li> result is {@link #normalize()}ed</li> - * </ul> - * </p> - * @param directionIn where to <i>look</i> at - * @param upIn a vector indicating the local <i>up</i> direction. - * @param xAxisOut vector storing the <i>orthogonal</i> x-axis of the coordinate system. - * @param yAxisOut vector storing the <i>orthogonal</i> y-axis of the coordinate system. - * @param zAxisOut vector storing the <i>orthogonal</i> z-axis of the coordinate system. - * @return this quaternion for chaining. - * @see <a href="http://www.euclideanspace.com/maths/algebra/vectors/lookat/index.htm">euclideanspace.com-LookUp</a> - */ - public Quaternion setLookAt(final Vec3f directionIn, final Vec3f upIn, - final Vec3f xAxisOut, final Vec3f yAxisOut, final Vec3f zAxisOut) { - // Z = norm(dir) - zAxisOut.set(directionIn).normalize(); - - // X = upIn x Z - // (borrow yAxisOut for upNorm) - yAxisOut.set(upIn).normalize(); - xAxisOut.cross(yAxisOut, zAxisOut).normalize(); - - // Y = Z x X - // - yAxisOut.cross(zAxisOut, xAxisOut).normalize(); - - /** - final float m00 = xAxisOut[0]; - final float m01 = yAxisOut[0]; - final float m02 = zAxisOut[0]; - final float m10 = xAxisOut[1]; - final float m11 = yAxisOut[1]; - final float m12 = zAxisOut[1]; - final float m20 = xAxisOut[2]; - final float m21 = yAxisOut[2]; - final float m22 = zAxisOut[2]; - */ - return setFromAxes(xAxisOut, yAxisOut, zAxisOut).normalize(); - } - - // - // Conversions - // - - /** - * Initialize this quaternion from two vectors - * <pre> - * q = (s,v) = (v1•v2 , v1 × v2), - * angle = angle(v1, v2) = v1•v2 - * axis = normal(v1 x v2) - * </pre> - * <p> - * Implementation Details: - * <ul> - * <li> {@link #setIdentity()} if square vector-length is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * </ul> - * </p> - * @param v1 not normalized - * @param v2 not normalized - * @param tmpPivotVec temp storage for cross product - * @param tmpNormalVec temp storage to normalize vector - * @return this quaternion for chaining. - */ - public final Quaternion setFromVectors(final Vec3f v1, final Vec3f v2, final Vec3f tmpPivotVec, final Vec3f tmpNormalVec) { - final float factor = v1.length() * v2.length(); - if ( FloatUtil.isZero(factor, FloatUtil.EPSILON ) ) { - return setIdentity(); - } else { - final float dot = v1.dot(v2) / factor; // normalize - final float theta = FloatUtil.acos(Math.max(-1.0f, Math.min(dot, 1.0f))); // clipping [-1..1] - - tmpPivotVec.cross(v1, v2); - - if ( dot < 0.0f && FloatUtil.isZero( tmpPivotVec.length(), FloatUtil.EPSILON ) ) { - // Vectors parallel and opposite direction, therefore a rotation of 180 degrees about any vector - // perpendicular to this vector will rotate vector a onto vector b. - // - // The following guarantees the dot-product will be 0.0. - int dominantIndex; - if (Math.abs(v1.x()) > Math.abs(v1.y())) { - if (Math.abs(v1.x()) > Math.abs(v1.z())) { - dominantIndex = 0; - } else { - dominantIndex = 2; - } - } else { - if (Math.abs(v1.y()) > Math.abs(v1.z())) { - dominantIndex = 1; - } else { - dominantIndex = 2; - } - } - tmpPivotVec.set( dominantIndex, -v1.get( (dominantIndex + 1) % 3 ) ); - tmpPivotVec.set( (dominantIndex + 1) % 3, v1.get( dominantIndex ) ); - tmpPivotVec.set( (dominantIndex + 2) % 3, 0f ); - } - return setFromAngleAxis(theta, tmpPivotVec, tmpNormalVec); - } - } - - /** - * Initialize this quaternion from two normalized vectors - * <pre> - * q = (s,v) = (v1•v2 , v1 × v2), - * angle = angle(v1, v2) = v1•v2 - * axis = v1 x v2 - * </pre> - * <p> - * Implementation Details: - * <ul> - * <li> {@link #setIdentity()} if square vector-length is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * </ul> - * </p> - * @param v1 normalized - * @param v2 normalized - * @param tmpPivotVec temp storage for cross product - * @return this quaternion for chaining. - */ - public final Quaternion setFromNormalVectors(final Vec3f v1, final Vec3f v2, final Vec3f tmpPivotVec) { - final float factor = v1.length() * v2.length(); - if ( FloatUtil.isZero(factor, FloatUtil.EPSILON ) ) { - return setIdentity(); - } else { - final float dot = v1.dot(v2) / factor; // normalize - final float theta = FloatUtil.acos(Math.max(-1.0f, Math.min(dot, 1.0f))); // clipping [-1..1] - - tmpPivotVec.cross(v1, v2); - - if ( dot < 0.0f && FloatUtil.isZero( tmpPivotVec.length(), FloatUtil.EPSILON ) ) { - // Vectors parallel and opposite direction, therefore a rotation of 180 degrees about any vector - // perpendicular to this vector will rotate vector a onto vector b. - // - // The following guarantees the dot-product will be 0.0. - int dominantIndex; - if (Math.abs(v1.x()) > Math.abs(v1.y())) { - if (Math.abs(v1.x()) > Math.abs(v1.z())) { - dominantIndex = 0; - } else { - dominantIndex = 2; - } - } else { - if (Math.abs(v1.y()) > Math.abs(v1.z())) { - dominantIndex = 1; - } else { - dominantIndex = 2; - } - } - tmpPivotVec.set( dominantIndex, -v1.get( (dominantIndex + 1) % 3 ) ); - tmpPivotVec.set( (dominantIndex + 1) % 3, v1.get( dominantIndex ) ); - tmpPivotVec.set( (dominantIndex + 2) % 3, 0f ); - } - return setFromAngleNormalAxis(theta, tmpPivotVec); - } - } - - /*** - * Initialize this quaternion with given non-normalized axis vector and rotation angle - * <p> - * Implementation Details: - * <ul> - * <li> {@link #setIdentity()} if axis is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * </ul> - * </p> - * @param angle rotation angle (rads) - * @param vector axis vector not normalized - * @param tmpV3f temp storage to normalize vector - * @return this quaternion for chaining. - * - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56">Matrix-FAQ Q56</a> - * @see #toAngleAxis(Vec3f) - */ - public final Quaternion setFromAngleAxis(final float angle, final Vec3f vector, final Vec3f tmpV3f) { - tmpV3f.set(vector).normalize(); - return setFromAngleNormalAxis(angle, tmpV3f); - } - - /*** - * Initialize this quaternion with given normalized axis vector and rotation angle - * <p> - * Implementation Details: - * <ul> - * <li> {@link #setIdentity()} if axis is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * </ul> - * </p> - * @param angle rotation angle (rads) - * @param vector axis vector normalized - * @return this quaternion for chaining. - * - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56">Matrix-FAQ Q56</a> - * @see #toAngleAxis(Vec3f) - */ - public final Quaternion setFromAngleNormalAxis(final float angle, final Vec3f vector) { - if( vector.isZero() ) { - setIdentity(); - } else { - final float halfangle = angle * 0.5f; - final float sin = FloatUtil.sin(halfangle); - x = vector.x() * sin; - y = vector.y() * sin; - z = vector.z() * sin; - w = FloatUtil.cos(halfangle); - } - return this; - } - - /** - * Transform the rotational quaternion to axis based rotation angles - * - * @param axis storage for computed axis - * @return the rotation angle in radians - * @see #setFromAngleAxis(float, Vec3f, Vec3f) - */ - public final float toAngleAxis(final Vec3f axis) { - final float sqrLength = x*x + y*y + z*z; - float angle; - if ( FloatUtil.isZero(sqrLength, FloatUtil.EPSILON) ) { // length is ~0 - angle = 0.0f; - axis.set( 1.0f, 0.0f, 0.0f ); - } else { - angle = FloatUtil.acos(w) * 2.0f; - final float invLength = 1.0f / FloatUtil.sqrt(sqrLength); - axis.set( x * invLength, - y * invLength, - z * invLength ); - } - return angle; - } - - /** - * Initializes this quaternion from the given Euler rotation array <code>angradXYZ</code> in radians. - * <p> - * The <code>angradXYZ</code> vector is laid out in natural order: - * <ul> - * <li>x - bank</li> - * <li>y - heading</li> - * <li>z - attitude</li> - * </ul> - * </p> - * For details see {@link #setFromEuler(float, float, float)}. - * @param angradXYZ euler angle vector in radians holding x-bank, y-heading and z-attitude - * @return this quaternion for chaining. - * @see #setFromEuler(float, float, float) - */ - public final Quaternion setFromEuler(final Vec3f angradXYZ) { - return setFromEuler(angradXYZ.x(), angradXYZ.y(), angradXYZ.z()); - } - - /** - * Initializes this quaternion from the given Euler rotation angles in radians. - * <p> - * The rotations are applied in the given order: - * <ul> - * <li>y - heading</li> - * <li>z - attitude</li> - * <li>x - bank</li> - * </ul> - * </p> - * <p> - * Implementation Details: - * <ul> - * <li> {@link #setIdentity()} if all angles are {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * <li> result is {@link #normalize()}ed</li> - * </ul> - * </p> - * @param bankX the Euler pitch angle in radians. (rotation about the X axis) - * @param headingY the Euler yaw angle in radians. (rotation about the Y axis) - * @param attitudeZ the Euler roll angle in radians. (rotation about the Z axis) - * @return this quaternion for chaining. - * - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q60">Matrix-FAQ Q60</a> - * @see <a href="http://vered.rose.utoronto.ca/people/david_dir/GEMS/GEMS.html">Gems</a> - * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm">euclideanspace.com-eulerToQuaternion</a> - * @see #toEuler(Vec3f) - */ - public final Quaternion setFromEuler(final float bankX, final float headingY, final float attitudeZ) { - if ( VectorUtil.isZero(bankX, headingY, attitudeZ, FloatUtil.EPSILON) ) { - return setIdentity(); - } else { - float angle = headingY * 0.5f; - final float sinHeadingY = FloatUtil.sin(angle); - final float cosHeadingY = FloatUtil.cos(angle); - angle = attitudeZ * 0.5f; - final float sinAttitudeZ = FloatUtil.sin(angle); - final float cosAttitudeZ = FloatUtil.cos(angle); - angle = bankX * 0.5f; - final float sinBankX = FloatUtil.sin(angle); - final float cosBankX = FloatUtil.cos(angle); - - // variables used to reduce multiplication calls. - final float cosHeadingXcosAttitude = cosHeadingY * cosAttitudeZ; - final float sinHeadingXsinAttitude = sinHeadingY * sinAttitudeZ; - final float cosHeadingXsinAttitude = cosHeadingY * sinAttitudeZ; - final float sinHeadingXcosAttitude = sinHeadingY * cosAttitudeZ; - - w = cosHeadingXcosAttitude * cosBankX - sinHeadingXsinAttitude * sinBankX; - x = cosHeadingXcosAttitude * sinBankX + sinHeadingXsinAttitude * cosBankX; - y = sinHeadingXcosAttitude * cosBankX + cosHeadingXsinAttitude * sinBankX; - z = cosHeadingXsinAttitude * cosBankX - sinHeadingXcosAttitude * sinBankX; - return normalize(); - } - } - - /** - * Transform this quaternion to Euler rotation angles in radians (pitchX, yawY and rollZ). - * <p> - * The <code>result</code> array is laid out in natural order: - * <ul> - * <li>x - bank</li> - * <li>y - heading</li> - * <li>z - attitude</li> - * </ul> - * </p> - * - * @param result euler angle result vector for radians x-bank, y-heading and z-attitude - * @return the Vec3f `result` filled with x-bank, y-heading and z-attitude - * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm">euclideanspace.com-quaternionToEuler</a> - * @see #setFromEuler(float, float, float) - */ - public Vec3f toEuler(final Vec3f result) { - final float sqw = w*w; - final float sqx = x*x; - final float sqy = y*y; - final float sqz = z*z; - final float unit = sqx + sqy + sqz + sqw; // if normalized is one, otherwise, is correction factor - final float test = x*y + z*w; - - if (test > 0.499f * unit) { // singularity at north pole - result.set( 0f, // x-bank - 2f * FloatUtil.atan2(x, w), // y-heading - FloatUtil.HALF_PI ); // z-attitude - } else if (test < -0.499f * unit) { // singularity at south pole - result.set( 0f, // x-bank - -2 * FloatUtil.atan2(x, w), // y-heading - -FloatUtil.HALF_PI ); // z-attitude - } else { - result.set( FloatUtil.atan2(2f * x * w - 2 * y * z, -sqx + sqy - sqz + sqw), // x-bank - FloatUtil.atan2(2f * y * w - 2 * x * z, sqx - sqy - sqz + sqw), // y-heading - FloatUtil.asin( 2f * test / unit) ); // z-attitude - } - return result; - } - - /** - * Compute the quaternion from a 3x3 column rotation matrix - * <p> - * See <a href="ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z">Graphics Gems Code</a>,<br/> - * <a href="http://mathworld.wolfram.com/MatrixTrace.html">MatrixTrace</a>. - * </p> - * <p> - * Buggy <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q55">Matrix-FAQ Q55</a> - * </p> - * - * @return this quaternion for chaining. - * @see #setFromMatrix(Matrix4f) - */ - public Quaternion setFromMatrix(final float m00, final float m01, final float m02, - final float m10, final float m11, final float m12, - final float m20, final float m21, final float m22) { - // Note: Other implementations uses 'T' w/o '+1f' and compares 'T >= 0' while adding missing 1f in sqrt expr. - // However .. this causes setLookAt(..) to fail and actually violates the 'trace definition'. - - // The trace T is the sum of the diagonal elements; see - // http://mathworld.wolfram.com/MatrixTrace.html - final float T = m00 + m11 + m22 + 1f; - // System.err.println("setFromMatrix.0 T "+T+", m00 "+m00+", m11 "+m11+", m22 "+m22); - if ( T > 0f ) { - // System.err.println("setFromMatrix.1"); - final float S = 0.5f / FloatUtil.sqrt(T); // S = 1 / ( 2 t ) - w = 0.25f / S; // w = 1 / ( 4 S ) = t / 2 - x = ( m21 - m12 ) * S; - y = ( m02 - m20 ) * S; - z = ( m10 - m01 ) * S; - } else if ( m00 > m11 && m00 > m22) { - // System.err.println("setFromMatrix.2"); - final float S = 0.5f / FloatUtil.sqrt(1.0f + m00 - m11 - m22); // S=4*qx - w = ( m21 - m12 ) * S; - x = 0.25f / S; - y = ( m10 + m01 ) * S; - z = ( m02 + m20 ) * S; - } else if ( m11 > m22 ) { - // System.err.println("setFromMatrix.3"); - final float S = 0.5f / FloatUtil.sqrt(1.0f + m11 - m00 - m22); // S=4*qy - w = ( m02 - m20 ) * S; - x = ( m20 + m01 ) * S; - y = 0.25f / S; - z = ( m21 + m12 ) * S; - } else { - // System.err.println("setFromMatrix.3"); - final float S = 0.5f / FloatUtil.sqrt(1.0f + m22 - m00 - m11); // S=4*qz - w = ( m10 - m01 ) * S; - x = ( m02 + m20 ) * S; - y = ( m21 + m12 ) * S; - z = 0.25f / S; - } - return this; - } - - /** - * Compute the quaternion from a 3x3 column rotation matrix - * <p> - * See <a href="ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z">Graphics Gems Code</a>,<br/> - * <a href="http://mathworld.wolfram.com/MatrixTrace.html">MatrixTrace</a>. - * </p> - * <p> - * Buggy <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q55">Matrix-FAQ Q55</a> - * </p> - * - * @return this quaternion for chaining. - * @see Matrix4f#getRotation(Quaternion) - * @see #setFromMatrix(float, float, float, float, float, float, float, float, float) - */ - public Quaternion setFromMatrix(final Matrix4f m) { - return m.getRotation(this); - } - - /** - * Transform this quaternion to a normalized 4x4 column matrix representing the rotation. - * <p> - * Implementation Details: - * <ul> - * <li> makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * </ul> - * </p> - * - * @param matrix float[16] store for the resulting normalized column matrix 4x4 - * @return the given matrix store - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54">Matrix-FAQ Q54</a> - * @see #setFromMatrix(Matrix4f) - * @see #setFromMatrix(float, float, float, float, float, float, float, float, float) - */ - public final float[] toMatrix(final float[] matrix) { - // pre-multiply scaled-reciprocal-magnitude to reduce multiplications - final float norm = magnitudeSquared(); - if ( FloatUtil.isZero(norm) ) { - // identity matrix -> srecip = 0f - return FloatUtil.makeIdentity(matrix); - } - final float srecip; - if ( FloatUtil.isEqual(1f, norm) ) { - srecip = 2f; - } else { - srecip = 2.0f / norm; - } - - final float xs = srecip * x; - final float ys = srecip * y; - final float zs = srecip * z; - - final float xx = x * xs; - final float xy = x * ys; - final float xz = x * zs; - final float xw = xs * w; - final float yy = y * ys; - final float yz = y * zs; - final float yw = ys * w; - final float zz = z * zs; - final float zw = zs * w; - - matrix[0+0*4] = 1f - ( yy + zz ); - matrix[0+1*4] = ( xy - zw ); - matrix[0+2*4] = ( xz + yw ); - matrix[0+3*4] = 0f; - - matrix[1+0*4] = ( xy + zw ); - matrix[1+1*4] = 1f - ( xx + zz ); - matrix[1+2*4] = ( yz - xw ); - matrix[1+3*4] = 0f; - - matrix[2+0*4] = ( xz - yw ); - matrix[2+1*4] = ( yz + xw ); - matrix[2+2*4] = 1f - ( xx + yy ); - matrix[2+3*4] = 0f; - - matrix[3+0*4] = 0f; - matrix[3+1*4] = 0f; - matrix[3+2*4] = 0f; - matrix[3+3*4] = 1f; - return matrix; - } - - /** - * Transform this quaternion to a normalized 4x4 column matrix representing the rotation. - * <p> - * Implementation Details: - * <ul> - * <li> makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * </ul> - * </p> - * - * @param matrix store for the resulting normalized column matrix 4x4 - * @return the given matrix store - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54">Matrix-FAQ Q54</a> - * @see #setFromMatrix(float, float, float, float, float, float, float, float, float) - * @see Matrix4f#setToRotation(Quaternion) - */ - public final Matrix4f toMatrix(final Matrix4f matrix) { - return matrix.setToRotation(this); - } - - /** - * Initializes this quaternion to represent a rotation formed by the given three <i>orthogonal</i> axes. - * <p> - * No validation whether the axes are <i>orthogonal</i> is performed. - * </p> - * - * @param xAxis vector representing the <i>orthogonal</i> x-axis of the coordinate system. - * @param yAxis vector representing the <i>orthogonal</i> y-axis of the coordinate system. - * @param zAxis vector representing the <i>orthogonal</i> z-axis of the coordinate system. - * @return this quaternion for chaining. - */ - public final Quaternion setFromAxes(final Vec3f xAxis, final Vec3f yAxis, final Vec3f zAxis) { - return setFromMatrix(xAxis.x(), yAxis.x(), zAxis.x(), - xAxis.y(), yAxis.y(), zAxis.y(), - xAxis.z(), yAxis.z(), zAxis.z()); - } - - /** - * Extracts this quaternion's <i>orthogonal</i> rotation axes. - * - * @param xAxis vector representing the <i>orthogonal</i> x-axis of the coordinate system. - * @param yAxis vector representing the <i>orthogonal</i> y-axis of the coordinate system. - * @param zAxis vector representing the <i>orthogonal</i> z-axis of the coordinate system. - * @param tmpMat4 temporary float[4] matrix, used to transform this quaternion to a matrix. - */ - public void toAxes(final Vec3f xAxis, final Vec3f yAxis, final Vec3f zAxis, final Matrix4f tmpMat4) { - tmpMat4.setToRotation(this); - tmpMat4.getColumn(2, zAxis); - tmpMat4.getColumn(1, yAxis); - tmpMat4.getColumn(0, xAxis); - } - - /** - * Check if the the 3x3 matrix (param) is in fact an affine rotational - * matrix - * - * @param m 3x3 column matrix - * @return true if representing a rotational matrix, false otherwise - */ - @Deprecated - public final boolean isRotationMatrix3f(final float[] m) { - final float epsilon = 0.01f; // margin to allow for rounding errors - if (Math.abs(m[0] * m[3] + m[3] * m[4] + m[6] * m[7]) > epsilon) - return false; - if (Math.abs(m[0] * m[2] + m[3] * m[5] + m[6] * m[8]) > epsilon) - return false; - if (Math.abs(m[1] * m[2] + m[4] * m[5] + m[7] * m[8]) > epsilon) - return false; - if (Math.abs(m[0] * m[0] + m[3] * m[3] + m[6] * m[6] - 1) > epsilon) - return false; - if (Math.abs(m[1] * m[1] + m[4] * m[4] + m[7] * m[7] - 1) > epsilon) - return false; - if (Math.abs(m[2] * m[2] + m[5] * m[5] + m[8] * m[8] - 1) > epsilon) - return false; - return (Math.abs(determinant3f(m) - 1) < epsilon); - } - - @Deprecated - private final float determinant3f(final float[] m) { - return m[0] * m[4] * m[8] + m[3] * m[7] * m[2] + m[6] * m[1] * m[5] - - m[0] * m[7] * m[5] - m[3] * m[1] * m[8] - m[6] * m[4] * m[2]; - } - - // - // std java overrides - // - - /** - * @param o the object to compare for equality - * @return true if this quaternion and the provided quaternion have roughly the same x, y, z and w values. - */ - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Quaternion)) { - return false; - } - final Quaternion comp = (Quaternion) o; - return Math.abs(x - comp.x()) <= ALLOWED_DEVIANCE && - Math.abs(y - comp.y()) <= ALLOWED_DEVIANCE && - Math.abs(z - comp.z()) <= ALLOWED_DEVIANCE && - Math.abs(w - comp.w()) <= ALLOWED_DEVIANCE; - } - @Override - public final int hashCode() { - throw new InternalError("hashCode not designed"); - } - - @Override - public String toString() { - return "Quat[x "+x+", y "+y+", z "+z+", w "+w+"]"; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Ray.java b/src/jogl/classes/com/jogamp/opengl/math/Ray.java deleted file mode 100644 index 25a7d9a70..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Ray.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright 2014-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.math; - -import com.jogamp.opengl.math.geom.AABBox; - -/** - * Simple compound denoting a ray. - * <p> - * A ray, also known as a half line, consists out of it's <i>origin</i> - * and <i>direction</i>. Hence it is bound to only the <i>origin</i> side, - * where the other end is +infinitive. - * <pre> - * R(t) = R0 + Rd * t with R0 origin, Rd direction and t > 0.0 - * </pre> - * </p> - * <p> - * A {@link Ray} maybe used for <i>picking</i> - * using a {@link AABBox bounding box} via - * {@link AABBox#intersectsRay(Ray) fast probe} or - * {@link AABBox#getRayIntersection(float[], Ray, float, boolean, float[], float[], float[]) returning the intersection}. - * </p> - */ -public class Ray { - /** Origin of Ray. */ - public final Vec3f orig = new Vec3f(); - - /** Normalized direction vector of ray. */ - public final Vec3f dir = new Vec3f(); - - @Override - public String toString() { - return "Ray[orig["+orig+"], dir["+dir+"]]"; - } -}
\ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/opengl/math/Recti.java b/src/jogl/classes/com/jogamp/opengl/math/Recti.java deleted file mode 100644 index 58f5e5e77..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Recti.java +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright 2022-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.opengl.math; - -/** - * Rectangle with x, y, width and height integer components. - */ -public final class Recti { - private int x; - private int y; - private int width; - private int height; - - public Recti() {} - - public Recti(final Recti o) { - set(o); - } - - public Recti copy() { - return new Recti(this); - } - - public Recti(final int[/*4*/] xywh) { - set(xywh); - } - - public Recti(final int x, final int y, final int width, final int height) { - set(x, y, width, height); - } - - /** this = o, returns this. */ - public void set(final Recti o) { - this.x = o.x; - this.y = o.y; - this.width = o.width; - this.height= o.height; - } - - /** this = { x, y, width, height }, returns this. */ - public void set(final int x, final int y, final int width, final int height) { - this.x = x; - this.y = y; - this.width = width; - this.height= height; - } - - /** this = xywh, returns this. */ - public Recti set(final int[/*2*/] xywh) { - this.x = xywh[0]; - this.y = xywh[1]; - this.width = xywh[2]; - this.height= xywh[3]; - return this; - } - - /** xywh = this, returns xy. */ - public int[] get(final int[/*4*/] xywh) { - xywh[0] = this.x; - xywh[1] = this.y; - xywh[2] = this.width; - xywh[3] = this.height; - return xywh; - } - - public int x() { return x; } - public int y() { return y; } - public int width() { return width; } - public int height() { return height; } - - public void setX(final int x) { this.x = x; } - public void setY(final int y) { this.y = y; } - public void setWidth(final int width) { this.width = width; } - public void setHeight(final int height) { this.height = height; } - - /** Return true if all components are zero. */ - public boolean isZero() { - return 0 == x && 0 == y; - } - - /** - * Equals check. - * @param o comparison value - * @return true if all components are equal - */ - public boolean isEqual(final Recti o) { - if( this == o ) { - return true; - } else { - return x == o.x && y == o.y && - width == o.width && height == o.height; - } - } - - @Override - public boolean equals(final Object o) { - if( o instanceof Recti ) { - return isEqual((Recti)o); - } else { - return false; - } - } - - @Override - public String toString() { - return x + " / " + y + " " + width + " x " + height; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec2f.java b/src/jogl/classes/com/jogamp/opengl/math/Vec2f.java deleted file mode 100644 index f504b960b..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Vec2f.java +++ /dev/null @@ -1,385 +0,0 @@ -/** - * Copyright 2022-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.opengl.math; - -/** - * 2D Vector based upon two float components. - * - * Implementation borrowed from [gfxbox2](https://jausoft.com/cgit/cs_class/gfxbox2.git/tree/include/pixel/pixel2f.hpp#n29) - * and its data layout from JOAL's Vec3f. - */ -public final class Vec2f { - private float x; - private float y; - - public static Vec2f from_length_angle(final float magnitude, final float radians) { - return new Vec2f((float)(magnitude * Math.cos(radians)), (float)(magnitude * Math.sin(radians))); - } - - public Vec2f() {} - - public Vec2f(final Vec2f o) { - set(o); - } - - /** Creating new Vec2f using Vec3f, dropping z. */ - public Vec2f(final Vec3f o) { - set(o); - } - - public Vec2f copy() { - return new Vec2f(this); - } - - public Vec2f(final float[/*2*/] xy) { - set(xy); - } - - public Vec2f(final float x, final float y) { - set(x, y); - } - - /** this = o, returns this. */ - public void set(final Vec2f o) { - this.x = o.x; - this.y = o.y; - } - - /** this = o while dropping z, returns this. */ - public void set(final Vec3f o) { - this.x = o.x(); - this.y = o.y(); - } - - /** this = { x, y }, returns this. */ - public void set(final float x, final float y) { - this.x = x; - this.y = y; - } - - /** this = xy, returns this. */ - public Vec2f set(final float[/*2*/] xy) { - this.x = xy[0]; - this.y = xy[1]; - return this; - } - - /** Sets the ith component, 0 <= i < 2 */ - public void set(final int i, final float val) { - switch (i) { - case 0: x = val; break; - case 1: y = val; break; - default: throw new IndexOutOfBoundsException(); - } - } - - /** xy = this, returns xy. */ - public float[] get(final float[/*2*/] xy) { - xy[0] = this.x; - xy[1] = this.y; - return xy; - } - - /** Gets the ith component, 0 <= i < 2 */ - public float get(final int i) { - switch (i) { - case 0: return x; - case 1: return y; - default: throw new IndexOutOfBoundsException(); - } - } - - public float x() { return x; } - public float y() { return y; } - - public void setX(final float x) { this.x = x; } - public void setY(final float y) { this.y = y; } - - /** this = max(this, m), returns this. */ - public Vec2f max(final Vec2f m) { - this.x = Math.max(this.x, m.x); - this.y = Math.max(this.y, m.y); - return this; - } - /** this = min(this, m), returns this. */ - public Vec2f min(final Vec2f m) { - this.x = Math.min(this.x, m.x); - this.y = Math.min(this.y, m.y); - return this; - } - - /** Returns this * val; creates new vector */ - public Vec2f mul(final float val) { - return new Vec2f(this).scale(val); - } - - /** this = a * b, returns this. */ - public Vec2f mul(final Vec2f a, final Vec2f b) { - x = a.x * b.x; - y = a.y * b.y; - return this; - } - - /** this = this * s, returns this. */ - public Vec2f scale(final float s) { - x *= s; - y *= s; - return this; - } - - /** this = this * { sx, sy }, returns this. */ - public Vec2f scale(final float sx, final float sy) { - x *= sx; - y *= sy; - return this; - } - - /** this = this * { s.x, s.y }, returns this. */ - public Vec2f scale(final Vec2f s) { return scale(s.x, s.y); } - - /** Returns this + arg; creates new vector */ - public Vec2f plus(final Vec2f arg) { - return new Vec2f(this).add(arg); - } - - /** this = a + b, returns this. */ - public Vec2f plus(final Vec2f a, final Vec2f b) { - x = a.x + b.x; - y = a.y + b.y; - return this; - } - - /** this = this + { dx, dy }, returns this. */ - public Vec2f add(final float dx, final float dy) { - x += dx; - y += dy; - return this; - } - - /** this = this + b, returns this. */ - public Vec2f add(final Vec2f b) { - x += b.x; - y += b.y; - return this; - } - - /** Returns this - arg; creates new vector */ - public Vec2f minus(final Vec2f arg) { - return new Vec2f(this).sub(arg); - } - - /** this = a - b, returns this. */ - public Vec2f minus(final Vec2f a, final Vec2f b) { - x = a.x - b.x; - y = a.y - b.y; - return this; - } - - /** this = this - b, returns this. */ - public Vec2f sub(final Vec2f b) { - x -= b.x; - y -= b.y; - return this; - } - - /** Return true if all components are zero, i.e. it's absolute value < {@link #EPSILON}. */ - public boolean isZero() { - return FloatUtil.isZero(x) && FloatUtil.isZero(y); - } - - public void rotate(final float radians, final Vec2f ctr) { - final float cos = (float)Math.cos(radians); - final float sin = (float)Math.sin(radians); - rotate(sin, cos, ctr); - } - - public void rotate(final float sin, final float cos, final Vec2f ctr) { - final float x0 = x - ctr.x; - final float y0 = y - ctr.y; - final float tmp = x0 * cos - y0 * sin + ctr.x; - y = x0 * sin + y0 * cos + ctr.y; - x = tmp; - } - - /** - * Return the length of this vector, a.k.a the <i>norm</i> or <i>magnitude</i> - */ - public float length() { - return (float) Math.sqrt(lengthSq()); - } - - /** - * Return the squared length of this vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i> - */ - public float lengthSq() { - return x*x + y*y; - } - - /** - * Return the direction angle of this vector in radians - */ - public float angle() { - // Utilize atan2 taking y=sin(a) and x=cos(a), resulting in proper direction angle for all quadrants. - return (float) Math.atan2(y, x); - } - - /** - * Normalize this vector in place - */ - public Vec2f normalize() { - final float lengthSq = lengthSq(); - if ( FloatUtil.isZero( lengthSq ) ) { - x = 0.0f; - y = 0.0f; - } else { - final float invSqr = 1.0f / (float)Math.sqrt(lengthSq); - x *= invSqr; - y *= invSqr; - } - return this; - } - - /** - * Return the squared distance between this vector and the given one. - * <p> - * When comparing the relative distance between two points it is usually sufficient to compare the squared - * distances, thus avoiding an expensive square root operation. - * </p> - */ - public float distSq(final Vec2f o) { - final float dx = x - o.x; - final float dy = y - o.y; - return dx*dx + dy*dy; - } - - /** - * Return the distance between this vector and the given one. - */ - public float dist(final Vec2f o) { - return (float)Math.sqrt(distSq(o)); - } - - - /** - * Return the dot product of this vector and the given one - * @return the dot product as float - */ - public float dot(final Vec2f arg) { - return x * arg.x + y * arg.y; - } - - /** - * Returns cross product of this vectors and the given one, i.e. *this x o. - * - * The 2D cross product is identical with the 2D perp dot product. - * - * @return the resulting scalar - */ - public float cross(final Vec2f o) { - return x * o.y - y * o.x; - } - - /** - * Return the cosines of the angle between two vectors - */ - public float cosAngle(final Vec2f o) { - return dot(o) / ( length() * o.length() ) ; - } - - /** - * Return the angle between two vectors in radians - */ - public float angle(final Vec2f o) { - return (float) Math.acos( cosAngle(o) ); - } - - /** - * Return the counter-clock-wise (CCW) normal of this vector, i.e. perp(endicular) vector - */ - public Vec2f normal_ccw() { - return new Vec2f(-y, x); - } - - /** - * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * @param o comparison value - * @param epsilon consider using {@link FloatUtil#EPSILON} - * @return true if all components differ less than {@code epsilon}, otherwise false. - */ - public boolean isEqual(final Vec2f o, final float epsilon) { - if( this == o ) { - return true; - } else { - return FloatUtil.isEqual(x, o.x, epsilon) && - FloatUtil.isEqual(y, o.y, epsilon); - } - } - - /** - * Equals check using {@link FloatUtil#EPSILON} in {@link FloatUtil#isEqual(float, float)}. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * @param o comparison value - * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false. - */ - public boolean isEqual(final Vec2f o) { - if( this == o ) { - return true; - } else { - return FloatUtil.isEqual(x, o.x) && - FloatUtil.isEqual(y, o.y); - } - } - - @Override - public boolean equals(final Object o) { - if( o instanceof Vec2f ) { - return isEqual((Vec2f)o); - } else { - return false; - } - } - - @Override - public String toString() { - return x + " / " + y; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec2i.java b/src/jogl/classes/com/jogamp/opengl/math/Vec2i.java deleted file mode 100644 index 9e70a502f..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Vec2i.java +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Copyright 2022-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.opengl.math; - -/** - * 2D Vector based upon two integer components. - */ -public final class Vec2i { - private int x; - private int y; - - public Vec2i() {} - - public Vec2i(final Vec2i o) { - set(o); - } - - public Vec2i copy() { - return new Vec2i(this); - } - - public Vec2i(final int[/*2*/] xy) { - set(xy); - } - - public Vec2i(final int x, final int y) { - set(x, y); - } - - /** this = o, returns this. */ - public void set(final Vec2i o) { - this.x = o.x; - this.y = o.y; - } - - /** this = { x, y }, returns this. */ - public void set(final int x, final int y) { - this.x = x; - this.y = y; - } - - /** this = xy, returns this. */ - public Vec2i set(final int[/*2*/] xy) { - this.x = xy[0]; - this.y = xy[1]; - return this; - } - - /** xy = this, returns xy. */ - public int[] get(final int[/*2*/] xy) { - xy[0] = this.x; - xy[1] = this.y; - return xy; - } - - public int x() { return x; } - public int y() { return y; } - - public void setX(final int x) { this.x = x; } - public void setY(final int y) { this.y = y; } - - /** Return true if all components are zero. */ - public boolean isZero() { - return 0 == x && 0 == y; - } - - /** - * Return the length of this vector, a.k.a the <i>norm</i> or <i>magnitude</i> - */ - public int length() { - return (int) Math.sqrt(lengthSq()); - } - - /** - * Return the squared length of this vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i> - */ - public int lengthSq() { - return x*x + y*y; - } - - /** - * Return the squared distance between this vector and the given one. - * <p> - * When comparing the relative distance between two points it is usually sufficient to compare the squared - * distances, thus avoiding an expensive square root operation. - * </p> - */ - public int distSq(final Vec2i o) { - final int dx = x - o.x; - final int dy = y - o.y; - return dx*dx + dy*dy; - } - - /** - * Return the distance between this vector and the given one. - */ - public int dist(final Vec2i o) { - return (int)Math.sqrt(distSq(o)); - } - - /** - * Equals check. - * @param o comparison value - * @return true if all components are equal - */ - public boolean isEqual(final Vec2i o) { - if( this == o ) { - return true; - } else { - return x == o.x && y == o.y; - } - } - - @Override - public boolean equals(final Object o) { - if( o instanceof Vec2i ) { - return isEqual((Vec2i)o); - } else { - return false; - } - } - - @Override - public String toString() { - return x + " / " + y; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec3f.java b/src/jogl/classes/com/jogamp/opengl/math/Vec3f.java deleted file mode 100644 index 7012edd74..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Vec3f.java +++ /dev/null @@ -1,404 +0,0 @@ -/** - * Copyright 2022-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.opengl.math; - -/** - * 3D Vector based upon three float components. - * - * Implementation borrowed from [gfxbox2](https://jausoft.com/cgit/cs_class/gfxbox2.git/tree/include/pixel/pixel3f.hpp#n29) - * and its data layout from JOAL's Vec3f. - */ -public final class Vec3f { - public static final Vec3f ONE = new Vec3f(1f, 1f, 1f); - public static final Vec3f UNIT_X = new Vec3f(1f, 0f, 0f); - public static final Vec3f UNIT_X_NEG = new Vec3f(-1f, 0f, 0f); - public static final Vec3f UNIT_Y = new Vec3f(0f, 1f, 0f); - public static final Vec3f UNIT_Y_NEG = new Vec3f(0f, -1f, 0f); - public static final Vec3f UNIT_Z = new Vec3f(0f, 0f, 1f); - public static final Vec3f UNIT_Z_NEG = new Vec3f(0f, 0f, -1f); - - private float x; - private float y; - private float z; - - public Vec3f() {} - - public Vec3f(final Vec3f o) { - set(o); - } - - /** Creating new Vec3f using Vec4f, dropping w. */ - public Vec3f(final Vec4f o) { - set(o); - } - - /** Creating new Vec3f using { Vec2f, z}. */ - public Vec3f(final Vec2f o, final float z) { - set(o, z); - } - - public Vec3f copy() { - return new Vec3f(this); - } - - public Vec3f(final float[/*3*/] xyz) { - set(xyz); - } - - public Vec3f(final float x, final float y, final float z) { - set(x, y, z); - } - - /** this = o, returns this. */ - public Vec3f set(final Vec3f o) { - this.x = o.x; - this.y = o.y; - this.z = o.z; - return this; - } - - /** this = { o, z }, returns this. */ - public Vec3f set(final Vec2f o, final float z) { - this.x = o.x(); - this.y = o.y(); - this.z = z; - return this; - } - - /** this = o while dropping w, returns this. */ - public Vec3f set(final Vec4f o) { - this.x = o.x(); - this.y = o.y(); - this.z = o.z(); - return this; - } - - /** this = { x, y, z }, returns this. */ - public Vec3f set(final float x, final float y, final float z) { - this.x = x; - this.y = y; - this.z = z; - return this; - } - - /** this = xyz, returns this. */ - public Vec3f set(final float[/*3*/] xyz) { - this.x = xyz[0]; - this.y = xyz[1]; - this.z = xyz[2]; - return this; - } - - /** Sets the ith component, 0 <= i < 3 */ - public void set(final int i, final float val) { - switch (i) { - case 0: x = val; break; - case 1: y = val; break; - case 2: z = val; break; - default: throw new IndexOutOfBoundsException(); - } - } - - /** xyz = this, returns xyz. */ - public float[] get(final float[/*3*/] xyz) { - xyz[0] = this.x; - xyz[1] = this.y; - xyz[2] = this.z; - return xyz; - } - - /** Gets the ith component, 0 <= i < 3 */ - public float get(final int i) { - switch (i) { - case 0: return x; - case 1: return y; - case 2: return z; - default: throw new IndexOutOfBoundsException(); - } - } - - public float x() { return x; } - public float y() { return y; } - public float z() { return z; } - - public void setX(final float x) { this.x = x; } - public void setY(final float y) { this.y = y; } - public void setZ(final float z) { this.z = z; } - - /** this = max(this, m), returns this. */ - public Vec3f max(final Vec3f m) { - this.x = Math.max(this.x, m.x); - this.y = Math.max(this.y, m.y); - this.z = Math.max(this.z, m.z); - return this; - } - /** this = min(this, m), returns this. */ - public Vec3f min(final Vec3f m) { - this.x = Math.min(this.x, m.x); - this.y = Math.min(this.y, m.y); - this.z = Math.min(this.z, m.z); - return this; - } - - /** Returns this * val; creates new vector */ - public Vec3f mul(final float val) { - return new Vec3f(this).scale(val); - } - - /** this = a * b, returns this. */ - public Vec3f mul(final Vec3f a, final Vec3f b) { - x = a.x * b.x; - y = a.y * b.y; - z = a.z * b.z; - return this; - } - - /** this = this * s, returns this. */ - public Vec3f scale(final float s) { - x *= s; - y *= s; - z *= s; - return this; - } - - /** this = this * { sx, sy, sz }, returns this. */ - public Vec3f scale(final float sx, final float sy, final float sz) { - x *= sx; - y *= sy; - z *= sz; - return this; - } - - /** this = this * { s.x, s.y, s.z }, returns this. */ - public Vec3f scale(final Vec3f s) { return scale(s.x, s.y, s.z); } - - /** Returns this + arg; creates new vector */ - public Vec3f plus(final Vec3f arg) { - return new Vec3f(this).add(arg); - } - - /** this = a + b, returns this. */ - public Vec3f plus(final Vec3f a, final Vec3f b) { - x = a.x + b.x; - y = a.y + b.y; - z = a.z + b.z; - return this; - } - - /** this = this + { dx, dy, dz }, returns this. */ - public Vec3f add(final float dx, final float dy, final float dz) { - x += dx; - y += dy; - z += dz; - return this; - } - - /** this = this + b, returns this. */ - public Vec3f add(final Vec3f b) { - x += b.x; - y += b.y; - z += b.z; - return this; - } - - /** Returns this - arg; creates new vector */ - public Vec3f minus(final Vec3f arg) { - return new Vec3f(this).sub(arg); - } - - /** this = a - b, returns this. */ - public Vec3f minus(final Vec3f a, final Vec3f b) { - x = a.x - b.x; - y = a.y - b.y; - z = a.z - b.z; - return this; - } - - /** this = this - b, returns this. */ - public Vec3f sub(final Vec3f b) { - x -= b.x; - y -= b.y; - z -= b.z; - return this; - } - - /** Return true if all components are zero, i.e. it's absolute value < {@link #EPSILON}. */ - public boolean isZero() { - return FloatUtil.isZero(x) && FloatUtil.isZero(y) && FloatUtil.isZero(z); - } - - /** - * Return the length of this vector, a.k.a the <i>norm</i> or <i>magnitude</i> - */ - public float length() { - return (float) Math.sqrt(lengthSq()); - } - - /** - * Return the squared length of this vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i> - */ - public float lengthSq() { - return x*x + y*y + z*z; - } - - /** - * Normalize this vector in place - */ - public Vec3f normalize() { - final float lengthSq = lengthSq(); - if ( FloatUtil.isZero( lengthSq ) ) { - x = 0.0f; - y = 0.0f; - z = 0.0f; - } else { - final float invSqr = 1.0f / (float)Math.sqrt(lengthSq); - x *= invSqr; - y *= invSqr; - z *= invSqr; - } - return this; - } - - /** - * Return the squared distance between this vector and the given one. - * <p> - * When comparing the relative distance between two points it is usually sufficient to compare the squared - * distances, thus avoiding an expensive square root operation. - * </p> - */ - public float distSq(final Vec3f o) { - final float dx = x - o.x; - final float dy = y - o.y; - final float dz = z - o.z; - return dx*dx + dy*dy + dz*dz; - } - - /** - * Return the distance between this vector and the given one. - */ - public float dist(final Vec3f o) { - return (float)Math.sqrt(distSq(o)); - } - - - /** - * Return the dot product of this vector and the given one - * @return the dot product as float - */ - public float dot(final Vec3f o) { - return x*o.x + y*o.y + z*o.z; - } - - /** Returns this cross arg; creates new vector */ - public Vec3f cross(final Vec3f arg) { - return new Vec3f().cross(this, arg); - } - - /** this = a cross b. NOTE: "this" must be a different vector than - both a and b. */ - public Vec3f cross(final Vec3f a, final Vec3f b) { - x = a.y * b.z - a.z * b.y; - y = a.z * b.x - a.x * b.z; - z = a.x * b.y - a.y * b.x; - return this; - } - - /** - * Return the cosine of the angle between two vectors using {@link #dot(Vec3f)} - */ - public float cosAngle(final Vec3f o) { - return dot(o) / ( length() * o.length() ) ; - } - - /** - * Return the angle between two vectors in radians using {@link Math#acos(double)} on {@link #cosAngle(Vec3f)}. - */ - public float angle(final Vec3f o) { - return (float) Math.acos( cosAngle(o) ); - } - - /** - * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * @param o comparison value - * @param epsilon consider using {@link FloatUtil#EPSILON} - * @return true if all components differ less than {@code epsilon}, otherwise false. - */ - public boolean isEqual(final Vec3f o, final float epsilon) { - if( this == o ) { - return true; - } else { - return FloatUtil.isEqual(x, o.x, epsilon) && - FloatUtil.isEqual(y, o.y, epsilon) && - FloatUtil.isEqual(z, o.z, epsilon); - } - } - - /** - * Equals check using {@link FloatUtil#EPSILON} in {@link FloatUtil#isEqual(float, float)}. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * @param o comparison value - * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false. - */ - public boolean isEqual(final Vec3f o) { - if( this == o ) { - return true; - } else { - return FloatUtil.isEqual(x, o.x) && - FloatUtil.isEqual(y, o.y) && - FloatUtil.isEqual(z, o.z); - } - } - - @Override - public boolean equals(final Object o) { - if( o instanceof Vec3f ) { - return isEqual((Vec3f)o); - } else { - return false; - } - } - - @Override - public String toString() { - return x + " / " + y + " / " + z; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vec4f.java b/src/jogl/classes/com/jogamp/opengl/math/Vec4f.java deleted file mode 100644 index 914450bf1..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Vec4f.java +++ /dev/null @@ -1,394 +0,0 @@ -/** - * Copyright 2022-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ - -package com.jogamp.opengl.math; - -/** - * 4D Vector based upon four float components. - * - * Implementation borrowed from [gfxbox2](https://jausoft.com/cgit/cs_class/gfxbox2.git/tree/include/pixel/pixel3f.hpp#n29) - * and its data layout from JOAL's Vec3f. - */ -public final class Vec4f { - private float x; - private float y; - private float z; - private float w; - - public Vec4f() {} - - public Vec4f(final Vec4f o) { - set(o); - } - - /** Creating new Vec4f using { o, w }. */ - public Vec4f(final Vec3f o, final float w) { - set(o, w); - } - - public Vec4f copy() { - return new Vec4f(this); - } - - public Vec4f(final float[/*4*/] xyzw) { - set(xyzw); - } - - public Vec4f(final float x, final float y, final float z, final float w) { - set(x, y, z, w); - } - - /** this = o, returns this. */ - public Vec4f set(final Vec4f o) { - this.x = o.x; - this.y = o.y; - this.z = o.z; - this.w = o.w; - return this; - } - - /** this = { o, w }, returns this. */ - public Vec4f set(final Vec3f o, final float w) { - this.x = o.x(); - this.y = o.y(); - this.z = o.z(); - this.w = w; - return this; - } - - /** this = { x, y, z, w }, returns this. */ - public Vec4f set(final float x, final float y, final float z, final float w) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - return this; - } - - /** this = xyzw, returns this. */ - public Vec4f set(final float[/*4*/] xyzw) { - this.x = xyzw[0]; - this.y = xyzw[1]; - this.z = xyzw[2]; - this.w = xyzw[3]; - return this; - } - - /** Sets the ith component, 0 <= i < 4 */ - public void set(final int i, final float val) { - switch (i) { - case 0: x = val; break; - case 1: y = val; break; - case 2: z = val; break; - case 3: w = val; break; - default: throw new IndexOutOfBoundsException(); - } - } - - /** xyzw = this, returns xyzw. */ - public float[] get(final float[/*4*/] xyzw) { - xyzw[0] = this.x; - xyzw[1] = this.y; - xyzw[2] = this.z; - xyzw[3] = this.w; - return xyzw; - } - - /** Gets the ith component, 0 <= i < 4 */ - public float get(final int i) { - switch (i) { - case 0: return x; - case 1: return y; - case 2: return z; - case 3: return w; - default: throw new IndexOutOfBoundsException(); - } - } - - public float x() { return x; } - public float y() { return y; } - public float z() { return z; } - public float w() { return w; } - - public void setX(final float x) { this.x = x; } - public void setY(final float y) { this.y = y; } - public void setZ(final float z) { this.z = z; } - public void setW(final float w) { this.w = w; } - - /** this = max(this, m), returns this. */ - public Vec4f max(final Vec4f m) { - this.x = Math.max(this.x, m.x); - this.y = Math.max(this.y, m.y); - this.z = Math.max(this.z, m.z); - this.w = Math.max(this.w, m.w); - return this; - } - /** this = min(this, m), returns this. */ - public Vec4f min(final Vec4f m) { - this.x = Math.min(this.x, m.x); - this.y = Math.min(this.y, m.y); - this.z = Math.min(this.z, m.z); - this.w = Math.min(this.w, m.w); - return this; - } - - /** Returns this * val; creates new vector */ - public Vec4f mul(final float val) { - return new Vec4f(this).scale(val); - } - - /** this = a * b, returns this. */ - public Vec4f mul(final Vec4f a, final Vec4f b) { - x = a.x * b.x; - y = a.y * b.y; - z = a.z * b.z; - w = a.w * b.w; - return this; - } - - /** this = this * s, returns this. */ - public Vec4f scale(final float s) { - x *= s; - y *= s; - z *= s; - w *= s; - return this; - } - - /** this = this * { sx, sy, sz, sw }, returns this. */ - public Vec4f scale(final float sx, final float sy, final float sz, final float sw) { - x *= sx; - y *= sy; - z *= sz; - w *= sw; - return this; - } - - /** this = this * { s.x, s.y, s.z, s.w }, returns this. */ - public Vec4f scale(final Vec4f s) { return scale(s.x, s.y, s.z, s.w); } - - /** Returns this + arg; creates new vector */ - public Vec4f plus(final Vec4f arg) { - return new Vec4f(this).add(arg); - } - - /** this = a + b, returns this. */ - public Vec4f plus(final Vec4f a, final Vec4f b) { - x = a.x + b.x; - y = a.y + b.y; - z = a.z + b.z; - w = a.w + b.w; - return this; - } - - /** this = this + { dx, dy, dz, dw }, returns this. */ - public Vec4f add(final float dx, final float dy, final float dz, final float dw) { - x += dx; - y += dy; - z += dz; - w += dw; - return this; - } - - /** this = this + b, returns this. */ - public Vec4f add(final Vec4f b) { - x += b.x; - y += b.y; - z += b.z; - w += b.w; - return this; - } - - /** Returns this - arg; creates new vector */ - public Vec4f minus(final Vec4f arg) { - return new Vec4f(this).sub(arg); - } - - /** this = a - b, returns this. */ - public Vec4f minus(final Vec4f a, final Vec4f b) { - x = a.x - b.x; - y = a.y - b.y; - z = a.z - b.z; - w = a.w - b.w; - return this; - } - - /** this = this - b, returns this. */ - public Vec4f sub(final Vec4f b) { - x -= b.x; - y -= b.y; - z -= b.z; - w -= b.w; - return this; - } - - /** Return true if all components are zero, i.e. it's absolute value < {@link #EPSILON}. */ - public boolean isZero() { - return FloatUtil.isZero(x) && FloatUtil.isZero(y) && FloatUtil.isZero(z) && FloatUtil.isZero(w); - } - - /** - * Return the length of this vector, a.k.a the <i>norm</i> or <i>magnitude</i> - */ - public float length() { - return (float) Math.sqrt(lengthSq()); - } - - /** - * Return the squared length of this vector, a.k.a the squared <i>norm</i> or squared <i>magnitude</i> - */ - public float lengthSq() { - return x*x + y*y + z*z + w*w; - } - - /** - * Normalize this vector in place - */ - public Vec4f normalize() { - final float lengthSq = lengthSq(); - if ( FloatUtil.isZero( lengthSq ) ) { - x = 0.0f; - y = 0.0f; - z = 0.0f; - w = 0.0f; - } else { - final float invSqr = 1.0f / (float)Math.sqrt(lengthSq); - x *= invSqr; - y *= invSqr; - z *= invSqr; - w *= invSqr; - } - return this; - } - - /** - * Return the squared distance between this vector and the given one. - * <p> - * When comparing the relative distance between two points it is usually sufficient to compare the squared - * distances, thus avoiding an expensive square root operation. - * </p> - */ - public float distSq(final Vec4f o) { - final float dx = x - o.x; - final float dy = y - o.y; - final float dz = z - o.z; - final float dw = w - o.w; - return dx*dx + dy*dy + dz*dz + dw*dw; - } - - /** - * Return the distance between this vector and the given one. - */ - public float dist(final Vec4f o) { - return (float)Math.sqrt(distSq(o)); - } - - - /** - * Return the dot product of this vector and the given one - * @return the dot product as float - */ - public float dot(final Vec4f o) { - return x*o.x + y*o.y + z*o.z + w*o.w; - } - - /** - * Return the cosines of the angle between two vectors - */ - public float cosAngle(final Vec4f o) { - return dot(o) / ( length() * o.length() ) ; - } - - /** - * Return the angle between two vectors in radians - */ - public float angle(final Vec4f o) { - return (float) Math.acos( cosAngle(o) ); - } - - /** - * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * @param o comparison value - * @param epsilon consider using {@link FloatUtil#EPSILON} - * @return true if all components differ less than {@code epsilon}, otherwise false. - */ - public boolean isEqual(final Vec4f o, final float epsilon) { - if( this == o ) { - return true; - } else { - return FloatUtil.isEqual(x, o.x, epsilon) && - FloatUtil.isEqual(y, o.y, epsilon) && - FloatUtil.isEqual(z, o.z, epsilon) && - FloatUtil.isEqual(w, o.w, epsilon); - } - } - - /** - * Equals check using {@link FloatUtil#EPSILON} in {@link FloatUtil#isEqual(float, float)}. - * <p> - * Implementation considers following corner cases: - * <ul> - * <li>NaN == NaN</li> - * <li>+Inf == +Inf</li> - * <li>-Inf == -Inf</li> - * </ul> - * @param o comparison value - * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false. - */ - public boolean isEqual(final Vec4f o) { - if( this == o ) { - return true; - } else { - return FloatUtil.isEqual(x, o.x) && - FloatUtil.isEqual(y, o.y) && - FloatUtil.isEqual(z, o.z) && - FloatUtil.isEqual(w, o.w); - } - } - - @Override - public boolean equals(final Object o) { - if( o instanceof Vec4f ) { - return isEqual((Vec4f)o); - } else { - return false; - } - } - - @Override - public String toString() { - return x + " / " + y + " / " + z + " / " + w; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java b/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java deleted file mode 100644 index e38501c73..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java +++ /dev/null @@ -1,770 +0,0 @@ -/** - * Copyright 2010-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.math; - -import java.util.ArrayList; - -import com.jogamp.graph.geom.plane.Winding; - -public final class VectorUtil { - /** - * Return true if 2D vector components are zero, no {@link FloatUtil#EPSILON} is taken into consideration. - */ - public static boolean isVec2Zero(final Vec3f vec) { - return 0f == vec.x() && 0f == vec.y(); - } - - /** - * Return true if all three vector components are zero, i.e. it's their absolute value < <code>epsilon</code>. - * <p> - * Implementation uses {@link FloatUtil#isZero(float, float)}, see API doc for details. - * </p> - */ - public static boolean isZero(final float x, final float y, final float z, final float epsilon) { - return FloatUtil.isZero(x, epsilon) && - FloatUtil.isZero(y, epsilon) && - FloatUtil.isZero(z, epsilon) ; - } - - /** - * Return true if all three vector components are zero, i.e. it's their absolute value < {@link FloatUtil#EPSILON}. - * <p> - * Implementation uses {@link FloatUtil#isZero(float)}, see API doc for details. - * </p> - */ - public static boolean isZero(final float x, final float y, final float z) { - return FloatUtil.isZero(x) && - FloatUtil.isZero(y) && - FloatUtil.isZero(z) ; - } - - /** - * Return the squared distance between the given two points described vector v1 and v2. - * <p> - * When comparing the relative distance between two points it is usually sufficient to compare the squared - * distances, thus avoiding an expensive square root operation. - * </p> - */ - public static float distSquareVec3(final float[] v1, final float[] v2) { - final float dx = v1[0] - v2[0]; - final float dy = v1[1] - v2[1]; - final float dz = v1[2] - v2[2]; - return dx * dx + dy * dy + dz * dz; - } - - /** - * Return the distance between the given two points described vector v1 and v2. - */ - public static float distVec3(final float[] v1, final float[] v2) { - return FloatUtil.sqrt(distSquareVec3(v1, v2)); - } - - /** - * 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) { - return vec[0]*vec[0] + vec[1]*vec[1]; - } - - /** - * 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) { - return FloatUtil.sqrt(normSquareVec2(vec)); - } - - /** - * Normalize a vector in place - * @param vector input vector - * @return normalized output vector - */ - public static float[] normalizeVec3(final float[] vector) { - final float lengthSq = normSquareVec3(vector); - if ( FloatUtil.isZero(lengthSq, FloatUtil.EPSILON) ) { - vector[0] = 0f; - vector[1] = 0f; - vector[2] = 0f; - } else { - final float invSqr = 1f / FloatUtil.sqrt(lengthSq); - vector[0] *= invSqr; - vector[1] *= invSqr; - vector[2] *= invSqr; - } - return vector; - } - - /** - * 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[], result = vector * scale - * @param result vector for the result, may be vector (in-place) - * @param vector input vector - * @param scale single scale constant for all vector components - * @return result vector for chaining - */ - public static float[] scaleVec2(final float[] result, final float[] vector, final float scale) { - result[0] = vector[0] * scale; - result[1] = vector[1] * scale; - return result; - } - - /** - * Scales a vector by param using given result float[], result = vector * scale - * @param result vector for the result, may be vector (in-place) - * @param vector input vector - * @param scale 2 component scale constant for each vector component - * @return result vector for chaining - */ - public static float[] scaleVec2(final float[] result, final float[] vector, final float[] scale) - { - result[0] = vector[0] * scale[0]; - result[1] = vector[1] * scale[1]; - return result; - } - - /** - * Divides a vector by param using given result float[], result = vector / scale - * @param result vector for the result, may be vector (in-place) - * @param vector input vector - * @param scale single scale constant for all vector components - * @return result vector for chaining - */ - public static float[] divVec2(final float[] result, final float[] vector, final float scale) { - result[0] = vector[0] / scale; - result[1] = vector[1] / scale; - return result; - } - - /** - * Divides a vector by param using given result float[], result = vector / scale - * @param result vector for the result, may be vector (in-place) - * @param vector input vector - * @param scale 2 component scale constant for each vector component - * @return result vector for chaining - */ - public static float[] divVec2(final float[] result, final float[] vector, final float[] scale) - { - result[0] = vector[0] / scale[0]; - result[1] = vector[1] / scale[1]; - return result; - } - - /** - * Adds two vectors, result = v1 + v2 - * @param result float[2] result vector, may be either v1 or v2 (in-place) - * @param v1 vector 1 - * @param v2 vector 2 - * @return result vector for chaining - */ - public static float[] addVec2(final float[] result, final float[] v1, final float[] v2) { - result[0] = v1[0] + v2[0]; - result[1] = v1[1] + v2[1]; - return result; - } - - /** - * Subtracts two vectors, result = v1 - v2 - * @param result float[2] result vector, may be either v1 or v2 (in-place) - * @param v1 vector 1 - * @param v2 vector 2 - * @return result vector for chaining - */ - public static float[] subVec2(final float[] result, final float[] v1, final float[] v2) { - result[0] = v1[0] - v2[0]; - result[1] = v1[1] - v2[1]; - return result; - } - - /** - * 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; - } - - /** - * Calculate the midpoint of two points - * @param p1 first point vector - * @param p2 second point vector - * @return midpoint - */ - public static Vec3f midVec3(final Vec3f result, final Vec3f p1, final Vec3f p2) { - result.set( (p1.x() + p2.x())*0.5f, - (p1.y() + p2.y())*0.5f, - (p1.z() + p2.z())*0.5f ); - return result; - } - - /** - * Return the determinant of 3 vectors - * @param a vector 1 - * @param b vector 2 - * @param c vector 3 - * @return the determinant value - */ - public static float determinantVec3(final Vec3f a, final Vec3f b, final Vec3f c) { - return a.x()*b.y()*c.z() + a.y()*b.z()*c.x() + a.z()*b.x()*c.y() - a.x()*b.z()*c.y() - a.y()*b.x()*c.z() - a.z()*b.y()*c.x(); - } - - /** - * Check if three vertices are colliniear - * @param v1 vertex 1 - * @param v2 vertex 2 - * @param v3 vertex 3 - * @return true if collinear, false otherwise - */ - public static boolean isCollinearVec3(final Vec3f v1, final Vec3f v2, final Vec3f v3) { - return FloatUtil.isZero( determinantVec3(v1, v2, v3), FloatUtil.EPSILON ); - } - - /** - * Check if vertices in triangle circumcircle - * @param a triangle vertex 1 - * @param b triangle vertex 2 - * @param c triangle vertex 3 - * @param d vertex in question - * @return true if the vertex d is inside the circle defined by the - * vertices a, b, c. from paper by Guibas and Stolfi (1985). - */ - public static boolean isInCircleVec2(final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c, final Vert2fImmutable d) { - return (a.x() * a.x() + a.y() * a.y()) * triAreaVec2(b, c, d) - - (b.x() * b.x() + b.y() * b.y()) * triAreaVec2(a, c, d) + - (c.x() * c.x() + c.y() * c.y()) * triAreaVec2(a, b, d) - - (d.x() * d.x() + d.y() * d.y()) * triAreaVec2(a, b, c) > 0; - } - - /** - * Computes oriented area of a triangle - * @param a first vertex - * @param b second vertex - * @param c third vertex - * @return compute twice the area of the oriented triangle (a,b,c), the area - * is positive if the triangle is oriented counterclockwise. - */ - public static float triAreaVec2(final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c){ - return (b.x() - a.x()) * (c.y() - a.y()) - (b.y() - a.y()) * (c.x() - a.x()); - } - - /** - * Check if a vertex is in triangle using barycentric coordinates computation. - * @param a first triangle vertex - * @param b second triangle vertex - * @param c third triangle vertex - * @param p the vertex in question - * @param ac temporary storage - * @param ab temporary storage - * @param ap temporary storage - * @return true if p is in triangle (a, b, c), false otherwise. - */ - public static boolean isInTriangleVec3(final Vec3f a, final Vec3f b, final Vec3f c, - final Vec3f p, - final Vec3f ac, final Vec3f ab, final Vec3f ap){ - // Compute vectors - ac.minus( c, a); // v0 - ab.minus( b, a); // v1 - ap.minus( p, a); // v2 - - // Compute dot products - final float dotAC_AC = ac.dot(ac); - final float dotAC_AB = ac.dot(ab); - final float dotAB_AB = ab.dot(ab); - final float dotAC_AP = ac.dot(ap); - final float dotAB_AP = ab.dot(ap); - - // Compute barycentric coordinates - final float invDenom = 1 / (dotAC_AC * dotAB_AB - dotAC_AB * dotAC_AB); - final float u = (dotAB_AB * dotAC_AP - dotAC_AB * dotAB_AP) * invDenom; - final float v = (dotAC_AC * dotAB_AP - dotAC_AB * dotAC_AP) * invDenom; - - // Check if point is in triangle - return (u >= 0) && (v >= 0) && (u + v < 1); - } - - /** - * Check if one of three vertices are in triangle using barycentric coordinates computation. - * @param a first triangle vertex - * @param b second triangle vertex - * @param c third triangle vertex - * @param p1 the vertex in question - * @param p2 the vertex in question - * @param p3 the vertex in question - * @param ac temporary storage - * @param ab temporary storage - * @param ap temporary storage - * @return true if p1 or p2 or p3 is in triangle (a, b, c), false otherwise. - */ - public static boolean isVec3InTriangle3(final Vec3f a, final Vec3f b, final Vec3f c, - final Vec3f p1, final Vec3f p2, final Vec3f p3, - final Vec3f ac, final Vec3f ab, final Vec3f ap){ - // Compute vectors - ac.minus(c, a); // v0 - ab.minus(b, a); // v1 - - // Compute dot products - final float dotAC_AC = ac.dot(ac); - final float dotAC_AB = ac.dot(ab); - final float dotAB_AB = ab.dot(ab); - - // Compute barycentric coordinates - final float invDenom = 1 / (dotAC_AC * dotAB_AB - dotAC_AB * dotAC_AB); - { - ap.minus(p1, a); // v2 - final float dotAC_AP1 = ac.dot(ap); - final float dotAB_AP1 = ab.dot(ap); - final float u = (dotAB_AB * dotAC_AP1 - dotAC_AB * dotAB_AP1) * invDenom; - final float v = (dotAC_AC * dotAB_AP1 - dotAC_AB * dotAC_AP1) * invDenom; - - // Check if point is in triangle - if ( (u >= 0) && (v >= 0) && (u + v < 1) ) { - return true; - } - } - - { - ap.minus(p2, a); // v2 - final float dotAC_AP2 = ac.dot(ap); - final float dotAB_AP2 = ab.dot(ap); - final float u = (dotAB_AB * dotAC_AP2 - dotAC_AB * dotAB_AP2) * invDenom; - final float v = (dotAC_AC * dotAB_AP2 - dotAC_AB * dotAC_AP2) * invDenom; - - // Check if point is in triangle - if ( (u >= 0) && (v >= 0) && (u + v < 1) ) { - return true; - } - } - - { - ap.minus(p3, a); // v3 - final float dotAC_AP3 = ac.dot(ap); - final float dotAB_AP3 = ab.dot(ap); - final float u = (dotAB_AB * dotAC_AP3 - dotAC_AB * dotAB_AP3) * invDenom; - final float v = (dotAC_AC * dotAB_AP3 - dotAC_AB * dotAC_AP3) * invDenom; - - // Check if point is in triangle - if ( (u >= 0) && (v >= 0) && (u + v < 1) ) { - return true; - } - } - return false; - } - /** - * Check if one of three vertices are in triangle using - * barycentric coordinates computation, using given epsilon for comparison. - * @param a first triangle vertex - * @param b second triangle vertex - * @param c third triangle vertex - * @param p1 the vertex in question - * @param p2 the vertex in question - * @param p3 the vertex in question - * @param tmpAC - * @param tmpAB - * @param tmpAP - * @return true if p1 or p2 or p3 is in triangle (a, b, c), false otherwise. - */ - public static boolean isVec3InTriangle3(final Vec3f a, final Vec3f b, final Vec3f c, - final Vec3f p1, final Vec3f p2, final Vec3f p3, - final Vec3f ac, final Vec3f ab, final Vec3f ap, - final float epsilon) { - // Compute vectors - ac.minus(c, a); // v0 - ab.minus(b, a); // v1 - - // Compute dot products - final float dotAC_AC = ac.dot(ac); - final float dotAC_AB = ac.dot(ab); - final float dotAB_AB = ab.dot(ab); - - // Compute barycentric coordinates - final float invDenom = 1 / (dotAC_AC * dotAB_AB - dotAC_AB * dotAC_AB); - { - ap.minus(p1, a); // v2 - final float dotAC_AP1 = ac.dot(ap); - final float dotAB_AP1 = ab.dot(ap); - final float u = (dotAB_AB * dotAC_AP1 - dotAC_AB * dotAB_AP1) * invDenom; - final float v = (dotAC_AC * dotAB_AP1 - dotAC_AB * dotAC_AP1) * invDenom; - - // Check if point is in triangle - if( FloatUtil.compare(u, 0.0f, epsilon) >= 0 && - FloatUtil.compare(v, 0.0f, epsilon) >= 0 && - FloatUtil.compare(u+v, 1.0f, epsilon) < 0 ) { - return true; - } - } - - { - ap.minus(p2, a); // v3 - final float dotAC_AP2 = ac.dot(ap); - final float dotAB_AP2 = ab.dot(ap); - final float u = (dotAB_AB * dotAC_AP2 - dotAC_AB * dotAB_AP2) * invDenom; - final float v = (dotAC_AC * dotAB_AP2 - dotAC_AB * dotAC_AP2) * invDenom; - - // Check if point is in triangle - if( FloatUtil.compare(u, 0.0f, epsilon) >= 0 && - FloatUtil.compare(v, 0.0f, epsilon) >= 0 && - FloatUtil.compare(u+v, 1.0f, epsilon) < 0 ) { - return true; - } - } - - { - ap.minus(p3, a); // v4 - final float dotAC_AP3 = ac.dot(ap); - final float dotAB_AP3 = ab.dot(ap); - final float u = (dotAB_AB * dotAC_AP3 - dotAC_AB * dotAB_AP3) * invDenom; - final float v = (dotAC_AC * dotAB_AP3 - dotAC_AB * dotAC_AP3) * invDenom; - - // Check if point is in triangle - if( FloatUtil.compare(u, 0.0f, epsilon) >= 0 && - FloatUtil.compare(v, 0.0f, epsilon) >= 0 && - FloatUtil.compare(u+v, 1.0f, epsilon) < 0 ) { - return true; - } - } - return false; - } - - /** - * Check if points are in ccw order - * @param a first vertex - * @param b second vertex - * @param c third vertex - * @return true if the points a,b,c are in a ccw order - */ - public static boolean isCCW(final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c){ - return triAreaVec2(a,b,c) > 0; - } - - /** - * Compute the winding of the 3 given points - * <p> - * Consider using {@link #getWinding(ArrayList)} using the {@link #area(ArrayList)} function over all points - * on complex shapes for a reliable result! - * </p> - * @param a first vertex - * @param b second vertex - * @param c third vertex - * @return {@link Winding#CCW} or {@link Winding#CW} - * @see #getWinding(ArrayList) - */ - public static Winding getWinding(final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c) { - return triAreaVec2(a,b,c) > 0 ? Winding.CCW : Winding.CW ; - } - - /** - * Computes the area of a list of vertices. - * <p> - * This method is utilized e.g. to reliably compute the {@link Winding} of complex shapes. - * </p> - * @param vertices - * @return positive area if ccw else negative area value - * @see #getWinding(ArrayList) - */ - public static float area(final ArrayList<? extends Vert2fImmutable> vertices) { - final int n = vertices.size(); - float area = 0.0f; - for (int p = n - 1, q = 0; q < n; p = q++) { - final Vert2fImmutable pCoord = vertices.get(p); - final Vert2fImmutable qCoord = vertices.get(q); - area += pCoord.x() * qCoord.y() - qCoord.x() * pCoord.y(); - } - return area; - } - - /** - * Compute the winding using the {@link #area(ArrayList)} function over all vertices for complex shapes. - * <p> - * Uses the {@link #area(ArrayList)} function over all points - * on complex shapes for a reliable result! - * </p> - * @param vertices array of Vertices - * @return {@link Winding#CCW} or {@link Winding#CW} - * @see #area(ArrayList) - */ - public static Winding getWinding(final ArrayList<? extends Vert2fImmutable> vertices) { - return area(vertices) >= 0 ? Winding.CCW : Winding.CW ; - } - - /** - * Finds the plane equation of a plane given its normal and a point on the plane. - * - * @param resultV4 vec4 plane equation - * @param normalVec3 - * @param pVec3 - * @return result for chaining - */ - public static Vec4f getPlaneVec3(final Vec4f resultV4, final Vec3f normalVec3, final Vec3f pVec3) { - /** - Ax + By + Cz + D == 0 ; - D = - ( Ax + By + Cz ) - = - ( A*a[0] + B*a[1] + C*a[2] ) - = - vec3Dot ( normal, a ) ; - */ - resultV4.set(normalVec3, -normalVec3.dot(pVec3)); - return resultV4; - } - - /** - * This finds the plane equation of a triangle given three vertices. - * - * @param resultVec4 vec4 plane equation - * @param v1 vec3 - * @param v2 vec3 - * @param v3 vec3 - * @param temp1V3 - * @param temp2V3 - * @return result for chaining - */ - public static Vec4f getPlaneVec3(final Vec4f resultVec4, final Vec3f v1, final Vec3f v2, final Vec3f v3, - final Vec3f temp1V3, final Vec3f temp2V3, final Vec3f temp3V3) { - /** - Ax + By + Cz + D == 0 ; - D = - ( Ax + By + Cz ) - = - ( A*a[0] + B*a[1] + C*a[2] ) - = - vec3Dot ( normal, a ) ; - */ - temp3V3.cross(temp1V3.minus(v2, v1), temp2V3.minus(v3, v1)).normalize(); - resultVec4.set(temp3V3, -temp3V3.dot(v1)); - return resultVec4; - } - - /** - * Return intersection of an infinite line with a plane if exists, otherwise null. - * <p> - * Thanks to <i>Norman Vine -- [email protected] (with hacks by Steve)</i> - * </p> - * - * @param result vec3 result buffer for intersecting coords - * @param ray here representing an infinite line, origin and direction. - * @param plane vec4 plane equation - * @param epsilon - * @return resulting intersecting if exists, otherwise null - */ - public static Vec3f line2PlaneIntersection(final Vec3f result, final Ray ray, final Vec4f plane, final float epsilon) { - final Vec3f plane3 = new Vec3f(plane); - final float tmp = ray.dir.dot(plane3); - - if ( Math.abs(tmp) < epsilon ) { - return null; // ray is parallel to plane - } - result.set( ray.dir ); - return result.scale( -( ray.orig.dot(plane3) + plane.w() ) / tmp ).add(ray.orig); - } - - /** Compute intersection between two segments - * @param a vertex 1 of first segment - * @param b vertex 2 of first segment - * @param c vertex 1 of second segment - * @param d vertex 2 of second segment - * @return the intersection coordinates if the segments intersect, otherwise returns null - */ - public static Vec3f seg2SegIntersection(final Vec3f result, final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c, final Vert2fImmutable d) { - final float determinant = (a.x()-b.x())*(c.y()-d.y()) - (a.y()-b.y())*(c.x()-d.x()); - - if (determinant == 0) - return null; - - final float alpha = (a.x()*b.y()-a.y()*b.x()); - final float beta = (c.x()*d.y()-c.y()*d.y()); - final float xi = ((c.x()-d.x())*alpha-(a.x()-b.x())*beta)/determinant; - final float yi = ((c.y()-d.y())*alpha-(a.y()-b.y())*beta)/determinant; - - final float gamma = (xi - a.x())/(b.x() - a.x()); - final float gamma1 = (xi - c.x())/(d.x() - c.x()); - if(gamma <= 0 || gamma >= 1) return null; - if(gamma1 <= 0 || gamma1 >= 1) return null; - - return result.set(xi, yi, 0); - } - - /** - * Compute intersection between two segments - * @param a vertex 1 of first segment - * @param b vertex 2 of first segment - * @param c vertex 1 of second segment - * @param d vertex 2 of second segment - * @return true if the segments intersect, otherwise returns false - */ - public static boolean testSeg2SegIntersection(final Vert2fImmutable a, final Vert2fImmutable b, - final Vert2fImmutable c, final Vert2fImmutable d) { - final float determinant = (a.x()-b.x())*(c.y()-d.y()) - (a.y()-b.y())*(c.x()-d.x()); - - if (determinant == 0) { - return false; - } - - final float alpha = (a.x()*b.y()-a.y()*b.x()); - final float beta = (c.x()*d.y()-c.y()*d.y()); - final float xi = ((c.x()-d.x())*alpha-(a.x()-b.x())*beta)/determinant; - - final float gamma0 = (xi - a.x())/(b.x() - a.x()); - final float gamma1 = (xi - c.x())/(d.x() - c.x()); - if(gamma0 <= 0 || gamma0 >= 1 || gamma1 <= 0 || gamma1 >= 1) { - return false; - } - - return true; - } - /** - * Compute intersection between two segments, using given epsilon for comparison. - * @param a vertex 1 of first segment - * @param b vertex 2 of first segment - * @param c vertex 1 of second segment - * @param d vertex 2 of second segment - * @return true if the segments intersect, otherwise returns false - */ - public static boolean testSeg2SegIntersection(final Vert2fImmutable a, final Vert2fImmutable b, - final Vert2fImmutable c, final Vert2fImmutable d, - final float epsilon) { - final float determinant = (a.x()-b.x())*(c.y()-d.y()) - (a.y()-b.y())*(c.x()-d.x()); - - if ( FloatUtil.isZero(determinant, epsilon) ) { - return false; - } - - final float alpha = (a.x()*b.y()-a.y()*b.x()); - final float beta = (c.x()*d.y()-c.y()*d.y()); - final float xi = ((c.x()-d.x())*alpha-(a.x()-b.x())*beta)/determinant; - - final float gamma0 = (xi - a.x())/(b.x() - a.x()); - final float gamma1 = (xi - c.x())/(d.x() - c.x()); - - if( FloatUtil.compare(gamma0, 0.0f, epsilon) <= 0 || - FloatUtil.compare(gamma0, 1.0f, epsilon) >= 0 || - FloatUtil.compare(gamma1, 0.0f, epsilon) <= 0 || - FloatUtil.compare(gamma1, 1.0f, epsilon) >= 0 ) { - return false; - } - - if(gamma0 <= 0 || gamma0 >= 1 || gamma1 <= 0 || gamma1 >= 1) { - return false; - } - - return true; - } - - /** - * Compute intersection between two lines - * @param a vertex 1 of first line - * @param b vertex 2 of first line - * @param c vertex 1 of second line - * @param d vertex 2 of second line - * @return the intersection coordinates if the lines intersect, otherwise - * returns null - */ - public static Vec3f line2lineIntersection(final Vec3f result, - final Vert2fImmutable a, final Vert2fImmutable b, - final Vert2fImmutable c, final Vert2fImmutable d) { - final float determinant = (a.x()-b.x())*(c.y()-d.y()) - (a.y()-b.y())*(c.x()-d.x()); - - if (determinant == 0) - return null; - - final float alpha = (a.x()*b.y()-a.y()*b.x()); - final float beta = (c.x()*d.y()-c.y()*d.y()); - final float xi = ((c.x()-d.x())*alpha-(a.x()-b.x())*beta)/determinant; - final float yi = ((c.y()-d.y())*alpha-(a.y()-b.y())*beta)/determinant; - - return result.set(xi, yi, 0); - } - - /** - * Check if a segment intersects with a triangle - * @param a vertex 1 of the triangle - * @param b vertex 2 of the triangle - * @param c vertex 3 of the triangle - * @param d vertex 1 of first segment - * @param e vertex 2 of first segment - * @return true if the segment intersects at least one segment of the triangle, false otherwise - */ - public static boolean testTri2SegIntersection(final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c, - final Vert2fImmutable d, final Vert2fImmutable e){ - return testSeg2SegIntersection(a, b, d, e) || - testSeg2SegIntersection(b, c, d, e) || - testSeg2SegIntersection(a, c, d, e) ; - } - /** - * Check if a segment intersects with a triangle, using given epsilon for comparison. - * @param a vertex 1 of the triangle - * @param b vertex 2 of the triangle - * @param c vertex 3 of the triangle - * @param d vertex 1 of first segment - * @param e vertex 2 of first segment - * @return true if the segment intersects at least one segment of the triangle, false otherwise - */ - public static boolean testTri2SegIntersection(final Vert2fImmutable a, final Vert2fImmutable b, final Vert2fImmutable c, - final Vert2fImmutable d, final Vert2fImmutable e, - final float epsilon){ - return testSeg2SegIntersection(a, b, d, e, epsilon) || - testSeg2SegIntersection(b, c, d, e, epsilon) || - testSeg2SegIntersection(a, c, d, e, epsilon) ; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vert2fImmutable.java b/src/jogl/classes/com/jogamp/opengl/math/Vert2fImmutable.java deleted file mode 100644 index 66bf078f3..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Vert2fImmutable.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright 2012 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.math; - -public interface Vert2fImmutable { - float x(); - - float y(); - - int getCoordCount(); -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/Vert3fImmutable.java b/src/jogl/classes/com/jogamp/opengl/math/Vert3fImmutable.java deleted file mode 100644 index 6f63a746c..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/Vert3fImmutable.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright 2012 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.math; - -public interface Vert3fImmutable extends Vert2fImmutable { - float z(); - - Vec3f getCoord(); -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java b/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java deleted file mode 100644 index 1720caf0e..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java +++ /dev/null @@ -1,923 +0,0 @@ -/** - * Copyright 2010-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.math.geom; - -import com.jogamp.graph.geom.plane.AffineTransform; -import com.jogamp.opengl.math.FloatUtil; -import com.jogamp.opengl.math.Matrix4f; -import com.jogamp.opengl.math.Quaternion; -import com.jogamp.opengl.math.Ray; -import com.jogamp.opengl.math.Recti; -import com.jogamp.opengl.math.Vec3f; -import com.jogamp.opengl.util.PMVMatrix; - - -/** - * Axis Aligned Bounding Box. Defined by two 3D coordinates (low and high) - * The low being the the lower left corner of the box, and the high being the upper - * right corner of the box. - * <p> - * A few references for collision detection, intersections: - * <pre> - * http://www.realtimerendering.com/intersections.html - * http://www.codercorner.com/RayAABB.cpp - * http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter0.htm - * http://realtimecollisiondetection.net/files/levine_swept_sat.txt - * </pre> - * </p> - * - */ -public class AABBox { - private static final boolean DEBUG = FloatUtil.DEBUG; - private final Vec3f low = new Vec3f(); - private final Vec3f high = new Vec3f(); - private final Vec3f center = new Vec3f(); - - /** - * Create an Axis Aligned bounding box (AABBox) with the - * inverse low/high, allowing the next {@link #resize(float, float, float)} command to hit. - * <p> - * The dimension, i.e. {@link #getWidth()} abd {@link #getHeight()} is {@link Float#isInfinite()} thereafter. - * </p> - * @see #reset() - */ - public AABBox() { - reset(); - } - - /** - * Create an AABBox copying all values from the given one - * @param src the box value to be used for the new instance - */ - public AABBox(final AABBox src) { - copy(src); - } - - /** - * Create an AABBox specifying the coordinates - * of the low and high - * @param lx min x-coordinate - * @param ly min y-coordnate - * @param lz min z-coordinate - * @param hx max x-coordinate - * @param hy max y-coordinate - * @param hz max z-coordinate - */ - public AABBox(final float lx, final float ly, final float lz, - final float hx, final float hy, final float hz) { - setSize(lx, ly, lz, hx, hy, hz); - } - - /** - * Create a AABBox defining the low and high - * @param low min xyz-coordinates - * @param high max xyz-coordinates - */ - public AABBox(final float[] low, final float[] high) { - setSize(low, high); - } - - /** - * Create a AABBox defining the low and high - * @param low min xyz-coordinates - * @param high max xyz-coordinates - */ - public AABBox(final Vec3f low, final Vec3f high) { - setSize(low, high); - } - - /** - * Resets this box to the inverse low/high, allowing the next {@link #resize(float, float, float)} command to hit. - * <p> - * The dimension, i.e. {@link #getWidth()} abd {@link #getHeight()} is {@link Float#isInfinite()} thereafter. - * </p> - * @return this AABBox for chaining - */ - public final AABBox reset() { - setLow(Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE); - setHigh(-1*Float.MAX_VALUE,-1*Float.MAX_VALUE,-1*Float.MAX_VALUE); - center.set( 0f, 0f, 0f); - return this; - } - - /** Get the max xyz-coordinates - * @return max xyz coordinates - */ - public final Vec3f getHigh() { - return high; - } - - private final void setHigh(final float hx, final float hy, final float hz) { - this.high.set(hx, hy, hz); - } - - /** Get the min xyz-coordinates - * @return min xyz coordinates - */ - public final Vec3f getLow() { - return low; - } - - private final void setLow(final float lx, final float ly, final float lz) { - this.low.set(lx, ly, lz); - } - - private final void computeCenter() { - center.set(high).add(low).scale(1f/2f); - } - - /** - * Copy given AABBox 'src' values to this AABBox. - * - * @param src source AABBox - * @return this AABBox for chaining - */ - public final AABBox copy(final AABBox src) { - low.set(src.low); - high.set(src.high); - center.set(src.center); - return this; - } - - /** - * Set size of the AABBox specifying the coordinates - * of the low and high. - * - * @param low min xyz-coordinates - * @param high max xyz-coordinates - * @return this AABBox for chaining - */ - public final AABBox setSize(final float[] low, final float[] high) { - return setSize(low[0],low[1],low[2], high[0],high[1],high[2]); - } - - /** - * Set size of the AABBox specifying the coordinates - * of the low and high. - * - * @param lx min x-coordinate - * @param ly min y-coordnate - * @param lz min z-coordinate - * @param hx max x-coordinate - * @param hy max y-coordinate - * @param hz max z-coordinate - * @return this AABBox for chaining - */ - public final AABBox setSize(final float lx, final float ly, final float lz, - final float hx, final float hy, final float hz) { - this.low.set(lx, ly, lz); - this.high.set(hx, hy, hz); - computeCenter(); - return this; - } - - /** - * Set size of the AABBox specifying the coordinates - * of the low and high. - * - * @param low min xyz-coordinates - * @param high max xyz-coordinates - * @return this AABBox for chaining - */ - public final AABBox setSize(final Vec3f low, final Vec3f high) { - this.low.set(low); - this.high.set(high); - computeCenter(); - return this; - } - - /** - * Resize width of this AABBox with explicit left- and right delta values - * @param deltaLeft positive value will shrink width, otherwise expand width - * @param deltaRight positive value will expand width, otherwise shrink width - * @return this AABBox for chaining - */ - public final AABBox resizeWidth(final float deltaLeft, final float deltaRight) { - boolean mod = false; - if( !FloatUtil.isZero(deltaLeft) ) { - low.setX( low.x() + deltaLeft ); - mod = true; - } - if( !FloatUtil.isZero(deltaRight) ) { - high.setX( high.x() + deltaRight ); - mod = true; - } - if( mod ) { - computeCenter(); - } - return this; - } - - /** - * Resize height of this AABBox with explicit bottom- and top delta values - * @param deltaBottom positive value will shrink height, otherwise expand height - * @param deltaTop positive value will expand height, otherwise shrink height - * @return this AABBox for chaining - */ - public final AABBox resizeHeight(final float deltaBottom, final float deltaTop) { - boolean mod = false; - if( !FloatUtil.isZero(deltaBottom) ) { - low.setY( low.y() + deltaBottom ); - mod = true; - } - if( !FloatUtil.isZero(deltaTop) ) { - high.setY( high.y() + deltaTop ); - mod = true; - } - if( mod ) { - computeCenter(); - } - return this; - } - - /** - * Assign values of given AABBox to this instance. - * - * @param o source AABBox - * @return this AABBox for chaining - */ - public final AABBox set(final AABBox o) { - this.low.set(o.low); - this.high.set(o.high); - this.center.set(o.center); - return this; - } - - /** - * Resize the AABBox to encapsulate another AABox - * @param newBox AABBox to be encapsulated in - * @return this AABBox for chaining - */ - public final AABBox resize(final AABBox newBox) { - final Vec3f newLow = newBox.getLow(); - final Vec3f newHigh = newBox.getHigh(); - - /** test low */ - if (newLow.x() < low.x()) { - low.setX( newLow.x() ); - } - if (newLow.y() < low.y()) { - low.setY( newLow.y() ); - } - if (newLow.z() < low.z()) { - low.setZ( newLow.z() ); - } - - /** test high */ - if (newHigh.x() > high.x()) { - high.setX( newHigh.x() ); - } - if (newHigh.y() > high.y()) { - high.setY( newHigh.y() ); - } - if (newHigh.z() > high.z()) { - high.setZ( newHigh.z() ); - } - computeCenter(); - return this; - } - - /** - * Resize the AABBox to encapsulate another AABox, which will be <i>transformed</i> on the fly first. - * @param newBox AABBox to be encapsulated in - * @param t the {@link AffineTransform} applied on <i>newBox</i> on the fly - * @param tmpV3 temporary storage - * @return this AABBox for chaining - */ - public final AABBox resize(final AABBox newBox, final AffineTransform t, final Vec3f tmpV3) { - /** test low */ - { - final Vec3f newBoxLow = newBox.getLow(); - t.transform(newBoxLow, tmpV3); - if (tmpV3.x() < low.x()) - low.setX( tmpV3.x() ); - if (tmpV3.y() < low.y()) - low.setY( tmpV3.y() ); - if (tmpV3.z() < low.z()) - low.setZ( tmpV3.z() ); - } - - /** test high */ - { - final Vec3f newBoxHigh = newBox.getHigh(); - t.transform(newBoxHigh, tmpV3); - if (tmpV3.x() > high.x()) - high.setX( tmpV3.x() ); - if (tmpV3.y() > high.y()) - high.setY( tmpV3.y() ); - if (tmpV3.z() > high.z()) - high.setZ( tmpV3.z() ); - } - - computeCenter(); - return this; - } - - /** - * Resize the AABBox to encapsulate the passed - * xyz-coordinates. - * @param x x-axis coordinate value - * @param y y-axis coordinate value - * @param z z-axis coordinate value - * @return this AABBox for chaining - */ - public final AABBox resize(final float x, final float y, final float z) { - /** test low */ - if (x < low.x()) { - low.setX( x ); - } - if (y < low.y()) { - low.setY( y ); - } - if (z < low.z()) { - low.setZ( z ); - } - - /** test high */ - if (x > high.x()) { - high.setX( x ); - } - if (y > high.y()) { - high.setY( y ); - } - if (z > high.z()) { - high.setZ( z ); - } - - computeCenter(); - return this; - } - - /** - * Resize the AABBox to encapsulate the passed - * xyz-coordinates. - * @param xyz xyz-axis coordinate values - * @param offset of the array - * @return this AABBox for chaining - */ - public final AABBox resize(final float[] xyz, final int offset) { - return resize(xyz[0+offset], xyz[1+offset], xyz[2+offset]); - } - - /** - * Resize the AABBox to encapsulate the passed - * xyz-coordinates. - * @param xyz xyz-axis coordinate values - * @return this AABBox for chaining - */ - public final AABBox resize(final float[] xyz) { - return resize(xyz[0], xyz[1], xyz[2]); - } - - /** - * Resize the AABBox to encapsulate the passed - * xyz-coordinates. - * @param xyz xyz-axis coordinate values - * @return this AABBox for chaining - */ - public final AABBox resize(final Vec3f xyz) { - return resize(xyz.x(), xyz.y(), xyz.z()); - } - - /** - * Check if the x & y coordinates are bounded/contained - * by this AABBox - * @param x x-axis coordinate value - * @param y y-axis coordinate value - * @return true if x belong to (low.x, high.x) and - * y belong to (low.y, high.y) - */ - public final boolean contains(final float x, final float y) { - if(x<low.x() || x>high.x()){ - return false; - } - if(y<low.y()|| y>high.y()){ - return false; - } - return true; - } - - /** - * Check if the xyz coordinates are bounded/contained - * by this AABBox. - * @param x x-axis coordinate value - * @param y y-axis coordinate value - * @param z z-axis coordinate value - * @return true if x belong to (low.x, high.x) and - * y belong to (low.y, high.y) and z belong to (low.z, high.z) - */ - public final boolean contains(final float x, final float y, final float z) { - if(x<low.x() || x>high.x()){ - return false; - } - if(y<low.y()|| y>high.y()){ - return false; - } - if(z<low.z() || z>high.z()){ - return false; - } - return true; - } - - /** - * Check if there is a common region between this AABBox and the passed - * 2D region irrespective of z range - * @param x lower left x-coord - * @param y lower left y-coord - * @param w width - * @param h hight - * @return true if this AABBox might have a common region with this 2D region - */ - public final boolean intersects2DRegion(final float x, final float y, final float w, final float h) { - if (w <= 0 || h <= 0) { - return false; - } - - final float _w = getWidth(); - final float _h = getHeight(); - if (_w <= 0 || _h <= 0) { - return false; - } - - final float x0 = getMinX(); - final float y0 = getMinY(); - return (x >= x0 && - y >= y0 && - x + w <= x0 + _w && - y + h <= y0 + _h); - } - - /** - * Check if {@link Ray} intersects this bounding box. - * <p> - * Versions uses the SAT[1], testing 6 axes. - * Original code for OBBs from MAGIC. - * Rewritten for AABBs and reorganized for early exits[2]. - * </p> - * <pre> - * [1] SAT = Separating Axis Theorem - * [2] http://www.codercorner.com/RayAABB.cpp - * </pre> - * @param ray - * @return - */ - public final boolean intersectsRay(final Ray ray) { - // diff[XYZ] -> VectorUtil.subVec3(diff, ray.orig, center); - // ext[XYZ] -> extend VectorUtil.subVec3(ext, high, center); - - final float dirX = ray.dir.x(); - final float diffX = ray.orig.x() - center.x(); - final float extX = high.x() - center.x(); - if( Math.abs(diffX) > extX && diffX*dirX >= 0f ) return false; - - final float dirY = ray.dir.y(); - final float diffY = ray.orig.y() - center.y(); - final float extY = high.y() - center.y(); - if( Math.abs(diffY) > extY && diffY*dirY >= 0f ) return false; - - final float dirZ = ray.dir.z(); - final float diffZ = ray.orig.z() - center.z(); - final float extZ = high.z() - center.z(); - if( Math.abs(diffZ) > extZ && diffZ*dirZ >= 0f ) return false; - - final float absDirY = Math.abs(dirY); - final float absDirZ = Math.abs(dirZ); - - float f = dirY * diffZ - dirZ * diffY; - if( Math.abs(f) > extY*absDirZ + extZ*absDirY ) return false; - - final float absDirX = Math.abs(dirX); - - f = dirZ * diffX - dirX * diffZ; - if( Math.abs(f) > extX*absDirZ + extZ*absDirX ) return false; - - f = dirX * diffY - dirY * diffX; - if( Math.abs(f) > extX*absDirY + extY*absDirX ) return false; - - return true; - } - - /** - * Return intersection of a {@link Ray} with this bounding box, - * or null if none exist. - * <p> - * <ul> - * <li>Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 [2]</li> - * <li>Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500)</li> - * <li>Epsilon value added by Klaus Hartmann.</li> - * </ul> - * </p> - * <p> - * Method is based on the requirements: - * <ul> - * <li>the integer representation of 0.0f is 0x00000000</li> - * <li>the sign bit of the float is the most significant one</li> - * </ul> - * </p> - * <p> - * Report bugs: [email protected] (original author) - * </p> - * <pre> - * [1] http://www.codercorner.com/RayAABB.cpp - * [2] http://tog.acm.org/resources/GraphicsGems/gems/RayBox.c - * </pre> - * @param result vec3 - * @param ray - * @param epsilon - * @param assumeIntersection if true, method assumes an intersection, i.e. by pre-checking via {@link #intersectsRay(Ray)}. - * In this case method will not validate a possible non-intersection and just computes - * coordinates. - * @return float[3] result of intersection coordinates, or null if none exists - */ - public final Vec3f getRayIntersection(final Vec3f result, final Ray ray, final float epsilon, - final boolean assumeIntersection) { - final float[] maxT = { -1f, -1f, -1f }; - - final Vec3f origin = ray.orig; - final Vec3f dir = ray.dir; - - boolean inside = true; - - // Find candidate planes. - for(int i=0; i<3; i++) { - final float origin_i = origin.get(i); - final float dir_i = dir.get(i); - final float low_i = low.get(i); - final float high_i = high.get(i); - if(origin_i < low_i) { - result.set(i, low_i); - inside = false; - - // Calculate T distances to candidate planes - if( 0 != Float.floatToIntBits(dir_i) ) { - maxT[i] = (low_i - origin_i) / dir_i; - } - } else if(origin_i > high_i) { - result.set(i, high_i); - inside = false; - - // Calculate T distances to candidate planes - if( 0 != Float.floatToIntBits(dir_i) ) { - maxT[i] = (high_i - origin_i) / dir_i; - } - } - } - - // Ray origin inside bounding box - if(inside) { - result.set(origin); - return result; - } - - // Get largest of the maxT's for final choice of intersection - int whichPlane = 0; - if(maxT[1] > maxT[whichPlane]) { whichPlane = 1; } - if(maxT[2] > maxT[whichPlane]) { whichPlane = 2; } - - if( !assumeIntersection ) { - // Check final candidate actually inside box - if( 0 != ( Float.floatToIntBits(maxT[whichPlane]) & 0x80000000 ) ) { - return null; - } - - /** Use unrolled version below .. - for(int i=0; i<3; i++) { - if( i!=whichPlane ) { - result[i] = origin[i] + maxT[whichPlane] * dir[i]; - if(result[i] < minB[i] - epsilon || result[i] > maxB[i] + epsilon) { return null; } - // if(result[i] < minB[i] || result[i] > maxB[i] ) { return null; } - } - } */ - switch( whichPlane ) { - case 0: - result.setY( origin.y() + maxT[whichPlane] * dir.y() ); - if(result.y() < low.y() - epsilon || result.y() > high.y() + epsilon) { return null; } - result.setZ( origin.z() + maxT[whichPlane] * dir.z() ); - if(result.z() < low.z() - epsilon || result.z() > high.z() + epsilon) { return null; } - break; - case 1: - result.setX( origin.x() + maxT[whichPlane] * dir.x() ); - if(result.x() < low.x() - epsilon || result.x() > high.x() + epsilon) { return null; } - result.setZ( origin.z() + maxT[whichPlane] * dir.z() ); - if(result.z() < low.z() - epsilon || result.z() > high.z() + epsilon) { return null; } - break; - case 2: - result.setX( origin.x() + maxT[whichPlane] * dir.x() ); - if(result.x() < low.x() - epsilon || result.x() > high.x() + epsilon) { return null; } - result.setY( origin.y() + maxT[whichPlane] * dir.y() ); - if(result.y() < low.y() - epsilon || result.y() > high.y() + epsilon) { return null; } - break; - default: - throw new InternalError("XXX"); - } - } else { - switch( whichPlane ) { - case 0: - result.setY( origin.y() + maxT[whichPlane] * dir.y() ); - result.setZ( origin.z() + maxT[whichPlane] * dir.z() ); - break; - case 1: - result.setX( origin.x() + maxT[whichPlane] * dir.x() ); - result.setZ( origin.z() + maxT[whichPlane] * dir.z() ); - break; - case 2: - result.setX( origin.x() + maxT[whichPlane] * dir.x() ); - result.setY( origin.y() + maxT[whichPlane] * dir.y() ); - break; - default: - throw new InternalError("XXX"); - } - } - return result; // ray hits box - } - - /** - * Get the size of this AABBox where the size is represented by the - * length of the vector between low and high. - * @return a float representing the size of the AABBox - */ - public final float getSize() { - return low.dist(high); - } - - /** - * Get the Center of this AABBox - * @return the xyz-coordinates of the center of the AABBox - */ - public final Vec3f getCenter() { - return center; - } - - /** - * Scale this AABBox by a constant around fixed center - * <p> - * high and low is recomputed by scaling its distance to fixed center. - * </p> - * @param size a constant float value - * @return this AABBox for chaining - * @see #scale2(float, float[]) - */ - public final AABBox scale(final float size) { - final Vec3f tmp = new Vec3f(); - tmp.set(high).sub(center).scale(size); - high.set(center).add(tmp); - - tmp.set(low).sub(center).scale(size); - low.set(center).add(tmp); - - return this; - } - - /** - * Scale this AABBox by a constant, recomputing center - * <p> - * high and low is scaled and center recomputed. - * </p> - * @param size a constant float value - * @return this AABBox for chaining - * @see #scale(float, float[]) - */ - public final AABBox scale2(final float size) { - high.scale(size); - low.scale(size); - computeCenter(); - return this; - } - - /** - * Translate this AABBox by a float[3] vector - * @param dx the translation x-component - * @param dy the translation y-component - * @param dz the translation z-component - * @param t the float[3] translation vector - * @return this AABBox for chaining - */ - public final AABBox translate(final float dx, final float dy, final float dz) { - low.add(dx, dy, dz); - high.add(dx, dy, dz); - computeCenter(); - return this; - } - - /** - * Translate this AABBox by a float[3] vector - * @param t the float[3] translation vector - * @return this AABBox for chaining - */ - public final AABBox translate(final Vec3f t) { - low.add(t); - high.add(t); - computeCenter(); - return this; - } - - /** - * Rotate this AABBox by a float[3] vector - * @param quat the {@link Quaternion} used for rotation - * @return this AABBox for chaining - */ - public final AABBox rotate(final Quaternion quat) { - quat.rotateVector(low, low); - quat.rotateVector(high, high); - computeCenter(); - return this; - } - - public final float getMinX() { - return low.x(); - } - - public final float getMinY() { - return low.y(); - } - - public final float getMinZ() { - return low.z(); - } - - public final float getMaxX() { - return high.x(); - } - - public final float getMaxY() { - return high.y(); - } - - public final float getMaxZ() { - return high.z(); - } - - public final float getWidth(){ - return high.x() - low.x(); - } - - public final float getHeight() { - return high.y() - low.y(); - } - - public final float getDepth() { - return high.z() - low.z(); - } - - /** Returns the volume, i.e. width * height * depth */ - public final float getVolume() { - return getWidth() * getHeight() * getDepth(); - } - - /** Return true if {@link #getVolume()} is {@link FloatUtil#isZero(float)}, considering epsilon. */ - public final boolean hasZeroVolume() { - return FloatUtil.isZero(getVolume()); - } - - /** Returns the assumed 2D area, i.e. width * height while assuming low and high lies on same plane. */ - public final float get2DArea() { - return getWidth() * getHeight(); - } - - /** Return true if {@link #get2DArea()} is {@link FloatUtil#isZero(float)}, considering epsilon. */ - public final boolean hasZero2DArea() { - return FloatUtil.isZero(get2DArea()); - } - - @Override - public final boolean equals(final Object obj) { - if( obj == this ) { - return true; - } - if( null == obj || !(obj instanceof AABBox) ) { - return false; - } - final AABBox other = (AABBox) obj; - return low.isEqual(other.low) && high.isEqual(other.high); - } - @Override - public final int hashCode() { - throw new InternalError("hashCode not designed"); - } - - /** - * Transform this box using the given {@link Matrix4f} into {@code out} - * @param mat transformation {@link Matrix4f} - * @param out the resulting {@link AABBox} - * @return the resulting {@link AABBox} for chaining - */ - public AABBox transform(final Matrix4f mat, final AABBox out) { - final Vec3f tmp = new Vec3f(); - out.reset(); - out.resize( mat.mulVec3f(low, tmp) ); - out.resize( mat.mulVec3f(high, tmp) ); - out.computeCenter(); - return out; - } - - /** - * Transform this box using the {@link PMVMatrix#getMvMat() modelview} of the given {@link PMVMatrix} into {@code out} - * @param pmv transformation {@link PMVMatrix} - * @param out the resulting {@link AABBox} - * @return the resulting {@link AABBox} for chaining - */ - public AABBox transformMv(final PMVMatrix pmv, final AABBox out) { - final Vec3f tmp = new Vec3f(); - out.reset(); - out.resize( pmv.mulMvMatVec3f(low, tmp) ); - out.resize( pmv.mulMvMatVec3f(high, tmp) ); - out.computeCenter(); - return out; - } - - /** - * Assume this bounding box as being in object space and - * compute the window bounding box. - * <p> - * If <code>useCenterZ</code> is <code>true</code>, - * only 4 {@link FloatUtil#mapObjToWin(float, float, float, float[], int[], float[], float[], float[]) mapObjToWinCoords} - * operations are made on points [1..4] using {@link #getCenter()}'s z-value. - * Otherwise 8 {@link FloatUtil#mapObjToWin(float, float, float, float[], int[], float[], float[], float[]) mapObjToWinCoords} - * operation on all 8 points are performed. - * </p> - * <pre> - * .z() ------ [4] - * | | - * | | - * .y() ------ [3] - * </pre> - * @param mat4PMv [projection] x [modelview] matrix, i.e. P x Mv - * @param viewport viewport rectangle - * @param useCenterZ - * @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 Matrix4f mat4PMv, final Recti viewport, final boolean useCenterZ) { - final Vec3f tmp = new Vec3f(); - final Vec3f winPos = new Vec3f(); - { - final float objZ = useCenterZ ? center.z() : getMinZ(); - result.reset(); - - Matrix4f.mapObjToWin(tmp.set(getMinX(), getMinY(), objZ), mat4PMv, viewport, winPos); - result.resize(winPos); - - Matrix4f.mapObjToWin(tmp.set(getMinX(), getMaxY(), objZ), mat4PMv, viewport, winPos); - result.resize(winPos); - - Matrix4f.mapObjToWin(tmp.set(getMaxX(), getMaxY(), objZ), mat4PMv, viewport, winPos); - result.resize(winPos); - - Matrix4f.mapObjToWin(tmp.set(getMaxX(), getMinY(), objZ), mat4PMv, viewport, winPos); - result.resize(winPos); - } - - if( !useCenterZ ) { - final float objZ = getMaxZ(); - - Matrix4f.mapObjToWin(tmp.set(getMinX(), getMinY(), objZ), mat4PMv, viewport, winPos); - result.resize(winPos); - - Matrix4f.mapObjToWin(tmp.set(getMinX(), getMaxY(), objZ), mat4PMv, viewport, winPos); - result.resize(winPos); - - Matrix4f.mapObjToWin(tmp.set(getMaxX(), getMaxY(), objZ), mat4PMv, viewport, winPos); - result.resize(winPos); - - Matrix4f.mapObjToWin(tmp.set(getMaxX(), getMinY(), objZ), mat4PMv, viewport, winPos); - result.resize(winPos); - } - if( DEBUG ) { - System.err.printf("AABBox.mapToWindow: view[%s], this %s -> %s%n", viewport, toString(), result.toString()); - } - return result; - } - - @Override - public final String toString() { - return "[dim "+getWidth()+" x "+getHeight()+" x "+getDepth()+ - ", box "+low+" .. "+high+", ctr "+center+"]"; - } -} diff --git a/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java b/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java deleted file mode 100644 index 73079959b..000000000 --- a/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java +++ /dev/null @@ -1,378 +0,0 @@ -/** - * Copyright 2010-2023 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package com.jogamp.opengl.math.geom; - -import com.jogamp.opengl.math.FovHVHalves; -import com.jogamp.opengl.math.Matrix4f; -import com.jogamp.opengl.math.Vec3f; - -/** - * Providing frustum {@link #getPlanes() planes} derived by different inputs - * ({@link #updateFrustumPlanes(float[], int) P*MV}, ..) used to classify objects - * <ul> - * <li> {@link #classifyPoint(float[]) point} </li> - * <li> {@link #classifySphere(float[], float) sphere} </li> - * </ul> - * and to test whether they are outside - * <ul> - * <li> {@link #isPointOutside(float[]) point} </li> - * <li> {@link #isSphereOutside(float[], float) sphere} </li> - * <li> {@link #isAABBoxOutside(AABBox) bounding-box} </li> - * </ul> - * - * <p> - * Extracting the world-frustum planes from the P*Mv: - * <pre> - * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix - * Gil Gribb <[email protected]> - * Klaus Hartmann <[email protected]> - * http://graphics.cs.ucf.edu/cap4720/fall2008/plane_extraction.pdf - * </pre> - * Classifying Point, Sphere and AABBox: - * <pre> - * Efficient View Frustum Culling - * Daniel Sýkora <[email protected]> - * Josef Jelínek <[email protected]> - * http://www.cg.tuwien.ac.at/hostings/cescg/CESCG-2002/DSykoraJJelinek/index.html - * </pre> - * <pre> - * Lighthouse3d.com - * http://www.lighthouse3d.com/tutorials/view-frustum-culling/ - * </pre> - * - * Fundamentals about Planes, Half-Spaces and Frustum-Culling:<br/> - * <pre> - * Planes and Half-Spaces, Max Wagner <[email protected]> - * http://www.emeyex.com/site/tuts/PlanesHalfSpaces.pdf - * </pre> - * <pre> - * Frustum Culling, Max Wagner <[email protected]> - * http://www.emeyex.com/site/tuts/FrustumCulling.pdf - * </pre> - * </p> - */ -public class Frustum { - /** - * {@link Frustum} description by {@link #fovhv} and {@link #zNear}, {@link #zFar}. - */ - public static class FovDesc { - /** Field of view in both directions, may not be centered, either {@link FovHVHalves#inTangents} or radians. */ - public final FovHVHalves fovhv; - /** Near Z */ - public final float zNear; - /** Far Z */ - public final float zFar; - /** - * @param fovhv field of view in both directions, may not be centered, either {@link FovHVHalves#inTangents} or radians - * @param zNear - * @param zFar - * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear}. - */ - public FovDesc(final FovHVHalves fovhv, final float zNear, final float zFar) throws IllegalArgumentException { - if( zNear <= 0.0f || zFar <= zNear ) { - throw new IllegalArgumentException("Requirements zNear > 0 and zFar > zNear, but zNear "+zNear+", zFar "+zFar); - } - this.fovhv = fovhv; - this.zNear = zNear; - this.zFar = zFar; - } - @Override - public final String toString() { - return "FrustumFovDesc["+fovhv.toStringInDegrees()+", Z["+zNear+" - "+zFar+"]]"; - } - } - - /** Normalized planes[l, r, b, t, n, f] */ - protected final Plane[] planes = new Plane[6]; - - /** - * Creates an undefined instance w/o calculating the frustum. - * <p> - * Use one of the <code>update(..)</code> methods to set the {@link #getPlanes() planes}. - * </p> - * @see #updateByPlanes(Plane[]) - * @see #updateFrustumPlanes(float[], int) - */ - public Frustum() { - for (int i = 0; i < 6; ++i) { - planes[i] = new Plane(); - } - } - - /** - * Plane equation := dot(n, x - p) = 0 -> ax + bc + cx + d == 0 - * <p> - * In order to work w/ {@link Frustum#isOutside(AABBox) isOutside(..)} methods, - * the normals have to point to the inside of the frustum. - * </p> - */ - public static class Plane { - /** Normal of the plane */ - public final Vec3f n = new Vec3f(); - - /** Distance to origin */ - public float d; - - /** - * Return signed distance of plane to given point. - * <ul> - * <li>If dist < 0 , then the point p lies in the negative halfspace.</li> - * <li>If dist = 0 , then the point p lies in the plane.</li> - * <li>If dist > 0 , then the point p lies in the positive halfspace.</li> - * </ul> - * A plane cuts 3D space into 2 half spaces. - * <p> - * Positive halfspace is where the plane’s normals vector points into. - * </p> - * <p> - * Negative halfspace is the <i>other side</i> of the plane, i.e. *-1 - * </p> - **/ - public final float distanceTo(final float x, final float y, final float z) { - return n.x() * x + n.y() * y + n.z() * z + d; - } - - /** Return distance of plane to given point, see {@link #distanceTo(float, float, float)}. */ - public final float distanceTo(final Vec3f p) { - return n.x() * p.x() + n.y() * p.y() + n.z() * p.z() + d; - } - - @Override - public String toString() { - return "Plane[ [ " + n + " ], " + d + "]"; - } - } - - /** Index for left plane: {@value} */ - public static final int LEFT = 0; - /** Index for right plane: {@value} */ - public static final int RIGHT = 1; - /** Index for bottom plane: {@value} */ - public static final int BOTTOM = 2; - /** Index for top plane: {@value} */ - public static final int TOP = 3; - /** Index for near plane: {@value} */ - public static final int NEAR = 4; - /** Index for far plane: {@value} */ - public static final int FAR = 5; - - /** - * {@link Plane}s are ordered in the returned array as follows: - * <ul> - * <li>{@link #LEFT}</li> - * <li>{@link #RIGHT}</li> - * <li>{@link #BOTTOM}</li> - * <li>{@link #TOP}</li> - * <li>{@link #NEAR}</li> - * <li>{@link #FAR}</li> - * </ul> - * <p> - * {@link Plane}'s normals are pointing to the inside of the frustum - * in order to work w/ {@link #isOutside(AABBox) isOutside(..)} methods. - * </p> - * - * @return array of normalized {@link Plane}s, order see above. - */ - public final Plane[] getPlanes() { return planes; } - - /** - * Copy the given <code>src</code> planes into this this instance's planes. - * @param src the 6 source planes - */ - public final void updateByPlanes(final Plane[] src) { - for (int i = 0; i < 6; ++i) { - final Plane pD = planes[i]; - final Plane pS = src[i]; - pD.d = pS.d; - System.arraycopy(pS.n, 0, pD.n, 0, 3); - } - } - - /** - * Calculate the frustum planes in world coordinates - * using the passed {@link FovDesc}. - * <p> - * Operation Details: - * <ul> - * <li>The given {@link FovDesc} will be transformed - * into the given perspective matrix (column major order) first, - * see {@link Matrix4f#setToPerspective(FovHVHalves, float, float)}.</li> - * <li>Then the perspective matrix is used to {@link Matrix4f#updateFrustumPlanes(Frustum)} this instance.</li> - * </ul> - * </p> - * <p> - * Frustum plane's normals will point to the inside of the viewing frustum, - * as required by this class. - * </p> - * - * @param m 4x4 matrix in column-major order (also result) - * @param fovDesc {@link Frustum} {@link FovDesc} - * @return given matrix for chaining - * @see Matrix4f#setToPerspective(FovHVHalves, float, float) - * @see Matrix4f#updateFrustumPlanes(Frustum) - * @see Matrix4f#getFrustum(Frustum, FovDesc) - */ - public Matrix4f updateByFovDesc(final Matrix4f m, final FovDesc fovDesc) { - m.setToPerspective(fovDesc.fovhv, fovDesc.zNear, fovDesc.zFar); - m.updateFrustumPlanes(this); - return m; - } - - /** - * Calculate the frustum planes in world coordinates - * using the passed premultiplied P*MV (column major order) matrix. - * <p> - * Frustum plane's normals will point to the inside of the viewing frustum, - * as required by this class. - * </p> - */ - public void updateFrustumPlanes(final Matrix4f pmv) { - pmv.updateFrustumPlanes(this); - } - - private static final boolean isOutsideImpl(final Plane p, final AABBox box) { - final Vec3f lo = box.getLow(); - final Vec3f hi = box.getHigh(); - - if ( p.distanceTo(lo.x(), lo.y(), lo.z()) > 0.0f || - p.distanceTo(hi.x(), lo.y(), lo.z()) > 0.0f || - p.distanceTo(lo.x(), hi.y(), lo.z()) > 0.0f || - p.distanceTo(hi.x(), hi.y(), lo.z()) > 0.0f || - p.distanceTo(lo.x(), lo.y(), hi.z()) > 0.0f || - p.distanceTo(hi.x(), lo.y(), hi.z()) > 0.0f || - p.distanceTo(lo.x(), hi.y(), hi.z()) > 0.0f || - p.distanceTo(hi.x(), hi.y(), hi.z()) > 0.0f ) { - return false; - } - return true; - } - - /** - * Check to see if an axis aligned bounding box is completely outside of the frustum. - * <p> - * Note: If method returns false, the box may only be partially inside. - * </p> - */ - public final boolean isAABBoxOutside(final AABBox box) { - for (int i = 0; i < 6; ++i) { - if ( isOutsideImpl(planes[i], box) ) { - // fully outside - return true; - } - } - // We make no attempt to determine whether it's fully inside or not. - return false; - } - - - public static enum Location { OUTSIDE, INSIDE, INTERSECT }; - - /** - * Check to see if a point is outside, inside or on a plane of the frustum. - * - * @param p the point - * @return {@link Location} of point related to frustum planes - */ - public final Location classifyPoint(final Vec3f p) { - Location res = Location.INSIDE; - - for (int i = 0; i < 6; ++i) { - final float d = planes[i].distanceTo(p); - if ( d < 0.0f ) { - return Location.OUTSIDE; - } else if ( d == 0.0f ) { - res = Location.INTERSECT; - } - } - return res; - } - - /** - * Check to see if a point is outside of the frustum. - * - * @param p the point - * @return true if outside of the frustum, otherwise inside or on a plane - */ - public final boolean isPointOutside(final Vec3f p) { - return Location.OUTSIDE == classifyPoint(p); - } - - /** - * Check to see if a sphere is outside, intersecting or inside of the frustum. - * - * @param p center of the sphere - * @param radius radius of the sphere - * @return {@link Location} of point related to frustum planes - */ - public final Location classifySphere(final Vec3f p, final float radius) { - Location res = Location.INSIDE; // fully inside - - for (int i = 0; i < 6; ++i) { - final float d = planes[i].distanceTo(p); - if ( d < -radius ) { - // fully outside - return Location.OUTSIDE; - } else if (d < radius ) { - // intersecting - res = Location.INTERSECT; - } - } - return res; - } - - /** - * Check to see if a sphere is outside of the frustum. - * - * @param p center of the sphere - * @param radius radius of the sphere - * @return true if outside of the frustum, otherwise inside or intersecting - */ - public final boolean isSphereOutside(final Vec3f p, final float radius) { - return Location.OUTSIDE == classifySphere(p, radius); - } - - public StringBuilder toString(StringBuilder sb) { - if( null == sb ) { - sb = new StringBuilder(); - } - sb.append("Frustum[Planes[").append(System.lineSeparator()) - .append(" L: ").append(planes[0]).append(", ").append(System.lineSeparator()) - .append(" R: ").append(planes[1]).append(", ").append(System.lineSeparator()) - .append(" B: ").append(planes[2]).append(", ").append(System.lineSeparator()) - .append(" T: ").append(planes[3]).append(", ").append(System.lineSeparator()) - .append(" N: ").append(planes[4]).append(", ").append(System.lineSeparator()) - .append(" F: ").append(planes[5]).append("], ").append(System.lineSeparator()) - .append("]"); - return sb; - } - - @Override - public String toString() { - return toString(null).toString(); - } -} |