diff options
author | Sven Gothel <[email protected]> | 2014-02-23 14:51:06 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-02-23 14:51:06 +0100 |
commit | 3352601e0860584509adf2b76f993d03893ded4b (patch) | |
tree | 974fccc8c0eb2f5ad9d4ffd741dfc35869ed67b5 /src/jogl/classes/com/jogamp/opengl/math/geom | |
parent | f51933f0ebe9ae030c26c066e59a728ce08b8559 (diff) | |
parent | c67de337a8aaf52e36104c3f13e273aa19d21f1f (diff) |
Merge branch 'master' into stash_glyphcache
Conflicts:
make/scripts/tests.sh
src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
src/jogl/classes/com/jogamp/graph/curve/Region.java
src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java
src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java
src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java
src/jogl/classes/com/jogamp/graph/font/Font.java
src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java
src/jogl/classes/jogamp/graph/curve/text/GlyphShape.java
src/jogl/classes/jogamp/graph/curve/text/GlyphString.java
src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java
src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java
src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl/math/geom')
-rw-r--r-- | src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java | 360 | ||||
-rw-r--r-- | src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java | 388 |
2 files changed, 748 insertions, 0 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java b/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java new file mode 100644 index 000000000..5fbc28c60 --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/math/geom/AABBox.java @@ -0,0 +1,360 @@ +/** + * Copyright 2010 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.VectorUtil; + + +/** + * 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. + * + */ +public class AABBox implements Cloneable { + private float[] low = new float[3]; + private float[] high = new float[3]; + private float[] center = new float[3]; + + /** Create a Axis Aligned bounding box (AABBox) + * where the low and and high MAX float Values. + */ + public AABBox() { + reset(); + } + + /** 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(float lx, float ly, float lz, + float hx, float hy, 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(float[] low, float[] high) { + setSize(low[0],low[1],low[2], high[0],high[1],high[2]); + } + + /** resets this box to the inverse low/high, allowing the next {@link #resize(float, float, float)} command to hit. */ + public final void reset() { + setLow(Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE); + setHigh(-1*Float.MAX_VALUE,-1*Float.MAX_VALUE,-1*Float.MAX_VALUE); + center[0] = 0f; + center[1] = 0f; + center[2] = 0f; + } + + /** Get the max xyz-coordinates + * @return a float array containing the max xyz coordinates + */ + public final float[] getHigh() { + return high; + } + + private final void setHigh(float hx, float hy, float hz) { + this.high[0] = hx; + this.high[1] = hy; + this.high[2] = hz; + } + + /** Get the min xyz-coordinates + * @return a float array containing the min xyz coordinates + */ + public final float[] getLow() { + return low; + } + + private final void setLow(float lx, float ly, float lz) { + this.low[0] = lx; + this.low[1] = ly; + this.low[2] = lz; + } + + private final void computeCenter() { + center[0] = (high[0] + low[0])/2; + center[1] = (high[1] + low[1])/2; + center[2] = (high[2] + low[2])/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 + */ + public final void setSize(float lx, float ly, float lz, + float hx, float hy, float hz) { + this.low[0] = lx; + this.low[1] = ly; + this.low[2] = lz; + this.high[0] = hx; + this.high[1] = hy; + this.high[2] = hz; + computeCenter(); + } + + /** Resize the AABBox to encapsulate another AABox + * @param newBox AABBox to be encapsulated in + */ + public final void resize(AABBox newBox) { + float[] newLow = newBox.getLow(); + float[] newHigh = newBox.getHigh(); + + /** test low */ + if (newLow[0] < low[0]) + low[0] = newLow[0]; + if (newLow[1] < low[1]) + low[1] = newLow[1]; + if (newLow[2] < low[2]) + low[2] = newLow[2]; + + /** test high */ + if (newHigh[0] > high[0]) + high[0] = newHigh[0]; + if (newHigh[1] > high[1]) + high[1] = newHigh[1]; + if (newHigh[2] > high[2]) + high[2] = newHigh[2]; + + computeCenter(); + } + + /** 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 + */ + public final void resize(float x, float y, float z) { + /** test low */ + if (x < low[0]) + low[0] = x; + if (y < low[1]) + low[1] = y; + if (z < low[2]) + low[2] = z; + + /** test high */ + if (x > high[0]) + high[0] = x; + if (y > high[1]) + high[1] = y; + if (z > high[2]) + high[2] = z; + + computeCenter(); + } + + /** Resize the AABBox to encapsulate the passed + * xyz-coordinates. + * @param xyz xyz-axis coordinate values + * @param offset of the array + */ + public final void resize(float[] xyz, int offset) { + resize(xyz[0+offset], xyz[1+offset], xyz[2+offset]); + } + + /** 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(float x, float y) { + if(x<low[0] || x>high[0]){ + return false; + } + if(y<low[1]|| y>high[1]){ + 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(float x, float y, float z) { + if(x<low[0] || x>high[0]){ + return false; + } + if(y<low[1]|| y>high[1]){ + return false; + } + if(z<low[2] || z>high[2]){ + 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 intersects(float x, float y, float w, 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 + w > x0 && + y + h > y0 && + x < x0 + _w && + y < y0 + _h); + } + + + /** Get the size of the Box 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 VectorUtil.computeLength(low, high); + } + + /**Get the Center of the AABBox + * @return the xyz-coordinates of the center of the AABBox + */ + public final float[] getCenter() { + return center; + } + + /** Scale the AABBox by a constant + * @param size a constant float value + */ + public final void scale(float size) { + float[] diffH = new float[3]; + diffH[0] = high[0] - center[0]; + diffH[1] = high[1] - center[1]; + diffH[2] = high[2] - center[2]; + + diffH = VectorUtil.scale(diffH, size); + + float[] diffL = new float[3]; + diffL[0] = low[0] - center[0]; + diffL[1] = low[1] - center[1]; + diffL[2] = low[2] - center[2]; + + diffL = VectorUtil.scale(diffL, size); + + high = VectorUtil.vectorAdd(center, diffH); + low = VectorUtil.vectorAdd(center, diffL); + } + + public final float getMinX() { + return low[0]; + } + + public final float getMinY() { + return low[1]; + } + + public final float getMinZ() { + return low[2]; + } + + public final float getMaxX() { + return high[0]; + } + + public final float getMaxY() { + return high[1]; + } + + public final float getMaxZ() { + return high[2]; + } + + public final float getWidth(){ + return high[0] - low[0]; + } + + public final float getHeight() { + return high[1] - low[1]; + } + + public final float getDepth() { + return high[2] - low[2]; + } + + @Override + public final AABBox clone() { + return new AABBox(this.low, this.high); + } + + @Override + public final boolean equals(Object obj) { + if( obj == this ) { + return true; + } + if( null == obj || !(obj instanceof AABBox) ) { + return false; + } + final AABBox other = (AABBox) obj; + return VectorUtil.checkEquality(low, other.low) && + VectorUtil.checkEquality(high, other.high) ; + } + + @Override + public final String toString() { + return "[ dim "+getWidth()+" x "+getHeight()+" x "+getDepth()+ + ", box "+low[0]+" / "+low[1]+" / "+low[2]+" .. "+high[0]+" / "+high[1]+" / "+high[2]+ + ", ctr "+center[0]+" / "+center[1]+" / "+center[2]+" ]"; + } +} diff --git a/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java b/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java new file mode 100644 index 000000000..fb311083f --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/math/geom/Frustum.java @@ -0,0 +1,388 @@ +/** + * Copyright 2010 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.common.os.Platform; + +/** + * Providing frustum {@link #getPlanes() planes} derived by different inputs + * ({@link #updateByPMV(float[], int) P*MV}, ..) + * used to {@link #classifySphere(float[], float) classify objects} and to test + * whether they are {@link #isOutside(AABBox) outside}. + * + * <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 { + /** Normalized planes[l, r, b, t, n, f] */ + protected 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 #updateByPMV(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 float[] n = new float[3]; + + /** 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(float x, float y, float z) { + return n[0] * x + n[1] * y + n[2] * z + d; + } + + /** Return distance of plane to given point, see {@link #distanceTo(float, float, float)}. */ + public final float distanceTo(float[] p) { + return n[0] * p[0] + n[1] * p[1] + n[2] * p[2] + d; + } + + @Override + public String toString() { + return "Plane[ [ " + n[0] + ", " + n[1] + ", " + n[2] + " ], " + 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(Plane[] src) { + for (int i = 0; i < 6; ++i) { + final Plane p0 = planes[i]; + final float[] p0_n = p0.n; + final Plane p1 = src[i]; + final float[] p1_n = p1.n; + p0_n[0] = p1_n[0]; + p0_n[1] = p1_n[1]; + p0_n[2] = p1_n[2]; + p0.d = p1.d; + } + } + + /** + * Calculate the frustum planes in world coordinates + * using the passed float[16] as premultiplied P*MV (column major order). + * <p> + * Frustum plane's normals will point to the inside of the viewing frustum, + * as required by this class. + * </p> + */ + public void updateByPMV(float[] pmv, int pmv_off) { + // Left: a = m41 + m11, b = m42 + m12, c = m43 + m13, d = m44 + m14 - [1..4] row-major + // Left: a = m30 + m00, b = m31 + m01, c = m32 + m02, d = m33 + m03 - [0..3] row-major + { + final Plane p = planes[LEFT]; + final float[] p_n = p.n; + p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 0 + 0 * 4 ]; + p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 0 + 1 * 4 ]; + p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 0 + 2 * 4 ]; + p.d = pmv[ pmv_off + 3 + 3 * 4 ] + pmv[ pmv_off + 0 + 3 * 4 ]; + } + + // Right: a = m41 - m11, b = m42 - m12, c = m43 - m13, d = m44 - m14 - [1..4] row-major + // Right: a = m30 - m00, b = m31 - m01, c = m32 - m02, d = m33 - m03 - [0..3] row-major + { + final Plane p = planes[RIGHT]; + final float[] p_n = p.n; + p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 0 + 0 * 4 ]; + p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 0 + 1 * 4 ]; + p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 0 + 2 * 4 ]; + p.d = pmv[ pmv_off + 3 + 3 * 4 ] - pmv[ pmv_off + 0 + 3 * 4 ]; + } + + // Bottom: a = m41 + m21, b = m42 + m22, c = m43 + m23, d = m44 + m24 - [1..4] row-major + // Bottom: a = m30 + m10, b = m31 + m11, c = m32 + m12, d = m33 + m13 - [0..3] row-major + { + final Plane p = planes[BOTTOM]; + final float[] p_n = p.n; + p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 1 + 0 * 4 ]; + p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 1 + 1 * 4 ]; + p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 1 + 2 * 4 ]; + p.d = pmv[ pmv_off + 3 + 3 * 4 ] + pmv[ pmv_off + 1 + 3 * 4 ]; + } + + // Top: a = m41 - m21, b = m42 - m22, c = m43 - m23, d = m44 - m24 - [1..4] row-major + // Top: a = m30 - m10, b = m31 - m11, c = m32 - m12, d = m33 - m13 - [0..3] row-major + { + final Plane p = planes[TOP]; + final float[] p_n = p.n; + p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 1 + 0 * 4 ]; + p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 1 + 1 * 4 ]; + p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 1 + 2 * 4 ]; + p.d = pmv[ pmv_off + 3 + 3 * 4 ] - pmv[ pmv_off + 1 + 3 * 4 ]; + } + + // Near: a = m41 + m31, b = m42 + m32, c = m43 + m33, d = m44 + m34 - [1..4] row-major + // Near: a = m30 + m20, b = m31 + m21, c = m32 + m22, d = m33 + m23 - [0..3] row-major + { + final Plane p = planes[NEAR]; + final float[] p_n = p.n; + p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] + pmv[ pmv_off + 2 + 0 * 4 ]; + p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] + pmv[ pmv_off + 2 + 1 * 4 ]; + p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] + pmv[ pmv_off + 2 + 2 * 4 ]; + p.d = pmv[ pmv_off + 3 + 3 * 4 ] + pmv[ pmv_off + 2 + 3 * 4 ]; + } + + // Far: a = m41 - m31, b = m42 - m32, c = m43 - m33, d = m44 - m34 - [1..4] row-major + // Far: a = m30 - m20, b = m31 - m21, c = m32 + m22, d = m33 + m23 - [0..3] row-major + { + final Plane p = planes[FAR]; + final float[] p_n = p.n; + p_n[0] = pmv[ pmv_off + 3 + 0 * 4 ] - pmv[ pmv_off + 2 + 0 * 4 ]; + p_n[1] = pmv[ pmv_off + 3 + 1 * 4 ] - pmv[ pmv_off + 2 + 1 * 4 ]; + p_n[2] = pmv[ pmv_off + 3 + 2 * 4 ] - pmv[ pmv_off + 2 + 2 * 4 ]; + p.d = pmv[ pmv_off + 3 + 3 * 4 ] - pmv[ pmv_off + 2 + 3 * 4 ]; + } + + // Normalize all planes + for (int i = 0; i < 6; ++i) { + final Plane p = planes[i]; + final float[] p_n = p.n; + final double invl = Math.sqrt(p_n[0] * p_n[0] + p_n[1] * p_n[1] + p_n[2] * p_n[2]); + + p_n[0] /= invl; + p_n[1] /= invl; + p_n[2] /= invl; + p.d /= invl; + } + } + + private static final boolean isOutsideImpl(Plane p, AABBox box) { + final float[] low = box.getLow(); + final float[] high = box.getHigh(); + + if ( p.distanceTo(low[0], low[1], low[2]) > 0.0f || + p.distanceTo(high[0], low[1], low[2]) > 0.0f || + p.distanceTo(low[0], high[1], low[2]) > 0.0f || + p.distanceTo(high[0], high[1], low[2]) > 0.0f || + p.distanceTo(low[0], low[1], high[2]) > 0.0f || + p.distanceTo(high[0], low[1], high[2]) > 0.0f || + p.distanceTo(low[0], high[1], high[2]) > 0.0f || + p.distanceTo(high[0], high[1], high[2]) > 0.0f ) { + 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(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(float[] 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(float[] 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(float[] p, 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(float[] p, float radius) { + return Location.OUTSIDE == classifySphere(p, radius); + } + + public StringBuilder toString(StringBuilder sb) { + if( null == sb ) { + sb = new StringBuilder(); + } + sb.append("Frustum[ Planes[ ").append(Platform.NEWLINE) + .append(" L: ").append(planes[0]).append(", ").append(Platform.NEWLINE) + .append(" R: ").append(planes[1]).append(", ").append(Platform.NEWLINE) + .append(" B: ").append(planes[2]).append(", ").append(Platform.NEWLINE) + .append(" T: ").append(planes[3]).append(", ").append(Platform.NEWLINE) + .append(" N: ").append(planes[4]).append(", ").append(Platform.NEWLINE) + .append(" F: ").append(planes[5]).append("], ").append(Platform.NEWLINE) + .append("]"); + return sb; + } + + @Override + public String toString() { + return toString(null).toString(); + } +} |