package rajawali.bounds; import java.nio.FloatBuffer; import rajawali.BaseObject3D; import rajawali.Camera; import rajawali.Geometry3D; import rajawali.materials.SimpleMaterial; import rajawali.math.Number3D; import rajawali.primitives.Cube; import android.opengl.GLES20; import android.opengl.Matrix; public class BoundingBox implements IBoundingVolume { protected Geometry3D mGeometry; protected Number3D mMin, mTransformedMin; protected Number3D mMax, mTransformedMax; protected Number3D mTmpMin, mTmpMax; protected Number3D[] mPoints; protected Number3D[] mTmp; protected int mI; protected Cube mVisualBox; protected float[] mTmpMatrix = new float[16]; public void copyPoints(Number3D[] pts){ Number3D min = mTransformedMin; Number3D max = mTransformedMax; // -- bottom plane // -- -x, -y, -z pts[0].setAll(min.x, min.y, min.z); // -- -x, -y, z pts[1].setAll(min.x, min.y, max.z); // -- x, -y, z pts[2].setAll(max.x, min.y, max.z); // -- x, -y, -z pts[3].setAll(max.x, min.y, min.z); // -- top plane // -- -x, y, -z pts[4].setAll(min.x, max.y, min.z); // -- -x, y, z pts[5].setAll(min.x, max.y, max.z); // -- x, y, z pts[6].setAll(max.x, max.y, max.z); // -- x, y, -z pts[7].setAll(max.x, max.y, min.z); } public BoundingBox() { super(); mTransformedMin = new Number3D(); mTransformedMax = new Number3D(); mTmpMin = new Number3D(); mTmpMax = new Number3D(); mPoints = new Number3D[8]; mTmp = new Number3D[8]; mMin = new Number3D(); mMax = new Number3D(); for(int i=0; i<8; ++i) { mPoints[i] = new Number3D(); mTmp[i] = new Number3D(); } } public void drawBoundingVolume(Camera camera, float[] projMatrix, float[] vMatrix, float[] mMatrix) { if(mVisualBox == null) { mVisualBox = new Cube(1); mVisualBox.setMaterial(new SimpleMaterial()); mVisualBox.getMaterial().setUseColor(true); mVisualBox.setColor(0xffffff00); mVisualBox.setDrawingMode(GLES20.GL_LINE_LOOP); } mVisualBox.setScale( Math.abs(mTransformedMax.x - mTransformedMin.x), Math.abs(mTransformedMax.y - mTransformedMin.y), Math.abs(mTransformedMax.z - mTransformedMin.z) ); Matrix.setIdentityM(mTmpMatrix, 0); mVisualBox.setPosition( mTransformedMin.x + (mTransformedMax.x - mTransformedMin.x) * .5f, mTransformedMin.y + (mTransformedMax.y - mTransformedMin.y) * .5f, mTransformedMin.z + (mTransformedMax.z - mTransformedMin.z) * .5f ); mVisualBox.render(camera, projMatrix, vMatrix, mTmpMatrix, null); } public BoundingBox(Geometry3D geometry) { this(); mGeometry = geometry; calculateBounds(mGeometry); } public BaseObject3D getVisual() { return mVisualBox; } public void calculateBounds(Geometry3D geometry) { FloatBuffer vertices = geometry.getVertices(); vertices.rewind(); mMin = new Number3D(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE); mMax = new Number3D(-Float.MAX_VALUE, -Float.MAX_VALUE, -Float.MAX_VALUE); Number3D vertex = new Number3D(); while(vertices.hasRemaining()) { vertex.x = vertices.get(); vertex.y = vertices.get(); vertex.z = vertices.get(); if(vertex.x < mMin.x) mMin.x = vertex.x; if(vertex.y < mMin.y) mMin.y = vertex.y; if(vertex.z < mMin.z) mMin.z = vertex.z; if(vertex.x > mMax.x) mMax.x = vertex.x; if(vertex.y > mMax.y) mMax.y = vertex.y; if(vertex.z > mMax.z) mMax.z = vertex.z; } // -- bottom plane // -- -x, -y, -z mPoints[0].setAll(mMin.x, mMin.y, mMin.z); // -- -x, -y, z mPoints[1].setAll(mMin.x, mMin.y, mMax.z); // -- x, -y, z mPoints[2].setAll(mMax.x, mMin.y, mMax.z); // -- x, -y, -z mPoints[3].setAll(mMax.x, mMin.y, mMin.z); // -- top plane // -- -x, y, -z mPoints[4].setAll(mMin.x, mMax.y, mMin.z); // -- -x, y, z mPoints[5].setAll(mMin.x, mMax.y, mMax.z); // -- x, y, z mPoints[6].setAll(mMax.x, mMax.y, mMax.z); // -- x, y, -z mPoints[7].setAll(mMax.x, mMax.y, mMin.z); } public void transform(final float[] matrix) { mTransformedMin.setAll(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE); mTransformedMax.setAll(-Float.MAX_VALUE, -Float.MAX_VALUE, -Float.MAX_VALUE); for(mI=0; mI<8; ++mI) { Number3D o = mPoints[mI]; Number3D d = mTmp[mI]; d.setAllFrom(o); d.multiply(matrix); if(d.x < mTransformedMin.x) mTransformedMin.x = d.x; if(d.y < mTransformedMin.y) mTransformedMin.y = d.y; if(d.z < mTransformedMin.z) mTransformedMin.z = d.z; if(d.x > mTransformedMax.x) mTransformedMax.x = d.x; if(d.y > mTransformedMax.y) mTransformedMax.y = d.y; if(d.z > mTransformedMax.z) mTransformedMax.z = d.z; } } public Number3D getMin() { return mMin; } public void setMin(Number3D min) { mMin.setAllFrom(min); } public Number3D getMax() { return mMax; } public void setMax(Number3D max) { mMax.setAllFrom(max); } public Number3D getTransformedMin() { return mTransformedMin; } public Number3D getTransformedMax() { return mTransformedMax; } public boolean intersectsWith(IBoundingVolume boundingVolume) { if(!(boundingVolume instanceof BoundingBox)) return false; BoundingBox boundingBox = (BoundingBox)boundingVolume; Number3D otherMin = boundingBox.getTransformedMin(); Number3D otherMax = boundingBox.getTransformedMax(); Number3D min = mTransformedMin; Number3D max = mTransformedMax; return (min.x < otherMax.x) && (max.x > otherMin.x) && (min.y < otherMax.y) && (max.y > otherMin.y) && (min.z < otherMax.z) && (max.z > otherMin.z); } public String toString() { return "BoundingBox min: " + mTransformedMin + " max: " + mTransformedMax; } }