onFrustumChange updates the frustum to reflect any changes
+ * made to the planes. The new frustum values are kept in a temporary
+ * location for use when calculating the new frame. The projection
+ * matrix is updated to reflect the current values of the frustum.
+ */
+ public void onFrustumChange(boolean parallelProjection) {
+ if (!parallelProjection) {
+ float nearSquared = frustumNear * frustumNear;
+ float leftSquared = frustumLeft * frustumLeft;
+ float rightSquared = frustumRight * frustumRight;
+ float bottomSquared = frustumBottom * frustumBottom;
+ float topSquared = frustumTop * frustumTop;
+
+ float inverseLength = FastMath.invSqrt(nearSquared + leftSquared);
+ coeffLeft[0] = -frustumNear * inverseLength;
+ coeffLeft[1] = -frustumLeft * inverseLength;
+
+ inverseLength = FastMath.invSqrt(nearSquared + rightSquared);
+ coeffRight[0] = frustumNear * inverseLength;
+ coeffRight[1] = frustumRight * inverseLength;
+
+ inverseLength = FastMath.invSqrt(nearSquared + bottomSquared);
+ coeffBottom[0] = frustumNear * inverseLength;
+ coeffBottom[1] = -frustumBottom * inverseLength;
+
+ inverseLength = FastMath.invSqrt(nearSquared + topSquared);
+ coeffTop[0] = -frustumNear * inverseLength;
+ coeffTop[1] = frustumTop * inverseLength;
+ } else {
+ coeffLeft[0] = 1;
+ coeffLeft[1] = 0;
+
+ coeffRight[0] = -1;
+ coeffRight[1] = 0;
+
+ coeffBottom[0] = 1;
+ coeffBottom[1] = 0;
+
+ coeffTop[0] = -1;
+ coeffTop[1] = 0;
+ }
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/math/Matrixf.java b/jme3-core/src/main/java/com/jme3/math/Matrixf.java
new file mode 100644
index 0000000000..8ab49058a6
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/math/Matrixf.java
@@ -0,0 +1,687 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT OWNER 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.
+ */
+package com.jme3.math;
+
+import com.jme3.export.*;
+import com.jme3.util.BufferUtils;
+import com.jme3.util.TempVars;
+import java.io.IOException;
+import java.nio.FloatBuffer;
+import java.util.logging.Logger;
+
+/**
+ * Matrix4f defines and maintains a 4x4 matrix in row major order.
+ * This matrix is intended for use in a translation and rotational capacity.
+ * It provides convenience methods for creating the matrix from a multitude
+ * of sources.
+ *
+ * Matrices are stored assuming column vectors on the right, with the translation
+ * in the rightmost column. Element numbering is row,column, so m03 is the zeroth
+ * row, third column, which is the "x" translation part. This means that the implicit
+ * storage order is column major. However, the get() and set() functions on float
+ * arrays default to row major order!
+ *
+ * @author Mark Powell
+ * @author Joshua Slack
+ */
+public abstract class Matrixf implements Savable, Cloneable, java.io.Serializable {
+
+ static final long serialVersionUID = 1;
+
+ protected static final Logger logger = Logger.getLogger(Matrix4f.class.getName());
+ protected float[][] matrix;
+ protected int matrixSize;
+
+
+ public static final Matrix4f ZERO = new Matrix4f(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ public static final Matrix4f IDENTITY = new Matrix4f();
+
+ /**
+ * Constructor instantiates a new Matrix that is set to the
+ * identity matrix.
+ *
+ */
+ public Matrixf() {
+ loadIdentity();
+ }
+
+ public abstract void loadIdentity();
+
+ /**
+ * constructs a matrix with the given values.
+ */
+ public Matrixf(float[] values, int n){
+ int c=0;
+ int line=0;
+ int i;
+ float[][] result = new float[n][n];
+ while(cset retrieves the values of this object into
+ * a float array.
+ *
+ * @param matrix
+ * the matrix to set the values into.
+ * @param rowMajor
+ * whether the outgoing data is in row or column major order.
+ */
+ public void get(float[] matrix, boolean rowMajor) {
+ if (matrix.length != matrixSize*matrixSize) {
+ throw new IllegalArgumentException(
+ "Array must be of size "+ matrixSize*matrixSize);
+ }
+
+ if (rowMajor) {
+ int i,j;
+ int current=0;
+ for(i=0;iJmeException is
+ * thrown.
+ *
+ * @param i
+ * the row index.
+ * @param j
+ * the colum index.
+ * @return the value at (i, j).
+ */
+ @SuppressWarnings("fallthrough")
+ public float get(int i, int j) {
+
+ if(iJmeException is
+ * thrown.
+ *
+ * @param i
+ * the row index.
+ * @param j
+ * the colum index.
+ * @param value
+ * the value for (i, j).
+ */
+ @SuppressWarnings("fallthrough")
+ public void set(int i, int j, float value) {
+
+ if(iset sets the values of this matrix from another matrix.
+ *
+ * @param matrix
+ * the matrix to read the value from.
+ */
+ public Matrixf set(Matrixf matrix) {
+ this.matrix = matrix.getMatrix();
+ return this;
+ }
+
+ /**
+ * set sets the values of this matrix from an array of
+ * values assuming that the data is rowMajor order;
+ *
+ * @param matrix
+ * the matrix to set the value to.
+ */
+ public void set(float[] matrix) {
+ set(matrix, true);
+ }
+
+ /**
+ * set sets the values of this matrix from an array of
+ * values;
+ *
+ * @param matrix
+ * the matrix to set the value to.
+ * @param rowMajor
+ * whether the incoming data is in row or column major order.
+ */
+ public void set(float[] matrix, boolean rowMajor) {
+ if (matrix.length != matrixSize*matrixSize) {
+ throw new IllegalArgumentException(
+ "Array must be of size "+matrixSize*matrixSize);
+ }
+
+ if (rowMajor) {
+ set(matrix);
+ } else {
+ int i,j;
+ for(i=0;itoFloatBuffer returns a FloatBuffer object that contains the
+ * matrix data.
+ *
+ * @param columnMajor
+ * if true, this buffer should be filled with column major data,
+ * otherwise it will be filled row major.
+ * @return matrix data as a FloatBuffer. The position is set to 0 for
+ * convenience.
+ */
+ public FloatBuffer toFloatBuffer(boolean columnMajor) {
+ FloatBuffer fb = BufferUtils.createFloatBuffer(matrixSize*matrixSize);
+ fillFloatBuffer(fb, columnMajor);
+ fb.rewind();
+ return fb;
+ }
+
+ /**
+ * fillFloatBuffer fills a FloatBuffer object with
+ * the matrix data.
+ * @param fb the buffer to fill, must be correct size
+ * @return matrix data as a FloatBuffer.
+ */
+ public FloatBuffer fillFloatBuffer(FloatBuffer fb) {
+ return fillFloatBuffer(fb, false);
+ }
+
+ /**
+ * fillFloatBuffer fills a FloatBuffer object with the matrix
+ * data.
+ *
+ * @param fb
+ * the buffer to fill, starting at current position. Must have
+ * room for 16 more floats.
+ * @param columnMajor
+ * if true, this buffer should be filled with column major data,
+ * otherwise it will be filled row major.
+ * @return matrix data as a FloatBuffer. (position is advanced by 16 and any
+ * limit set is not changed).
+ */
+ public FloatBuffer fillFloatBuffer(FloatBuffer fb, boolean columnMajor) {
+
+ TempVars vars = TempVars.get();
+
+
+ fillFloatArray(vars.matrixWrite, columnMajor);
+ fb.put(vars.matrixWrite, 0, matrixSize*matrixSize);
+
+ vars.release();
+
+ return fb;
+ }
+
+ public void fillFloatArray(float[] f, boolean columnMajor) {
+ if (columnMajor) {
+ int i,j;
+ int counter=0;
+ for(i=0;ireadFloatBuffer reads value for this matrix from a FloatBuffer.
+ * @param fb the buffer to read from, must be correct size
+ * @param columnMajor if true, this buffer should be filled with column
+ * major data, otherwise it will be filled row major.
+ * @return this data as a FloatBuffer.
+ */
+ public Matrixf readFloatBuffer(FloatBuffer fb, boolean columnMajor) {
+
+ int i,j;
+
+
+ if (columnMajor) {
+ for(i=0;isetFrustumBottom sets the value of the bottom frustum
- * plane.
- *
- * @param frustumBottom the value of the bottom frustum plane.
- */
- public void setFrustumBottom(float frustumBottom) {
- this.frustumBottom = frustumBottom;
- onFrustumChange();
- }
+
/**
* getFrustumFar gets the value of the far frustum plane.
@@ -489,7 +357,7 @@ public void setFrustumBottom(float frustumBottom) {
* @return the value of the far frustum plane.
*/
public float getFrustumFar() {
- return frustumFar;
+ return frustum.getFar();
}
/**
@@ -498,7 +366,7 @@ public float getFrustumFar() {
* @param frustumFar the value of the far frustum plane.
*/
public void setFrustumFar(float frustumFar) {
- this.frustumFar = frustumFar;
+ frustum.setFar(frustumFar);
onFrustumChange();
}
@@ -508,26 +376,17 @@ public void setFrustumFar(float frustumFar) {
* @return the value of the left frustum plane.
*/
public float getFrustumLeft() {
- return frustumLeft;
- }
-
- /**
- * setFrustumLeft sets the value of the left frustum plane.
- *
- * @param frustumLeft the value of the left frustum plane.
- */
- public void setFrustumLeft(float frustumLeft) {
- this.frustumLeft = frustumLeft;
- onFrustumChange();
+ return frustum.getLeft();
}
+
/**
* getFrustumNear gets the value of the near frustum plane.
*
* @return the value of the near frustum plane.
*/
public float getFrustumNear() {
- return frustumNear;
+ return frustum.getNear();
}
/**
@@ -536,7 +395,7 @@ public float getFrustumNear() {
* @param frustumNear the value of the near frustum plane.
*/
public void setFrustumNear(float frustumNear) {
- this.frustumNear = frustumNear;
+ frustum.setNear(frustumNear);
onFrustumChange();
}
@@ -546,18 +405,10 @@ public void setFrustumNear(float frustumNear) {
* @return frustumRight the value of the right frustum plane.
*/
public float getFrustumRight() {
- return frustumRight;
+ return frustum.getRight();
}
- /**
- * setFrustumRight sets the value of the right frustum plane.
- *
- * @param frustumRight the value of the right frustum plane.
- */
- public void setFrustumRight(float frustumRight) {
- this.frustumRight = frustumRight;
- onFrustumChange();
- }
+
/**
* getFrustumTop gets the value of the top frustum plane.
@@ -565,18 +416,10 @@ public void setFrustumRight(float frustumRight) {
* @return the value of the top frustum plane.
*/
public float getFrustumTop() {
- return frustumTop;
+ return frustum.getTop();
}
- /**
- * setFrustumTop sets the value of the top frustum plane.
- *
- * @param frustumTop the value of the top frustum plane.
- */
- public void setFrustumTop(float frustumTop) {
- this.frustumTop = frustumTop;
- onFrustumChange();
- }
+
/**
* getLocation retrieves the location vector of the camera.
@@ -745,12 +588,7 @@ public void normalize() {
public void setFrustum(float near, float far, float left, float right,
float top, float bottom) {
- frustumNear = near;
- frustumFar = far;
- frustumLeft = left;
- frustumRight = right;
- frustumTop = top;
- frustumBottom = bottom;
+ frustum.setFrustum(top, bottom, left, right, near, far);
onFrustumChange();
}
@@ -773,12 +611,7 @@ public void setFrustumPerspective(float fovY, float aspect, float near,
float h = FastMath.tan(fovY * FastMath.DEG_TO_RAD * .5f) * near;
float w = h * aspect;
- frustumLeft = -w;
- frustumRight = w;
- frustumBottom = -h;
- frustumTop = h;
- frustumNear = near;
- frustumFar = far;
+ frustum.setFrustum(h, -h, -w, w, near, far);
// Camera is no longer parallel projection even if it was before
parallelProjection = false;
@@ -901,18 +734,10 @@ public void setPlaneState(int planeState) {
* @return the left boundary of the viewport
*/
public float getViewPortLeft() {
- return viewPortLeft;
+ return displayViewPort.getLeft();
}
- /**
- * setViewPortLeft sets the left boundary of the viewport
- *
- * @param left the left boundary of the viewport
- */
- public void setViewPortLeft(float left) {
- viewPortLeft = left;
- onViewPortChange();
- }
+
/**
* getViewPortRight gets the right boundary of the viewport
@@ -920,37 +745,20 @@ public void setViewPortLeft(float left) {
* @return the right boundary of the viewport
*/
public float getViewPortRight() {
- return viewPortRight;
- }
-
- /**
- * setViewPortRight sets the right boundary of the viewport
- *
- * @param right the right boundary of the viewport
- */
- public void setViewPortRight(float right) {
- viewPortRight = right;
- onViewPortChange();
+ return displayViewPort.getRight();
}
+
/**
* getViewPortTop gets the top boundary of the viewport
*
* @return the top boundary of the viewport
*/
public float getViewPortTop() {
- return viewPortTop;
+ return displayViewPort.getTop();
}
- /**
- * setViewPortTop sets the top boundary of the viewport
- *
- * @param top the top boundary of the viewport
- */
- public void setViewPortTop(float top) {
- viewPortTop = top;
- onViewPortChange();
- }
+
/**
* getViewPortBottom gets the bottom boundary of the viewport
@@ -958,19 +766,10 @@ public void setViewPortTop(float top) {
* @return the bottom boundary of the viewport
*/
public float getViewPortBottom() {
- return viewPortBottom;
- }
-
- /**
- * setViewPortBottom sets the bottom boundary of the viewport
- *
- * @param bottom the bottom boundary of the viewport
- */
- public void setViewPortBottom(float bottom) {
- viewPortBottom = bottom;
- onViewPortChange();
+ return displayViewPort.getBottom();
}
+
/**
* setViewPort sets the boundaries of the viewport
*
@@ -980,10 +779,7 @@ public void setViewPortBottom(float bottom) {
* @param top the top boundary of the viewport (default: 1)
*/
public void setViewPort(float left, float right, float bottom, float top) {
- this.viewPortLeft = left;
- this.viewPortRight = right;
- this.viewPortBottom = bottom;
- this.viewPortTop = top;
+ displayViewPort.setDisplayViewPort(left, right, bottom, top);
onViewPortChange();
}
@@ -994,7 +790,7 @@ public void setViewPort(float left, float right, float bottom, float top) {
* @return Distance from the far plane to the point.
*/
public float distanceToNearPlane(Vector3f pos) {
- return worldPlane[NEAR_PLANE].pseudoDistance(pos);
+ return worldPlane[frustum.NEAR_PLANE].pseudoDistance(pos);
}
/**
@@ -1024,11 +820,11 @@ public FrustumIntersect contains(BoundingVolume bound) {
int mask;
FrustumIntersect rVal = FrustumIntersect.Inside;
- for (int planeCounter = FRUSTUM_PLANES; planeCounter >= 0; planeCounter--) {
+ for (int planeCounter = frustum.FRUSTUM_PLANES; planeCounter >= 0; planeCounter--) {
if (planeCounter == bound.getCheckPlane()) {
continue; // we have already checked this plane at first iteration
}
- int planeId = (planeCounter == FRUSTUM_PLANES) ? bound.getCheckPlane() : planeCounter;
+ int planeId = (planeCounter == frustum.FRUSTUM_PLANES) ? bound.getCheckPlane() : planeCounter;
// int planeId = planeCounter;
mask = 1 << (planeId);
@@ -1079,7 +875,7 @@ public boolean containsGui(BoundingVolume bound) {
* orientation of the camera.
*/
public Matrix4f getViewMatrix() {
- return viewMatrix;
+ return projectionMatrix.getViewMatrix();
}
/**
@@ -1092,10 +888,10 @@ public Matrix4f getViewMatrix() {
public void setProjectionMatrix(Matrix4f projMatrix) {
if (projMatrix == null) {
overrideProjection = false;
- projectionMatrixOverride.loadIdentity();
+ projectionMatrix.getProjectionMatrixOverride().loadIdentity();
} else {
overrideProjection = true;
- projectionMatrixOverride.set(projMatrix);
+ projectionMatrix.getProjectionMatrixOverride().set(projMatrix);
}
updateViewProjection();
}
@@ -1108,22 +904,17 @@ public void setProjectionMatrix(Matrix4f projMatrix) {
*/
public Matrix4f getProjectionMatrix() {
if (overrideProjection) {
- return projectionMatrixOverride;
+ return projectionMatrix.getProjectionMatrixOverride();
}
- return projectionMatrix;
+ return projectionMatrix.getProjectionMatrix();
}
/**
* Updates the view projection matrix.
*/
public void updateViewProjection() {
- if (overrideProjection) {
- viewProjectionMatrix.set(projectionMatrixOverride).multLocal(viewMatrix);
- } else {
- //viewProjectionMatrix.set(viewMatrix).multLocal(projectionMatrix);
- viewProjectionMatrix.set(projectionMatrix).multLocal(viewMatrix);
- }
+ projectionMatrix.updateViewProjection(overrideProjection);
}
/**
@@ -1132,7 +923,7 @@ public void updateViewProjection() {
* precomputed so as to not compute it every time an object is rendered.
*/
public Matrix4f getViewProjectionMatrix() {
- return viewProjectionMatrix;
+ return projectionMatrix.getviewProjectionMatrix();
}
/**
@@ -1161,69 +952,11 @@ public void onViewPortChange() {
}
private void setGuiBounding() {
- float sx = width * viewPortLeft;
- float ex = width * viewPortRight;
- float sy = height * viewPortBottom;
- float ey = height * viewPortTop;
- float xExtent = Math.max(0f, (ex - sx) / 2f);
- float yExtent = Math.max(0f, (ey - sy) / 2f);
- guiBounding.setCenter(sx + xExtent, sy + yExtent, 0);
- guiBounding.setXExtent(xExtent);
- guiBounding.setYExtent(yExtent);
- guiBounding.setZExtent(Float.MAX_VALUE);
- }
-
- /**
- * onFrustumChange updates the frustum to reflect any changes
- * made to the planes. The new frustum values are kept in a temporary
- * location for use when calculating the new frame. The projection
- * matrix is updated to reflect the current values of the frustum.
- */
- public void onFrustumChange() {
- if (!isParallelProjection()) {
- float nearSquared = frustumNear * frustumNear;
- float leftSquared = frustumLeft * frustumLeft;
- float rightSquared = frustumRight * frustumRight;
- float bottomSquared = frustumBottom * frustumBottom;
- float topSquared = frustumTop * frustumTop;
-
- float inverseLength = FastMath.invSqrt(nearSquared + leftSquared);
- coeffLeft[0] = -frustumNear * inverseLength;
- coeffLeft[1] = -frustumLeft * inverseLength;
-
- inverseLength = FastMath.invSqrt(nearSquared + rightSquared);
- coeffRight[0] = frustumNear * inverseLength;
- coeffRight[1] = frustumRight * inverseLength;
-
- inverseLength = FastMath.invSqrt(nearSquared + bottomSquared);
- coeffBottom[0] = frustumNear * inverseLength;
- coeffBottom[1] = -frustumBottom * inverseLength;
-
- inverseLength = FastMath.invSqrt(nearSquared + topSquared);
- coeffTop[0] = -frustumNear * inverseLength;
- coeffTop[1] = frustumTop * inverseLength;
- } else {
- coeffLeft[0] = 1;
- coeffLeft[1] = 0;
-
- coeffRight[0] = -1;
- coeffRight[1] = 0;
-
- coeffBottom[0] = 1;
- coeffBottom[1] = 0;
-
- coeffTop[0] = -1;
- coeffTop[1] = 0;
- }
-
- projectionMatrix.fromFrustum(frustumNear, frustumFar, frustumLeft, frustumRight, frustumTop, frustumBottom, parallelProjection);
-// projectionMatrix.transposeLocal();
-
- // The frame is effected by the frustum values
- // update it as well
- onFrameChange();
+ displayViewPort.setGuiBounding(width, height, guiBounding);
}
+
+
/**
* onFrameChange updates the view frame of the camera.
*/
@@ -1235,60 +968,61 @@ public void onFrameChange() {
Vector3f up = getUp(vars.vect3);
float dirDotLocation = direction.dot(location);
-
+ float[][] coeff=frustum.getCoeffFirstValue();
+
// left plane
- Vector3f leftPlaneNormal = worldPlane[LEFT_PLANE].getNormal();
- leftPlaneNormal.x = left.x * coeffLeft[0];
- leftPlaneNormal.y = left.y * coeffLeft[0];
- leftPlaneNormal.z = left.z * coeffLeft[0];
- leftPlaneNormal.addLocal(direction.x * coeffLeft[1], direction.y
- * coeffLeft[1], direction.z * coeffLeft[1]);
- worldPlane[LEFT_PLANE].setConstant(location.dot(leftPlaneNormal));
+ Vector3f leftPlaneNormal = worldPlane[frustum.LEFT_PLANE].getNormal();
+ leftPlaneNormal.x = left.x * coeff[0][0];
+ leftPlaneNormal.y = left.y * coeff[0][0];
+ leftPlaneNormal.z = left.z * coeff[0][0];
+ leftPlaneNormal.addLocal(direction.x * coeff[0][1], direction.y
+ * coeff[0][1], direction.z * coeff[0][1]);
+ worldPlane[frustum.LEFT_PLANE].setConstant(location.dot(leftPlaneNormal));
// right plane
- Vector3f rightPlaneNormal = worldPlane[RIGHT_PLANE].getNormal();
- rightPlaneNormal.x = left.x * coeffRight[0];
- rightPlaneNormal.y = left.y * coeffRight[0];
- rightPlaneNormal.z = left.z * coeffRight[0];
- rightPlaneNormal.addLocal(direction.x * coeffRight[1], direction.y
- * coeffRight[1], direction.z * coeffRight[1]);
- worldPlane[RIGHT_PLANE].setConstant(location.dot(rightPlaneNormal));
+ Vector3f rightPlaneNormal = worldPlane[frustum.RIGHT_PLANE].getNormal();
+ rightPlaneNormal.x = left.x * coeff[1][0];
+ rightPlaneNormal.y = left.y * coeff[1][0];
+ rightPlaneNormal.z = left.z * coeff[1][0];
+ rightPlaneNormal.addLocal(direction.x * coeff[1][1], direction.y
+ * coeff[1][1], direction.z * coeff[1][1]);
+ worldPlane[frustum.RIGHT_PLANE].setConstant(location.dot(rightPlaneNormal));
// bottom plane
- Vector3f bottomPlaneNormal = worldPlane[BOTTOM_PLANE].getNormal();
- bottomPlaneNormal.x = up.x * coeffBottom[0];
- bottomPlaneNormal.y = up.y * coeffBottom[0];
- bottomPlaneNormal.z = up.z * coeffBottom[0];
- bottomPlaneNormal.addLocal(direction.x * coeffBottom[1], direction.y
- * coeffBottom[1], direction.z * coeffBottom[1]);
- worldPlane[BOTTOM_PLANE].setConstant(location.dot(bottomPlaneNormal));
+ Vector3f bottomPlaneNormal = worldPlane[frustum.BOTTOM_PLANE].getNormal();
+ bottomPlaneNormal.x = up.x * coeff[2][0];
+ bottomPlaneNormal.y = up.y * coeff[2][0];
+ bottomPlaneNormal.z = up.z * coeff[2][0];
+ bottomPlaneNormal.addLocal(direction.x * coeff[2][1], direction.y
+ * coeff[2][1], direction.z * coeff[2][1]);
+ worldPlane[frustum.BOTTOM_PLANE].setConstant(location.dot(bottomPlaneNormal));
// top plane
- Vector3f topPlaneNormal = worldPlane[TOP_PLANE].getNormal();
- topPlaneNormal.x = up.x * coeffTop[0];
- topPlaneNormal.y = up.y * coeffTop[0];
- topPlaneNormal.z = up.z * coeffTop[0];
- topPlaneNormal.addLocal(direction.x * coeffTop[1], direction.y
- * coeffTop[1], direction.z * coeffTop[1]);
- worldPlane[TOP_PLANE].setConstant(location.dot(topPlaneNormal));
+ Vector3f topPlaneNormal = worldPlane[frustum.TOP_PLANE].getNormal();
+ topPlaneNormal.x = up.x * coeff[3][0];
+ topPlaneNormal.y = up.y * coeff[3][0];
+ topPlaneNormal.z = up.z * coeff[3][0];
+ topPlaneNormal.addLocal(direction.x * coeff[3][1], direction.y
+ * coeff[3][1], direction.z * coeff[3][1]);
+ worldPlane[frustum.TOP_PLANE].setConstant(location.dot(topPlaneNormal));
if (isParallelProjection()) {
- worldPlane[LEFT_PLANE].setConstant(worldPlane[LEFT_PLANE].getConstant() + frustumLeft);
- worldPlane[RIGHT_PLANE].setConstant(worldPlane[RIGHT_PLANE].getConstant() - frustumRight);
- worldPlane[TOP_PLANE].setConstant(worldPlane[TOP_PLANE].getConstant() - frustumTop);
- worldPlane[BOTTOM_PLANE].setConstant(worldPlane[BOTTOM_PLANE].getConstant() + frustumBottom);
+ worldPlane[frustum.LEFT_PLANE].setConstant(worldPlane[frustum.LEFT_PLANE].getConstant() + frustum.getLeft());
+ worldPlane[frustum.RIGHT_PLANE].setConstant(worldPlane[frustum.RIGHT_PLANE].getConstant() - frustum.getRight());
+ worldPlane[frustum.TOP_PLANE].setConstant(worldPlane[frustum.TOP_PLANE].getConstant() - frustum.getTop());
+ worldPlane[frustum.BOTTOM_PLANE].setConstant(worldPlane[frustum.BOTTOM_PLANE].getConstant() + frustum.getBottom());
}
// far plane
- worldPlane[FAR_PLANE].setNormal(left);
- worldPlane[FAR_PLANE].setNormal(-direction.x, -direction.y, -direction.z);
- worldPlane[FAR_PLANE].setConstant(-(dirDotLocation + frustumFar));
+ worldPlane[frustum.FAR_PLANE].setNormal(left);
+ worldPlane[frustum.FAR_PLANE].setNormal(-direction.x, -direction.y, -direction.z);
+ worldPlane[frustum.FAR_PLANE].setConstant(-(dirDotLocation + frustum.getFar()));
// near plane
- worldPlane[NEAR_PLANE].setNormal(direction.x, direction.y, direction.z);
- worldPlane[NEAR_PLANE].setConstant(dirDotLocation + frustumNear);
+ worldPlane[frustum.NEAR_PLANE].setNormal(direction.x, direction.y, direction.z);
+ worldPlane[frustum.NEAR_PLANE].setConstant(dirDotLocation + frustum.getNear());
- viewMatrix.fromFrame(location, direction, up, left);
+ projectionMatrix.getViewMatrix().fromFrame(location, direction, up, left);
vars.release();
@@ -1311,7 +1045,18 @@ public boolean isParallelProjection() {
*/
public void setParallelProjection(final boolean value) {
this.parallelProjection = value;
- onFrustumChange();
+ onFrustumChange();
+ }
+
+
+ public void onFrustumChange(){
+ frustum.onFrustumChange(isParallelProjection());
+ projectionMatrix.getProjectionMatrix().fromFrustum(frustum.getNear(), frustum.getFar(), frustum.getLeft(), frustum.getRight(), frustum.getTop(), frustum.getBottom(), parallelProjection);
+// projectionMatrix.transposeLocal();
+
+ // The frame is effected by the frustum values
+ // update it as well
+ onFrameChange();
}
/**
@@ -1356,12 +1101,12 @@ public Vector3f getWorldCoordinates(Vector2f screenPosition,
store = new Vector3f();
}
- Matrix4f inverseMat = new Matrix4f(viewProjectionMatrix);
+ Matrix4f inverseMat = new Matrix4f(projectionMatrix.getviewProjectionMatrix());
inverseMat.invertLocal();
store.set(
- (screenPosition.x / getWidth() - viewPortLeft) / (viewPortRight - viewPortLeft) * 2 - 1,
- (screenPosition.y / getHeight() - viewPortBottom) / (viewPortTop - viewPortBottom) * 2 - 1,
+ (screenPosition.x / getWidth() - displayViewPort.getLeft()) / (displayViewPort.getRight() - displayViewPort.getLeft()) * 2 - 1,
+ (screenPosition.y / getHeight() - displayViewPort.getBottom()) / (displayViewPort.getTop() - displayViewPort.getBottom()) * 2 - 1,
projectionZPos * 2 - 1);
float w = inverseMat.multProj(store, store);
@@ -1399,11 +1144,11 @@ public Vector3f getScreenCoordinates(Vector3f worldPosition, Vector3f store) {
// store.z = ( tmp_quat.getZ() + 1 ) / 2;
// vars.release();
- float w = viewProjectionMatrix.multProj(worldPosition, store);
+ float w = projectionMatrix.getviewProjectionMatrix().multProj(worldPosition, store);
store.divideLocal(w);
- store.x = ((store.x + 1f) * (viewPortRight - viewPortLeft) / 2f + viewPortLeft) * getWidth();
- store.y = ((store.y + 1f) * (viewPortTop - viewPortBottom) / 2f + viewPortBottom) * getHeight();
+ store.x = ((store.x + 1f) * displayViewPort.storeXValue()) * getWidth();
+ store.y = ((store.y + 1f) * displayViewPort.storeYValue())* getHeight();
store.z = (store.z + 1f) / 2f;
return store;
@@ -1427,27 +1172,31 @@ public int getHeight() {
public String toString() {
return "Camera[location=" + location + "\n, direction=" + getDirection() + "\n"
+ "res=" + width + "x" + height + ", parallel=" + parallelProjection + "\n"
- + "near=" + frustumNear + ", far=" + frustumFar + "]";
+ + "near=" + frustum.getNear() + ", far=" + frustum.getFar() + "]";
}
public void write(JmeExporter e) throws IOException {
OutputCapsule capsule = e.getCapsule(this);
capsule.write(location, "location", Vector3f.ZERO);
capsule.write(rotation, "rotation", Quaternion.DIRECTION_Z);
- capsule.write(frustumNear, "frustumNear", 1);
- capsule.write(frustumFar, "frustumFar", 2);
- capsule.write(frustumLeft, "frustumLeft", -0.5f);
- capsule.write(frustumRight, "frustumRight", 0.5f);
- capsule.write(frustumTop, "frustumTop", 0.5f);
- capsule.write(frustumBottom, "frustumBottom", -0.5f);
- capsule.write(coeffLeft, "coeffLeft", new float[2]);
- capsule.write(coeffRight, "coeffRight", new float[2]);
- capsule.write(coeffBottom, "coeffBottom", new float[2]);
- capsule.write(coeffTop, "coeffTop", new float[2]);
- capsule.write(viewPortLeft, "viewPortLeft", 0);
- capsule.write(viewPortRight, "viewPortRight", 1);
- capsule.write(viewPortTop, "viewPortTop", 1);
- capsule.write(viewPortBottom, "viewPortBottom", 0);
+ capsule.write(frustum.getNear(), "frustumNear", 1);
+ capsule.write(frustum.getFar(), "frustumFar", 2);
+ capsule.write(frustum.getNear(), "frustumLeft", -0.5f);
+ capsule.write(frustum.getRight(), "frustumRight", 0.5f);
+ capsule.write(frustum.getTop(), "frustumTop", 0.5f);
+ capsule.write(frustum.getBottom(), "frustumBottom", -0.5f);
+
+ float[][] coeff = frustum.getCoeffFirstValue();
+ capsule.write(coeff[0], "coeffLeft", new float[2]);
+ capsule.write(coeff[1], "coeffRight", new float[2]);
+ capsule.write(coeff[2], "coeffBottom", new float[2]);
+ capsule.write(coeff[3], "coeffTop", new float[2]);
+
+ float[] viewPorts = displayViewPort.getViewPorts();
+ capsule.write(viewPorts[0], "viewPortLeft", 0);
+ capsule.write(viewPorts[1], "viewPortRight", 1);
+ capsule.write(viewPorts[2], "viewPortTop", 1);
+ capsule.write(viewPorts[3], "viewPortBottom", 0);
capsule.write(width, "width", 0);
capsule.write(height, "height", 0);
capsule.write(name, "name", null);
@@ -1457,20 +1206,27 @@ public void read(JmeImporter e) throws IOException {
InputCapsule capsule = e.getCapsule(this);
location = (Vector3f) capsule.readSavable("location", Vector3f.ZERO.clone());
rotation = (Quaternion) capsule.readSavable("rotation", Quaternion.DIRECTION_Z.clone());
- frustumNear = capsule.readFloat("frustumNear", 1);
- frustumFar = capsule.readFloat("frustumFar", 2);
- frustumLeft = capsule.readFloat("frustumLeft", -0.5f);
- frustumRight = capsule.readFloat("frustumRight", 0.5f);
- frustumTop = capsule.readFloat("frustumTop", 0.5f);
- frustumBottom = capsule.readFloat("frustumBottom", -0.5f);
- coeffLeft = capsule.readFloatArray("coeffLeft", new float[2]);
- coeffRight = capsule.readFloatArray("coeffRight", new float[2]);
- coeffBottom = capsule.readFloatArray("coeffBottom", new float[2]);
- coeffTop = capsule.readFloatArray("coeffTop", new float[2]);
- viewPortLeft = capsule.readFloat("viewPortLeft", 0);
- viewPortRight = capsule.readFloat("viewPortRight", 1);
- viewPortTop = capsule.readFloat("viewPortTop", 1);
- viewPortBottom = capsule.readFloat("viewPortBottom", 0);
+
+ frustum.setFrustum(
+ capsule.readFloat("frustumTop", 0.5f),
+ capsule.readFloat("frustumBottom", -0.5f),
+ capsule.readFloat("frustumLeft", -0.5f),
+ capsule.readFloat("frustumRight", 0.5f),
+ capsule.readFloat("frustumNear", 1),
+ capsule.readFloat("frustumFar", 2));
+
+ frustum.setTemporaryVariables(
+ capsule.readFloatArray("coeffLeft", new float[2]),
+ capsule.readFloatArray("coeffRight", new float[2]),
+ capsule.readFloatArray("coeffBottom", new float[2]),
+ capsule.readFloatArray("coeffTop", new float[2]));
+
+ displayViewPort.setDisplayViewPort(
+ capsule.readFloat("viewPortLeft", 0),
+ capsule.readFloat("viewPortRight", 1),
+ capsule.readFloat("viewPortTop", 1),
+ capsule.readFloat("viewPortBottom", 0));
+
width = capsule.readInt("width", 1);
height = capsule.readInt("height", 1);
name = capsule.readString("name", null);
diff --git a/jme3-core/src/main/java/com/jme3/renderer/DisplayViewPort.java b/jme3-core/src/main/java/com/jme3/renderer/DisplayViewPort.java
new file mode 100644
index 0000000000..f6c24c4f5b
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/DisplayViewPort.java
@@ -0,0 +1,112 @@
+package com.jme3.renderer;
+
+import com.jme3.bounding.BoundingBox;
+
+public class DisplayViewPort {
+
+
+ //view port coordinates
+ /**
+ * Percent value on display where horizontal viewing starts for this camera.
+ * Default is 0.
+ */
+ private float viewPortLeft;
+ /**
+ * Percent value on display where horizontal viewing ends for this camera.
+ * Default is 1.
+ */
+ private float viewPortRight;
+ /**
+ * Percent value on display where vertical viewing ends for this camera.
+ * Default is 1.
+ */
+ private float viewPortTop;
+ /**
+ * Percent value on display where vertical viewing begins for this camera.
+ * Default is 0.
+ */
+ private float viewPortBottom;
+
+ public float getLeft(){
+ return viewPortLeft;
+ }
+
+ public float getRight(){
+ return viewPortRight;
+ }
+
+ public float getTop(){
+ return viewPortTop;
+ }
+
+ public float getBottom(){
+ return viewPortBottom;
+ }
+
+
+ public void setLeft(float value){
+ viewPortLeft=value;
+ }
+
+ public void setRight(float value){
+ viewPortRight=value;
+ }
+
+ public void setTop(float value){
+ viewPortTop =value;
+ }
+
+ public void setBottom(float value){
+ viewPortBottom=value;
+ }
+
+ public DisplayViewPort(float viewPortLeft,float viewPortRight,float viewPortTop, float viewPortBottom){
+ this.viewPortLeft = viewPortLeft;
+ this.viewPortRight = viewPortRight;
+ this.viewPortTop = viewPortTop;
+ this.viewPortBottom = viewPortBottom;
+ }
+
+ public void setDisplayViewPort(float viewPortLeft,float viewPortRight,float viewPortTop, float viewPortBottom){
+ this.viewPortLeft = viewPortLeft;
+ this.viewPortRight = viewPortRight;
+ this.viewPortTop = viewPortTop;
+ this.viewPortBottom = viewPortBottom;
+ }
+
+ public void copySettingFrom(DisplayViewPort cloneModel){
+ this.viewPortLeft = cloneModel.viewPortLeft;
+ this.viewPortRight = cloneModel.viewPortRight;
+ this.viewPortTop = cloneModel.viewPortTop;
+ this.viewPortBottom = cloneModel.viewPortBottom;
+ }
+
+ public void setGuiBounding(int width, int height, BoundingBox guiBounding){
+ float sx = width * viewPortLeft;
+ float ex = width * viewPortRight;
+ float sy = height * viewPortBottom;
+ float ey = height * viewPortTop;
+ float xExtent = Math.max(0f, (ex - sx) / 2f);
+ float yExtent = Math.max(0f, (ey - sy) / 2f);
+ guiBounding.setCenter(sx + xExtent, sy + yExtent, 0);
+ guiBounding.setXExtent(xExtent);
+ guiBounding.setYExtent(yExtent);
+ guiBounding.setZExtent(Float.MAX_VALUE);
+ }
+
+ public float storeXValue(){
+ return (viewPortRight - viewPortLeft) / 2f + viewPortLeft;
+ }
+
+ public float storeYValue(){
+ return (viewPortTop - viewPortBottom) / 2f + viewPortBottom;
+ }
+
+ public float[] getViewPorts(){
+ float[] result = {viewPortLeft,viewPortRight,viewPortTop,viewPortBottom};
+ return result;
+ }
+
+
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/ProjectionMatrix.java b/jme3-core/src/main/java/com/jme3/renderer/ProjectionMatrix.java
new file mode 100644
index 0000000000..cf27637c5c
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/ProjectionMatrix.java
@@ -0,0 +1,63 @@
+package com.jme3.renderer;
+
+import com.jme3.math.Matrix4f;
+
+public class ProjectionMatrix {
+
+ protected Matrix4f projectionMatrixOverride = new Matrix4f();
+ protected Matrix4f viewMatrix = new Matrix4f();
+ protected Matrix4f projectionMatrix = new Matrix4f();
+ protected Matrix4f viewProjectionMatrix = new Matrix4f();
+
+ public Matrix4f getviewProjectionMatrix(){
+ return viewProjectionMatrix;
+ }
+
+ public void cloneFrom(ProjectionMatrix original){
+ if (projectionMatrixOverride != null) {
+ this.projectionMatrixOverride = (Matrix4f) original.projectionMatrixOverride.clone();
+ }
+ this.viewMatrix = (Matrix4f) original.viewMatrix.clone();
+ this.projectionMatrix = (Matrix4f) original.projectionMatrix.clone();
+ this.viewProjectionMatrix = (Matrix4f) original.viewProjectionMatrix.clone();
+
+ }
+
+
+ public void copySettingsFrom(ProjectionMatrix theProjectionMatrix) {
+ this.projectionMatrixOverride.set(theProjectionMatrix.projectionMatrixOverride);
+
+ this.viewMatrix.set(theProjectionMatrix.viewMatrix);
+ this.projectionMatrix.set(theProjectionMatrix.projectionMatrix);
+ this.viewProjectionMatrix.set(theProjectionMatrix.viewProjectionMatrix);
+
+ }
+
+ public Matrix4f getViewMatrix(){
+ return viewMatrix;
+ }
+
+ public Matrix4f getSetMatrix(){
+ return (Matrix4f) projectionMatrixOverride.set(projectionMatrix);
+ }
+
+ public Matrix4f getProjectionMatrixOverride(){
+ return projectionMatrixOverride;
+ }
+
+ public Matrix4f getProjectionMatrix(){
+ return projectionMatrix;
+ }
+
+ public void updateViewProjection(boolean overrideProjection) {
+ if (overrideProjection) {
+ viewProjectionMatrix.set(projectionMatrixOverride).multLocal(viewMatrix);
+ } else {
+ //viewProjectionMatrix.set(viewMatrix).multLocal(projectionMatrix);
+ viewProjectionMatrix.set(projectionMatrix).multLocal(viewMatrix);
+ }
+
+ }
+
+
+}
diff --git a/jme3-core/src/test/java/com/jme3/math/Matrix4fTest.java b/jme3-core/src/test/java/com/jme3/math/Matrix4fTest.java
new file mode 100644
index 0000000000..2d9c86b04c
--- /dev/null
+++ b/jme3-core/src/test/java/com/jme3/math/Matrix4fTest.java
@@ -0,0 +1,399 @@
+package com.jme3.math;
+
+import static org.junit.Assert.*;
+
+import java.nio.FloatBuffer;
+
+import org.junit.Test;
+
+import com.jme3.bounding.BoundingBox;
+import com.jme3.bounding.BoundingSphere;
+import com.jme3.bounding.BoundingVolume;
+import com.jme3.bounding.BoundingVolume.Type;
+import com.jme3.collision.Collidable;
+import com.jme3.collision.CollisionResults;
+import com.jme3.collision.UnsupportedCollisionException;
+import com.jme3.math.FastMath;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Plane;
+import com.jme3.math.Plane.Side;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Ray;
+import com.jme3.math.Transform;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.util.BufferUtils;
+import com.jme3.util.TempVars;
+import com.sun.accessibility.internal.resources.accessibility;
+import com.sun.javafx.geom.Vec3f;
+
+import javafx.beans.property.FloatProperty;
+import sun.net.www.content.audio.x_aiff;
+
+public class Matrix4fTest {
+ float[] numbers = {-1.0f,0.0f,-0.0f,0.0f,0.0f,1.0f,-0.0f,0.0f,0.0f,-0.0f,-1.0f,0.0f,-0.0f,-0.0f,0.0f,1.0f};
+ Matrix4f matrix = new Matrix4f(numbers);
+
+ @Test
+ public void testCopy()
+ {
+ float[] numbers2 = {3.0f,0.0f,-0.0f,0.0f,0.0f,1.0f,-0.0f,0.0f,0.0f,-0.0f,-1.0f,0.0f,-0.0f,-0.0f,0.0f,1.0f};
+ Matrix4f newMatrix = new Matrix4f(numbers2);
+ newMatrix.copy(matrix);
+ assertTrue(matrix.equals(newMatrix));
+ }
+
+ @Test
+ public void testFromFrame()
+ {
+ Vector3f location = new Vector3f(1.0f, 2.0f, 3.0f);
+ Vector3f direction = new Vector3f(2.0f, 3.0f, 4.0f);
+ Vector3f up = new Vector3f(1.0f, 2.0f, 4.0f);
+ Vector3f left = new Vector3f(5.0f, 0.0f, 1.0f);
+ matrix.fromFrame(location, direction, up, left);
+ TempVars vars = TempVars.get();
+ assertTrue(vars.vect1.equals(new Vector3f(2.0f,3.0f,4.0f)));
+ assertTrue(vars.vect2.equals(new Vector3f(4.0f,-4.0f,1.0f)));
+ assertTrue(vars.vect3.equals(new Vector3f(-19.0f,-14.0f,20.0f)));
+ //System.out.println(vars.vect3);
+ }
+
+ @Test
+ public void testGetMatrix()
+ {
+ float[] matrixFloat = {-10.0f,0.0f,-0.0f,0.0f,0.0f,1.0f,-0.0f,0.0f,0.0f,-0.0f,-1.0f,0.0f,-0.0f,-0.0f,0.0f,1.0f};
+ matrix.get(matrixFloat);
+ for (int i=0; iA, A, A, B, B, B, C, C, C. + * + * @param materials The pre-sorted list of materials to check sorting for. + */ + private void testSort(Material ... materials) { + GeometryList gl = new GeometryList(comparator); + for (int g = 0; g < 5; g++) { + for (int i = materials.length - 1; i >= 0; i--) { + Geometry geom = new Geometry("geom", mesh); + Material clonedMaterial = materials[i].clone(); + + if (materials[i].getActiveTechnique() != null) { + String techniqueName = materials[i].getActiveTechnique().getDef().getName(); + clonedMaterial.selectTechnique(techniqueName, renderManager); + } else { + clonedMaterial.selectTechnique("Default", renderManager); + } + + geom.setMaterial(clonedMaterial); + gl.add(geom); + } + } + gl.sort(); + + for (int i = 0; i < gl.size(); i++) { + Material mat = gl.get(i).getMaterial(); + String sortId = Integer.toHexString(mat.getSortId()).toUpperCase(); + System.out.print(sortId + "\t"); + System.out.println(mat); + } + + Set