lwjgl/src/java/org/lwjgl/Math.java

1105 lines
34 KiB
Java

/*
* Copyright (c) 2002 Lighweight Java Game Library Project
* 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 'Light Weight Java Game Library' 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 org.lwjgl;
/**
* $Id$
*
* A floating point math library, with vector processing capabilities.
* This class differs significantly from its java.lang.Math counterpart
* in that it a) makes no claims about strict accuracy and b) uses degrees
* rather than radians for its functions which are more friendly to use.
*
* @author cix_foo <cix_foo@users.sourceforge.net>
* @version $Revision$
*/
public final class Math {
static {
System.loadLibrary(Sys.getLibraryName());
}
/** Floating point version of pi */
public static final float PI = (float) java.lang.Math.PI;
/*
* Unary matrix operations
*/
private static abstract class UnaryMatrixOperation {
private final int enum;
private final String name;
UnaryMatrixOperation(int enum, String name) {
this.enum = enum;
this.name = name;
}
public String toString() {
return name;
}
abstract MatrixOpClassification classify();
}
/**
* A matrix operation is unsafe if the source and destination overlap,
* and either the strides are not equal, or destination > source, which
* would give an undefined result
*/
private static final MatrixOpClassification MATRIXOP_UNSAFE = new MatrixOpClassification() {
protected MatrixOpClassification unsafe() { return this; }
protected MatrixOpClassification safe() { return this; }
protected MatrixOpClassification direct() { return this; }
boolean isSafe() { return false; }
void execute(
int leftSourceAddress,
int leftSourceStride,
int leftElements,
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceAddress,
int rightSourceStride,
int rightElements,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
int destAddress,
int destStride,
boolean transposeDest)
{
throw new IllegalArgumentException("Unsafe matrix operation.");
}
void execute(
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest)
{
throw new IllegalArgumentException("Unsafe matrix operation.");
}
};
/** Straight copy */
private static final class MatrixOpCopy extends UnaryMatrixOperation {
MatrixOpCopy() {
super(0, "copy");
}
MatrixOpClassification classify() {
return MATRIXOP_NONE;
}
/**
* Unclassified (initial state) matrix operation.
*/
private final MatrixOpClassification MATRIXOP_NONE = new MatrixOpClassification() {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return false; }
};
/**
* A matrix operation is direct if the source and destination addresses
* are the same, and the strides are the same.
*/
private final class MatrixOpDirect extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return this; }
protected MatrixOpClassification direct() { return this; }
boolean isSafe() { return false; }
native void execute(
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpDirect MATRIXOP_DIRECT = new MatrixOpDirect();
/**
* A matrix operation is safe if the source and destination do not
* overlap in any way
*/
private final class MatrixOpSafe extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return true; }
native void execute(
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpSafe MATRIXOP_SAFE = new MatrixOpSafe();
};
public static final MatrixOpCopy MATRIXOP_COPY = new MatrixOpCopy();
/** Negate the vector */
private static final class MatrixOpNegate extends UnaryMatrixOperation {
MatrixOpNegate() {
super(1, "negate");
}
MatrixOpClassification classify() {
return MATRIXOP_NONE;
}
/**
* Unclassified (initial state) matrix operation.
*/
private final MatrixOpClassification MATRIXOP_NONE = new MatrixOpClassification() {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return false; }
};
/**
* A matrix operation is direct if the source and destination addresses
* are the same, and the strides are the same.
*/
private final class MatrixOpDirect extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return this; }
protected MatrixOpClassification direct() { return this; }
boolean isSafe() { return false; }
native void execute(
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpDirect MATRIXOP_DIRECT = new MatrixOpDirect();
/**
* A matrix operation is safe if the source and destination do not
* overlap in any way
*/
private final class MatrixOpSafe extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return true; }
native void execute(
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpSafe MATRIXOP_SAFE = new MatrixOpSafe();
};
public static final MatrixOpNegate MATRIXOP_NEGATE = new MatrixOpNegate();
/** Normalise the vector (set to length 1) */
private static final class MatrixOpNormalise extends UnaryMatrixOperation {
MatrixOpNormalise() {
super(2, "normalise");
}
MatrixOpClassification classify() {
return MATRIXOP_NONE;
}
/**
* Unclassified (initial state) matrix operation.
*/
private final MatrixOpClassification MATRIXOP_NONE = new MatrixOpClassification() {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return true; }
};
/**
* A matrix operation is direct if the source and destination addresses
* are the same, and the strides are the same.
*/
private final class MatrixOpDirect extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return this; }
protected MatrixOpClassification direct() { return this; }
boolean isSafe() { return false; }
native void execute(
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpDirect MATRIXOP_DIRECT = new MatrixOpDirect();
/**
* A matrix operation is safe if the source and destination do not
* overlap in any way
*/
private final class MatrixOpSafe extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return true; }
native void execute(
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpSafe MATRIXOP_SAFE = new MatrixOpSafe();
};
public static final MatrixOpNormalise MATRIXOP_NORMALISE = new MatrixOpNormalise();
/** Compute the inverse matrix */
private static final class MatrixOpInvert extends UnaryMatrixOperation {
MatrixOpInvert() {
super(3, "invert");
}
MatrixOpClassification classify() {
return MATRIXOP_NONE;
}
/**
* Unclassified (initial state) matrix operation.
*/
private final MatrixOpClassification MATRIXOP_NONE = new MatrixOpClassification() {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return false; }
};
/**
* A matrix operation is direct if the source and destination addresses
* are the same, and the strides are the same.
*/
private final class MatrixOpDirect extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return this; }
protected MatrixOpClassification direct() { return this; }
boolean isSafe() { return false; }
native void execute(
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpDirect MATRIXOP_DIRECT = new MatrixOpDirect();
/**
* A matrix operation is safe if the source and destination do not
* overlap in any way
*/
private final class MatrixOpSafe extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return true; }
native void execute(
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpSafe MATRIXOP_SAFE = new MatrixOpSafe();
};
public static final MatrixOpInvert MATRIXOP_INVERT = new MatrixOpInvert();
/*
* Binary matrix operations
*/
private static abstract class BinaryMatrixOperation {
private final int enum;
private final String name;
BinaryMatrixOperation(int enum, String name) {
this.enum = enum;
this.name = name;
}
public String toString() {
return name;
}
/**
* Check the compatibility of a binary matrix operation.
* @return the miniumum stride, in bytes
* @throws IllegalArgumentException if the source and destinations are not
* compatible
*/
abstract int checkCompatibility(
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
boolean transposeDest);
abstract MatrixOpClassification classify();
}
/** Multiply left source by right source */
private static final class MatrixOpMultiply extends BinaryMatrixOperation {
MatrixOpMultiply() {
super(0, "multiply");
}
int checkCompatibility(
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
boolean transposeDest)
{
// Left matrix width must be the same as right matrix height.
int leftWidth = transposeLeftSource ? leftSourceHeight : leftSourceWidth;
int rightHeight = transposeRightSource ? rightSourceWidth : rightSourceHeight;
if (leftWidth != rightHeight)
throw new IllegalArgumentException("Left and right matrices are not compatible.");
int leftHeight = transposeLeftSource ? leftSourceWidth : leftSourceHeight;
int rightWidth = transposeRightSource ? rightSourceHeight : rightSourceWidth;
return (rightWidth * leftHeight) << 2;
}
MatrixOpClassification classify() {
return MATRIXOP_NONE;
}
/**
* Unclassified (initial state) matrix operation.
*/
private final MatrixOpClassification MATRIXOP_NONE = new MatrixOpClassification() {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return false; }
};
/**
* A matrix operation is direct if the source and destination addresses
* are the same, and the strides are the same.
*/
private final class MatrixOpDirect extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return this; }
protected MatrixOpClassification direct() { return this; }
boolean isSafe() { return false; }
native void execute(
int leftSourceAddress,
int leftSourceStride,
int leftElements,
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceAddress,
int rightSourceStride,
int rightElements,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpDirect MATRIXOP_DIRECT = new MatrixOpDirect();
/**
* A matrix operation is safe if the source and destination do not
* overlap in any way
*/
private final class MatrixOpSafe extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return true; }
native void execute(
int leftSourceAddress,
int leftSourceStride,
int leftElements,
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceAddress,
int rightSourceStride,
int rightElements,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpSafe MATRIXOP_SAFE = new MatrixOpSafe();
};
public static final MatrixOpMultiply MATRIXOP_MULTIPLY = new MatrixOpMultiply();
/** Add right source to left source */
private static final class MatrixOpAdd extends BinaryMatrixOperation {
MatrixOpAdd() {
super(1, "add");
}
int checkCompatibility(
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
boolean transposeDest)
{
if (transposeLeftSource == transposeRightSource) {
// Left and right must be the same size
if (leftSourceWidth != rightSourceWidth || leftSourceHeight != rightSourceHeight)
throw new IllegalArgumentException("Left and right matrices are not the same size.");
} else {
// Left and right must be the same size but one of them is transposed
if (leftSourceWidth != rightSourceHeight || leftSourceHeight != rightSourceWidth)
throw new IllegalArgumentException("Left and right matrices are not the same size.");
}
return (leftSourceWidth * leftSourceHeight) << 2;
}
MatrixOpClassification classify() {
return MATRIXOP_NONE;
}
/**
* Unclassified (initial state) matrix operation.
*/
private final MatrixOpClassification MATRIXOP_NONE = new MatrixOpClassification() {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return false; }
};
/**
* A matrix operation is direct if the source and destination addresses
* are the same, and the strides are the same.
*/
private final class MatrixOpDirect extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return this; }
protected MatrixOpClassification direct() { return this; }
boolean isSafe() { return false; }
native void execute(
int leftSourceAddress,
int leftSourceStride,
int leftElements,
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceAddress,
int rightSourceStride,
int rightElements,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpDirect MATRIXOP_DIRECT = new MatrixOpDirect();
/**
* A matrix operation is safe if the source and destination do not
* overlap in any way
*/
private final class MatrixOpSafe extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return true; }
native void execute(
int leftSourceAddress,
int leftSourceStride,
int leftElements,
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceAddress,
int rightSourceStride,
int rightElements,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpSafe MATRIXOP_SAFE = new MatrixOpSafe();
};
public static final MatrixOpAdd MATRIXOP_ADD = new MatrixOpAdd();
/** Subtract right source from left source */
private static final class MatrixOpSubtract extends BinaryMatrixOperation {
MatrixOpSubtract() {
super(2, "subtract");
}
int checkCompatibility(
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
boolean transposeDest)
{
// Same as for add, obviously...
return MATRIXOP_ADD.checkCompatibility(
leftSourceWidth,
leftSourceHeight,
transposeLeftSource,
rightSourceWidth,
rightSourceHeight,
transposeRightSource,
transposeDest
);
}
MatrixOpClassification classify() {
return MATRIXOP_NONE;
}
/**
* Unclassified (initial state) matrix operation.
*/
private final MatrixOpClassification MATRIXOP_NONE = new MatrixOpClassification() {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return false; }
};
/**
* A matrix operation is direct if the source and destination addresses
* are the same, and the strides are the same.
*/
private final class MatrixOpDirect extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return this; }
protected MatrixOpClassification direct() { return this; }
boolean isSafe() { return false; }
native void execute(
int leftSourceAddress,
int leftSourceStride,
int leftElements,
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceAddress,
int rightSourceStride,
int rightElements,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpDirect MATRIXOP_DIRECT = new MatrixOpDirect();
/**
* A matrix operation is safe if the source and destination do not
* overlap in any way
*/
private final class MatrixOpSafe extends MatrixOpClassification {
protected MatrixOpClassification unsafe() { return MATRIXOP_UNSAFE; }
protected MatrixOpClassification safe() { return MATRIXOP_SAFE; }
protected MatrixOpClassification direct() { return MATRIXOP_DIRECT; }
boolean isSafe() { return true; }
native void execute(
int leftSourceAddress,
int leftSourceStride,
int leftElements,
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceAddress,
int rightSourceStride,
int rightElements,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
int destAddress,
int destStride,
boolean transposeDest);
};
private final MatrixOpSafe MATRIXOP_SAFE = new MatrixOpSafe();
};
public static final MatrixOpSubtract MATRIXOP_SUBTRACT = new MatrixOpSubtract();
/**
* No constructor for Math.
*/
private Math() {
super();
}
/**
* Return the sine of theta
*
* @param theta angle in degrees
* @return sin(theta)
*/
public static float sin(float theta) {
return (float) java.lang.Math.sin(java.lang.Math.toRadians(theta));
}
/**
* Return the cosine of theta
*
* @param theta angle in degrees
* @return cos(theta)
*/
public static float cos(float theta) {
return (float) java.lang.Math.cos(java.lang.Math.toRadians(theta));
}
/**
* Return the tangent of theta
*
* @param theta angle in degrees
* @return tan(theta)
*/
public static float tan(float theta) {
return (float) java.lang.Math.tan(java.lang.Math.toRadians(theta));
}
/**
* Return the inverse sine of theta
*
* @param theta angle in degrees
* @return asin(theta)
*/
public static float asin(float theta) {
return (float) java.lang.Math.toDegrees(java.lang.Math.asin(theta));
}
/**
* Return the inverse cosine of theta
*
* @param theta angle in degrees
* @return acos(theta)
*/
public static float acos(float theta) {
return (float) java.lang.Math.toDegrees(java.lang.Math.acos(theta));
}
/**
* Return the inverse tangent of theta
*
* @param theta angle in degrees
* @return atan(theta)
*/
public static float atan(float theta) {
return (float) java.lang.Math.toDegrees(java.lang.Math.atan(theta));
}
/**
* Return the square root of a value
* @param n the number for which you want the square root
* @return sqrt(n)
*/
public static float sqrt(float n) {
return (float) java.lang.Math.sqrt(n);
}
/*
* Matrix operation classifications
*/
private static abstract class MatrixOpClassification {
abstract MatrixOpClassification unsafe();
abstract MatrixOpClassification safe();
abstract MatrixOpClassification direct();
/**
* Execute a unary matrix operation.
* The default implementation does nothing.
*/
void execute(
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest) {
}
/**
* Execute a binary matrix operation.
* The default implementation does nothing.
*/
void execute(
int leftSourceAddress,
int leftSourceStride,
int leftElements,
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceAddress,
int rightSourceStride,
int rightElements,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
int destAddress,
int destStride,
boolean transposeDest) {
}
/**
* Check a binary operation to make sure that when dealing with n x n
* result sets that when both n's are greater than 1 the operation must
* be safe; otherwise if is direct, then the side where n > 1 must be
* the destination.
*/
MatrixOpClassification checkBinaryOp(
int leftSourceElements,
int rightSourceElements,
int leftSourceAddress,
int rightSourceAddress,
int destinationAddress
) {
if (leftSourceElements > 1 && rightSourceElements > 1) {
if (isSafe())
return this;
else
return MATRIXOP_UNSAFE;
} else if (leftSourceElements == 1 && rightSourceElements > 1) {
if (isSafe())
return this;
else if (destinationAddress == rightSourceAddress)
return this;
else
return MATRIXOP_UNSAFE;
} else if (rightSourceElements == 1 && leftSourceElements > 1) {
if (isSafe())
return this;
else if (destinationAddress == leftSourceAddress)
return this;
else
return MATRIXOP_UNSAFE;
} else {
return MATRIXOP_UNSAFE;
}
}
/**
* @return true if this is a safe classification
*/
abstract boolean isSafe();
public final MatrixOpClassification check(
int sourceAddress,
int sourceStride,
int numElements,
int destAddress,
int destStride)
{
int sourceEnd = sourceAddress + sourceStride * numElements;
int destEnd = destAddress + destStride * numElements;
// Check to see if source is somewhere inside the destination
if ((sourceAddress >= destAddress && sourceAddress <= destEnd)
|| (sourceEnd >= destAddress && sourceEnd <= destEnd)) {
// Check out the strides first
if (destAddress > sourceAddress || sourceStride != destStride)
return unsafe();
else if (destAddress < sourceAddress)
return safe();
else
return direct();
} else {
// Completely safe
return safe();
}
}
}
/**
* Apply a unary matrix operation to an array of matrices.
* @param operation A unary vector operation which must be one of
* MATRIXOP_NOOP,
* MATRIXOP_NEGATE,
* MATRIXOP_NORMALIZE, etc.
* @param sourceAddress The address of the source matrices
* @param sourceStride The distance between source matrices, in bytes; if 0,
* it is assumed that the matrices are tightly packed. This is equivalent to
* sourceStride == sourceWidth * sourceHeight * 4
* @param numElements The number of matrices
* @param sourceWidth The width of the source matrix. Must be > 0.
* @param sourceHeight The height of the source matrix. Must be > 0.
* @param transposeSource The source can be transposed automatically before
* the operation is performed on it
* @param destAddress The results are placed here. This may overlap the
* source and can even be the same, which performs the unary operation
* in-situ
* @param destStride The distance between destination matrices, in bytes,
* similar to sourceStride. Note that if the source and destination address
* overlap and the strides are different then the result is undefined.
* @param transposeDest The destination can be transposed before being
* written
*/
public static void matrixOp(
UnaryMatrixOperation operation,
int sourceAddress,
int sourceStride,
int numElements,
int sourceWidth,
int sourceHeight,
boolean transposeSource,
int destAddress,
int destStride,
boolean transposeDest) {
// Check that certain parameters are legal in the first place
assert sourceAddress != 0 : "0 source address";
assert sourceStride >= 0 : "Illegal source stride";
assert numElements >= 0 : "Illegal number of elements";
assert sourceWidth >= 1 : "Illegal source width";
assert sourceHeight >= 1 : "Illegal source height";
assert destAddress != 0 : "0 dest address";
assert destStride >= 0 : "Illegal dest stride";
// Calculate actual strides
if (sourceStride == 0)
sourceStride = sourceWidth * sourceHeight;
if (destStride == 0)
destStride = sourceStride;
// Check unary matrix operation type
MatrixOpClassification op = operation.classify().check(sourceAddress, sourceStride, numElements, destAddress, destStride);
op.execute(
sourceAddress,
sourceStride,
numElements,
sourceWidth,
sourceHeight,
transposeSource,
destAddress,
destStride,
transposeDest
);
}
/**
* Apply a binary matrix operation to two arrays of matrices. The results
* are computed by applying the first right element to each of the left
* elements in turn; then the second right element to each left element;
* and so on.
* @param operation A binary vector operation which must be one of
* MATRIXOP_MUTLIPLY,
* MATRIXOP_ADD,
* MATRIXOP_SUBTRACT, etc.
* @param leftSourceAddress The address of the source matrices
* @param leftSourceStride The distance between source matrices, in bytes; if 0,
* it is assumed that the matrices are tightly packed. This is equivalent to
* sourceStride == sourceWidth * sourceHeight * 4
* @param leftElements The number of left-hand-side matrices
* @param leftSourceWidth The width of the left source matrix. Must be > 0.
* @param leftSourceHeight The height of the left source matrix. Must be > 0.
* @param transposeLeftSource The left source can be transposed automatically before
* the operation is performed on it
* @param rightSourceAddress The address of the right source matrices
* @param rightSourceStride The distance between right source matrices, in bytes; if 0,
* it is assumed that the matrices are tightly packed. This is equivalent to
* sourceStride == sourceWidth * sourceHeight * 4
* @param rightElements The number of right-hand-side matrices
* @param rightSourceWidth The width of the right source matrix. Must be > 0.
* @param rightSourceHeight The height of the right source matrix. Must be > 0.
* @param transposeRightSource The right source can be transposed automatically before
* the operation is performed on it
* @param destAddress The results are placed here. This may overlap the
* sources and can even be the same, which performs the binary operation
* in-situ
* @param destStride The distance between destination matrices, in bytes,
* similar to sourceStride. Note that if the source and destination address
* overlap and the strides are different then the result is undefined.
* @param transposeDest The destination can be transposed before being
* written
* @throws IllegalArgumentException if the source matrices are incompatible
*/
public static void matrixOp(
BinaryMatrixOperation operation,
int leftSourceAddress,
int leftSourceStride,
int leftElements,
int leftSourceWidth,
int leftSourceHeight,
boolean transposeLeftSource,
int rightSourceAddress,
int rightSourceStride,
int rightElements,
int rightSourceWidth,
int rightSourceHeight,
boolean transposeRightSource,
int destAddress,
int destStride,
boolean transposeDest) {
// Check that certain parameters are legal in the first place
assert leftSourceAddress != 0 : "0 left source address";
assert leftSourceStride >= 0 : "Illegal left source stride";
assert leftElements >= 0 : "Illegal number of left elements";
assert leftSourceWidth >= 1 : "Illegal left source width";
assert leftSourceHeight >= 1 : "Illegal left source height";
assert rightSourceAddress != 0 : "0 right source address";
assert rightSourceStride >= 0 : "Illegal right source stride";
assert rightElements >= 0 : "Illegal number of right elements";
assert rightSourceWidth >= 1 : "Illegal right source width";
assert rightSourceHeight >= 1 : "Illegal right source height";
assert destAddress != 0 : "0 dest address";
assert destStride >= 0 : "Illegal dest stride";
// Calculate actual strides
if (leftSourceStride == 0)
leftSourceStride = leftSourceWidth * leftSourceHeight;
if (rightSourceStride == 0)
rightSourceStride = rightSourceWidth * rightSourceHeight;
// Ensure the source and destination matrices are compatible
int minStride = operation.checkCompatibility(
leftSourceWidth,
leftSourceHeight,
transposeLeftSource,
rightSourceWidth,
rightSourceWidth,
transposeRightSource,
transposeDest);
if (destStride == 0)
destStride = minStride;
// Check unary matrix operation type
MatrixOpClassification op = operation.classify().check(leftSourceAddress, leftSourceStride, leftElements, destAddress, destStride);
op = op.check(rightSourceAddress, rightSourceStride, rightElements, destAddress, destStride);
op = op.checkBinaryOp(leftElements, rightElements, leftSourceAddress, rightSourceAddress, destAddress);
op.execute(
leftSourceAddress,
leftSourceStride,
leftElements,
leftSourceWidth,
leftSourceHeight,
transposeLeftSource,
rightSourceAddress,
rightSourceStride,
rightElements,
rightSourceWidth,
rightSourceHeight,
transposeRightSource,
destAddress,
destStride,
transposeDest
);
}
}