/******************************************************************************* | |
* Copyright 2011 See AUTHORS file. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
******************************************************************************/ | |
package com.badlogic.gdx.utils; | |
import java.nio.Buffer; | |
import java.nio.ByteBuffer; | |
import java.nio.ByteOrder; | |
import java.nio.CharBuffer; | |
import java.nio.DoubleBuffer; | |
import java.nio.FloatBuffer; | |
import java.nio.IntBuffer; | |
import java.nio.LongBuffer; | |
import java.nio.ShortBuffer; | |
import com.badlogic.gdx.math.Matrix3; | |
import com.badlogic.gdx.math.Matrix4; | |
/** Class with static helper methods to increase the speed of array/direct buffer and direct buffer/direct buffer transfers | |
* | |
* @author mzechner, xoppa */ | |
public final class BufferUtils { | |
static Array<ByteBuffer> unsafeBuffers = new Array<ByteBuffer>(); | |
static int allocatedUnsafe = 0; | |
/** Copies numFloats floats from src starting at offset to dst. Dst is assumed to be a direct {@link Buffer}. The method will | |
* crash if that is not the case. The position and limit of the buffer are ignored, the copy is placed at position 0 in the | |
* buffer. After the copying process the position of the buffer is set to 0 and its limit is set to numFloats * 4 if it is a | |
* ByteBuffer and numFloats if it is a FloatBuffer. In case the Buffer is neither a ByteBuffer nor a FloatBuffer the limit is | |
* not set. This is an expert method, use at your own risk. | |
* | |
* @param src the source array | |
* @param dst the destination buffer, has to be a direct Buffer | |
* @param numFloats the number of floats to copy | |
* @param offset the offset in src to start copying from */ | |
public static void copy (float[] src, Buffer dst, int numFloats, int offset) { | |
if (dst instanceof ByteBuffer) | |
dst.limit(numFloats << 2); | |
else if (dst instanceof FloatBuffer) dst.limit(numFloats); | |
copyJni(src, dst, numFloats, offset); | |
dst.position(0); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position will stay the same, the limit | |
* will be set to position + numElements. <b>The Buffer must be a direct Buffer with native byte order. No error checking is | |
* performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param dst the destination Buffer, its position is used as an offset. | |
* @param numElements the number of elements to copy. */ | |
public static void copy (byte[] src, int srcOffset, Buffer dst, int numElements) { | |
dst.limit(dst.position() + bytesToElements(dst, numElements)); | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position will stay the same, the limit | |
* will be set to position + numElements. <b>The Buffer must be a direct Buffer with native byte order. No error checking is | |
* performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param dst the destination Buffer, its position is used as an offset. | |
* @param numElements the number of elements to copy. */ | |
public static void copy (short[] src, int srcOffset, Buffer dst, int numElements) { | |
dst.limit(dst.position() + bytesToElements(dst, numElements << 1)); | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 1); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position and limit will stay the same. | |
* <b>The Buffer must be a direct Buffer with native byte order. No error checking is performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param numElements the number of elements to copy. | |
* @param dst the destination Buffer, its position is used as an offset. */ | |
public static void copy (char[] src, int srcOffset, int numElements, Buffer dst) { | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 1); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position and limit will stay the same. | |
* <b>The Buffer must be a direct Buffer with native byte order. No error checking is performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param numElements the number of elements to copy. | |
* @param dst the destination Buffer, its position is used as an offset. */ | |
public static void copy (int[] src, int srcOffset, int numElements, Buffer dst) { | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 2); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position and limit will stay the same. | |
* <b>The Buffer must be a direct Buffer with native byte order. No error checking is performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param numElements the number of elements to copy. | |
* @param dst the destination Buffer, its position is used as an offset. */ | |
public static void copy (long[] src, int srcOffset, int numElements, Buffer dst) { | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 3); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position and limit will stay the same. | |
* <b>The Buffer must be a direct Buffer with native byte order. No error checking is performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param numElements the number of elements to copy. | |
* @param dst the destination Buffer, its position is used as an offset. */ | |
public static void copy (float[] src, int srcOffset, int numElements, Buffer dst) { | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 2); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position and limit will stay the same. | |
* <b>The Buffer must be a direct Buffer with native byte order. No error checking is performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param numElements the number of elements to copy. | |
* @param dst the destination Buffer, its position is used as an offset. */ | |
public static void copy (double[] src, int srcOffset, int numElements, Buffer dst) { | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 3); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position will stay the same, the limit | |
* will be set to position + numElements. <b>The Buffer must be a direct Buffer with native byte order. No error checking is | |
* performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param dst the destination Buffer, its position is used as an offset. | |
* @param numElements the number of elements to copy. */ | |
public static void copy (char[] src, int srcOffset, Buffer dst, int numElements) { | |
dst.limit(dst.position() + bytesToElements(dst, numElements << 1)); | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 1); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position will stay the same, the limit | |
* will be set to position + numElements. <b>The Buffer must be a direct Buffer with native byte order. No error checking is | |
* performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param dst the destination Buffer, its position is used as an offset. | |
* @param numElements the number of elements to copy. */ | |
public static void copy (int[] src, int srcOffset, Buffer dst, int numElements) { | |
dst.limit(dst.position() + bytesToElements(dst, numElements << 2)); | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 2); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position will stay the same, the limit | |
* will be set to position + numElements. <b>The Buffer must be a direct Buffer with native byte order. No error checking is | |
* performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param dst the destination Buffer, its position is used as an offset. | |
* @param numElements the number of elements to copy. */ | |
public static void copy (long[] src, int srcOffset, Buffer dst, int numElements) { | |
dst.limit(dst.position() + bytesToElements(dst, numElements << 3)); | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 3); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position will stay the same, the limit | |
* will be set to position + numElements. <b>The Buffer must be a direct Buffer with native byte order. No error checking is | |
* performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param dst the destination Buffer, its position is used as an offset. | |
* @param numElements the number of elements to copy. */ | |
public static void copy (float[] src, int srcOffset, Buffer dst, int numElements) { | |
dst.limit(dst.position() + bytesToElements(dst, numElements << 2)); | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 2); | |
} | |
/** Copies the contents of src to dst, starting from src[srcOffset], copying numElements elements. The {@link Buffer} instance's | |
* {@link Buffer#position()} is used to define the offset into the Buffer itself. The position will stay the same, the limit | |
* will be set to position + numElements. <b>The Buffer must be a direct Buffer with native byte order. No error checking is | |
* performed</b>. | |
* | |
* @param src the source array. | |
* @param srcOffset the offset into the source array. | |
* @param dst the destination Buffer, its position is used as an offset. | |
* @param numElements the number of elements to copy. */ | |
public static void copy (double[] src, int srcOffset, Buffer dst, int numElements) { | |
dst.limit(dst.position() + bytesToElements(dst, numElements << 3)); | |
copyJni(src, srcOffset, dst, positionInBytes(dst), numElements << 3); | |
} | |
/** Copies the contents of src to dst, starting from the current position of src, copying numElements elements (using the data | |
* type of src, no matter the datatype of dst). The dst {@link Buffer#position()} is used as the writing offset. The position | |
* of both Buffers will stay the same. The limit of the src Buffer will stay the same. The limit of the dst Buffer will be set | |
* to dst.position() + numElements, where numElements are translated to the number of elements appropriate for the dst Buffer | |
* data type. <b>The Buffers must be direct Buffers with native byte order. No error checking is performed</b>. | |
* | |
* @param src the source Buffer. | |
* @param dst the destination Buffer. | |
* @param numElements the number of elements to copy. */ | |
public static void copy (Buffer src, Buffer dst, int numElements) { | |
int numBytes = elementsToBytes(src, numElements); | |
dst.limit(dst.position() + bytesToElements(dst, numBytes)); | |
copyJni(src, positionInBytes(src), dst, positionInBytes(dst), numBytes); | |
} | |
/** Multiply float vector components within the buffer with the specified matrix. The {@link Buffer#position()} is used as the | |
* offset. | |
* @param data The buffer to transform. | |
* @param dimensions The number of components of the vector (2 for xy, 3 for xyz or 4 for xyzw) | |
* @param strideInBytes The offset between the first and the second vector to transform | |
* @param count The number of vectors to transform | |
* @param matrix The matrix to multiply the vector with */ | |
public static void transform (Buffer data, int dimensions, int strideInBytes, int count, Matrix4 matrix) { | |
transform(data, dimensions, strideInBytes, count, matrix, 0); | |
} | |
/** Multiply float vector components within the buffer with the specified matrix. The {@link Buffer#position()} is used as the | |
* offset. | |
* @param data The buffer to transform. | |
* @param dimensions The number of components of the vector (2 for xy, 3 for xyz or 4 for xyzw) | |
* @param strideInBytes The offset between the first and the second vector to transform | |
* @param count The number of vectors to transform | |
* @param matrix The matrix to multiply the vector with */ | |
public static void transform (float[] data, int dimensions, int strideInBytes, int count, Matrix4 matrix) { | |
transform(data, dimensions, strideInBytes, count, matrix, 0); | |
} | |
/** Multiply float vector components within the buffer with the specified matrix. The specified offset value is added to the | |
* {@link Buffer#position()} and used as the offset. | |
* @param data The buffer to transform. | |
* @param dimensions The number of components of the vector (2 for xy, 3 for xyz or 4 for xyzw) | |
* @param strideInBytes The offset between the first and the second vector to transform | |
* @param count The number of vectors to transform | |
* @param matrix The matrix to multiply the vector with | |
* @param offset The offset within the buffer (in bytes relative to the current position) to the vector */ | |
public static void transform (Buffer data, int dimensions, int strideInBytes, int count, Matrix4 matrix, int offset) { | |
switch (dimensions) { | |
case 4: | |
transformV4M4Jni(data, strideInBytes, count, matrix.val, positionInBytes(data) + offset); | |
break; | |
case 3: | |
transformV3M4Jni(data, strideInBytes, count, matrix.val, positionInBytes(data) + offset); | |
break; | |
case 2: | |
transformV2M4Jni(data, strideInBytes, count, matrix.val, positionInBytes(data) + offset); | |
break; | |
default: | |
throw new IllegalArgumentException(); | |
} | |
} | |
/** Multiply float vector components within the buffer with the specified matrix. The specified offset value is added to the | |
* {@link Buffer#position()} and used as the offset. | |
* @param data The buffer to transform. | |
* @param dimensions The number of components of the vector (2 for xy, 3 for xyz or 4 for xyzw) | |
* @param strideInBytes The offset between the first and the second vector to transform | |
* @param count The number of vectors to transform | |
* @param matrix The matrix to multiply the vector with | |
* @param offset The offset within the buffer (in bytes relative to the current position) to the vector */ | |
public static void transform (float[] data, int dimensions, int strideInBytes, int count, Matrix4 matrix, int offset) { | |
switch (dimensions) { | |
case 4: | |
transformV4M4Jni(data, strideInBytes, count, matrix.val, offset); | |
break; | |
case 3: | |
transformV3M4Jni(data, strideInBytes, count, matrix.val, offset); | |
break; | |
case 2: | |
transformV2M4Jni(data, strideInBytes, count, matrix.val, offset); | |
break; | |
default: | |
throw new IllegalArgumentException(); | |
} | |
} | |
/** Multiply float vector components within the buffer with the specified matrix. The {@link Buffer#position()} is used as the | |
* offset. | |
* @param data The buffer to transform. | |
* @param dimensions The number of components (x, y, z) of the vector (2 for xy or 3 for xyz) | |
* @param strideInBytes The offset between the first and the second vector to transform | |
* @param count The number of vectors to transform | |
* @param matrix The matrix to multiply the vector with */ | |
public static void transform (Buffer data, int dimensions, int strideInBytes, int count, Matrix3 matrix) { | |
transform(data, dimensions, strideInBytes, count, matrix, 0); | |
} | |
/** Multiply float vector components within the buffer with the specified matrix. The {@link Buffer#position()} is used as the | |
* offset. | |
* @param data The buffer to transform. | |
* @param dimensions The number of components (x, y, z) of the vector (2 for xy or 3 for xyz) | |
* @param strideInBytes The offset between the first and the second vector to transform | |
* @param count The number of vectors to transform | |
* @param matrix The matrix to multiply the vector with */ | |
public static void transform (float[] data, int dimensions, int strideInBytes, int count, Matrix3 matrix) { | |
transform(data, dimensions, strideInBytes, count, matrix, 0); | |
} | |
/** Multiply float vector components within the buffer with the specified matrix. The specified offset value is added to the | |
* {@link Buffer#position()} and used as the offset. | |
* @param data The buffer to transform. | |
* @param dimensions The number of components (x, y, z) of the vector (2 for xy or 3 for xyz) | |
* @param strideInBytes The offset between the first and the second vector to transform | |
* @param count The number of vectors to transform | |
* @param matrix The matrix to multiply the vector with, | |
* @param offset The offset within the buffer (in bytes relative to the current position) to the vector */ | |
public static void transform (Buffer data, int dimensions, int strideInBytes, int count, Matrix3 matrix, int offset) { | |
switch (dimensions) { | |
case 3: | |
transformV3M3Jni(data, strideInBytes, count, matrix.val, positionInBytes(data) + offset); | |
break; | |
case 2: | |
transformV2M3Jni(data, strideInBytes, count, matrix.val, positionInBytes(data) + offset); | |
break; | |
default: | |
throw new IllegalArgumentException(); | |
} | |
} | |
/** Multiply float vector components within the buffer with the specified matrix. The specified offset value is added to the | |
* {@link Buffer#position()} and used as the offset. | |
* @param data The buffer to transform. | |
* @param dimensions The number of components (x, y, z) of the vector (2 for xy or 3 for xyz) | |
* @param strideInBytes The offset between the first and the second vector to transform | |
* @param count The number of vectors to transform | |
* @param matrix The matrix to multiply the vector with, | |
* @param offset The offset within the buffer (in bytes relative to the current position) to the vector */ | |
public static void transform (float[] data, int dimensions, int strideInBytes, int count, Matrix3 matrix, int offset) { | |
switch (dimensions) { | |
case 3: | |
transformV3M3Jni(data, strideInBytes, count, matrix.val, offset); | |
break; | |
case 2: | |
transformV2M3Jni(data, strideInBytes, count, matrix.val, offset); | |
break; | |
default: | |
throw new IllegalArgumentException(); | |
} | |
} | |
public static long findFloats (Buffer vertex, int strideInBytes, Buffer vertices, int numVertices) { | |
return find(vertex, positionInBytes(vertex), strideInBytes, vertices, positionInBytes(vertices), numVertices); | |
} | |
public static long findFloats (float[] vertex, int strideInBytes, Buffer vertices, int numVertices) { | |
return find(vertex, 0, strideInBytes, vertices, positionInBytes(vertices), numVertices); | |
} | |
public static long findFloats (Buffer vertex, int strideInBytes, float[] vertices, int numVertices) { | |
return find(vertex, positionInBytes(vertex), strideInBytes, vertices, 0, numVertices); | |
} | |
public static long findFloats (float[] vertex, int strideInBytes, float[] vertices, int numVertices) { | |
return find(vertex, 0, strideInBytes, vertices, 0, numVertices); | |
} | |
public static long findFloats (Buffer vertex, int strideInBytes, Buffer vertices, int numVertices, float epsilon) { | |
return find(vertex, positionInBytes(vertex), strideInBytes, vertices, positionInBytes(vertices), numVertices, epsilon); | |
} | |
public static long findFloats (float[] vertex, int strideInBytes, Buffer vertices, int numVertices, float epsilon) { | |
return find(vertex, 0, strideInBytes, vertices, positionInBytes(vertices), numVertices, epsilon); | |
} | |
public static long findFloats (Buffer vertex, int strideInBytes, float[] vertices, int numVertices, float epsilon) { | |
return find(vertex, positionInBytes(vertex), strideInBytes, vertices, 0, numVertices, epsilon); | |
} | |
public static long findFloats (float[] vertex, int strideInBytes, float[] vertices, int numVertices, float epsilon) { | |
return find(vertex, 0, strideInBytes, vertices, 0, numVertices, epsilon); | |
} | |
private static int positionInBytes (Buffer dst) { | |
if (dst instanceof ByteBuffer) | |
return dst.position(); | |
else if (dst instanceof ShortBuffer) | |
return dst.position() << 1; | |
else if (dst instanceof CharBuffer) | |
return dst.position() << 1; | |
else if (dst instanceof IntBuffer) | |
return dst.position() << 2; | |
else if (dst instanceof LongBuffer) | |
return dst.position() << 3; | |
else if (dst instanceof FloatBuffer) | |
return dst.position() << 2; | |
else if (dst instanceof DoubleBuffer) | |
return dst.position() << 3; | |
else | |
throw new GdxRuntimeException("Can't copy to a " + dst.getClass().getName() + " instance"); | |
} | |
private static int bytesToElements (Buffer dst, int bytes) { | |
if (dst instanceof ByteBuffer) | |
return bytes; | |
else if (dst instanceof ShortBuffer) | |
return bytes >>> 1; | |
else if (dst instanceof CharBuffer) | |
return bytes >>> 1; | |
else if (dst instanceof IntBuffer) | |
return bytes >>> 2; | |
else if (dst instanceof LongBuffer) | |
return bytes >>> 3; | |
else if (dst instanceof FloatBuffer) | |
return bytes >>> 2; | |
else if (dst instanceof DoubleBuffer) | |
return bytes >>> 3; | |
else | |
throw new GdxRuntimeException("Can't copy to a " + dst.getClass().getName() + " instance"); | |
} | |
private static int elementsToBytes (Buffer dst, int elements) { | |
if (dst instanceof ByteBuffer) | |
return elements; | |
else if (dst instanceof ShortBuffer) | |
return elements << 1; | |
else if (dst instanceof CharBuffer) | |
return elements << 1; | |
else if (dst instanceof IntBuffer) | |
return elements << 2; | |
else if (dst instanceof LongBuffer) | |
return elements << 3; | |
else if (dst instanceof FloatBuffer) | |
return elements << 2; | |
else if (dst instanceof DoubleBuffer) | |
return elements << 3; | |
else | |
throw new GdxRuntimeException("Can't copy to a " + dst.getClass().getName() + " instance"); | |
} | |
public static FloatBuffer newFloatBuffer (int numFloats) { | |
ByteBuffer buffer = ByteBuffer.allocateDirect(numFloats * 4); | |
buffer.order(ByteOrder.nativeOrder()); | |
return buffer.asFloatBuffer(); | |
} | |
public static DoubleBuffer newDoubleBuffer (int numDoubles) { | |
ByteBuffer buffer = ByteBuffer.allocateDirect(numDoubles * 8); | |
buffer.order(ByteOrder.nativeOrder()); | |
return buffer.asDoubleBuffer(); | |
} | |
public static ByteBuffer newByteBuffer (int numBytes) { | |
ByteBuffer buffer = ByteBuffer.allocateDirect(numBytes); | |
buffer.order(ByteOrder.nativeOrder()); | |
return buffer; | |
} | |
public static ShortBuffer newShortBuffer (int numShorts) { | |
ByteBuffer buffer = ByteBuffer.allocateDirect(numShorts * 2); | |
buffer.order(ByteOrder.nativeOrder()); | |
return buffer.asShortBuffer(); | |
} | |
public static CharBuffer newCharBuffer (int numChars) { | |
ByteBuffer buffer = ByteBuffer.allocateDirect(numChars * 2); | |
buffer.order(ByteOrder.nativeOrder()); | |
return buffer.asCharBuffer(); | |
} | |
public static IntBuffer newIntBuffer (int numInts) { | |
ByteBuffer buffer = ByteBuffer.allocateDirect(numInts * 4); | |
buffer.order(ByteOrder.nativeOrder()); | |
return buffer.asIntBuffer(); | |
} | |
public static LongBuffer newLongBuffer (int numLongs) { | |
ByteBuffer buffer = ByteBuffer.allocateDirect(numLongs * 8); | |
buffer.order(ByteOrder.nativeOrder()); | |
return buffer.asLongBuffer(); | |
} | |
// @off | |
/*JNI | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
*/ | |
public static void disposeUnsafeByteBuffer(ByteBuffer buffer) { | |
int size = buffer.capacity(); | |
synchronized(unsafeBuffers) { | |
if(!unsafeBuffers.removeValue(buffer, true)) | |
throw new IllegalArgumentException("buffer not allocated with newUnsafeByteBuffer or already disposed"); | |
} | |
allocatedUnsafe -= size; | |
freeMemory(buffer); | |
} | |
/** Allocates a new direct ByteBuffer from native heap memory using the native byte order. Needs to be disposed with | |
* {@link #freeMemory(ByteBuffer)}. | |
* @param numBytes */ | |
public static ByteBuffer newUnsafeByteBuffer (int numBytes) { | |
ByteBuffer buffer = newDisposableByteBuffer(numBytes); | |
buffer.order(ByteOrder.nativeOrder()); | |
allocatedUnsafe += numBytes; | |
synchronized(unsafeBuffers) { | |
unsafeBuffers.add(buffer); | |
} | |
return buffer; | |
} | |
/** | |
* Returns the address of the Buffer, it assumes it is an unsafe buffer. | |
* @param buffer The Buffer to ask the address for. | |
* @return the address of the Buffer. | |
*/ | |
public static long getUnsafeBufferAddress(Buffer buffer) { | |
return getBufferAddress(buffer) + buffer.position(); | |
} | |
/** | |
* Registers the given ByteBuffer as an unsafe ByteBuffer. The ByteBuffer must have been | |
* allocated in native code, pointing to a memory region allocated via malloc. Needs to | |
* be disposed with {@link #freeMemory(ByteBuffer)}. | |
* @param buffer the {@link ByteBuffer} to register | |
* @return the ByteBuffer passed to the method | |
*/ | |
public static ByteBuffer newUnsafeByteBuffer(ByteBuffer buffer) { | |
allocatedUnsafe += buffer.capacity(); | |
synchronized(unsafeBuffers) { | |
unsafeBuffers.add(buffer); | |
} | |
return buffer; | |
} | |
/** | |
* @return the number of bytes allocated with {@link #newUnsafeByteBuffer(int)} | |
*/ | |
public static int getAllocatedBytesUnsafe() { | |
return allocatedUnsafe; | |
} | |
/** Frees the memory allocated for the ByteBuffer. DO NOT USE THIS ON BYTEBUFFERS ALLOCATEd VIA METHODS IN THIS CLASS OR | |
* ByteBuffer.allocateDirect()! IT WILL EXPLODE! */ | |
private static native void freeMemory (ByteBuffer buffer); /* | |
free(buffer); | |
*/ | |
private static native ByteBuffer newDisposableByteBuffer (int numBytes); /* | |
return env->NewDirectByteBuffer((char*)malloc(numBytes), numBytes); | |
*/ | |
private static native long getBufferAddress (Buffer buffer); /* | |
return (jlong) buffer; | |
*/ | |
/** Writes the specified number of zeros to the buffer. This is generally faster than reallocating a new buffer. */ | |
public static native void clear (ByteBuffer buffer, int numBytes); /* | |
memset(buffer, 0, numBytes); | |
*/ | |
private native static void copyJni (float[] src, Buffer dst, int numFloats, int offset); /* | |
memcpy(dst, src + offset, numFloats << 2 ); | |
*/ | |
private native static void copyJni (byte[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); /* | |
memcpy(dst + dstOffset, src + srcOffset, numBytes); | |
*/ | |
private native static void copyJni (char[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); /* | |
memcpy(dst + dstOffset, src + srcOffset, numBytes); | |
*/ | |
private native static void copyJni (short[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); /* | |
memcpy(dst + dstOffset, src + srcOffset, numBytes); | |
*/ | |
private native static void copyJni (int[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); /* | |
memcpy(dst + dstOffset, src + srcOffset, numBytes); | |
*/ | |
private native static void copyJni (long[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); /* | |
memcpy(dst + dstOffset, src + srcOffset, numBytes); | |
*/ | |
private native static void copyJni (float[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); /* | |
memcpy(dst + dstOffset, src + srcOffset, numBytes); | |
*/ | |
private native static void copyJni (double[] src, int srcOffset, Buffer dst, int dstOffset, int numBytes); /* | |
memcpy(dst + dstOffset, src + srcOffset, numBytes); | |
*/ | |
private native static void copyJni (Buffer src, int srcOffset, Buffer dst, int dstOffset, int numBytes); /* | |
memcpy(dst + dstOffset, src + srcOffset, numBytes); | |
*/ | |
/*JNI | |
template<size_t n1, size_t n2> void transform(float * const &src, float * const &m, float * const &dst) {} | |
template<> inline void transform<4, 4>(float * const &src, float * const &m, float * const &dst) { | |
const float x = src[0], y = src[1], z = src[2], w = src[3]; | |
dst[0] = x * m[ 0] + y * m[ 4] + z * m[ 8] + w * m[12]; | |
dst[1] = x * m[ 1] + y * m[ 5] + z * m[ 9] + w * m[13]; | |
dst[2] = x * m[ 2] + y * m[ 6] + z * m[10] + w * m[14]; | |
dst[3] = x * m[ 3] + y * m[ 7] + z * m[11] + w * m[15]; | |
} | |
template<> inline void transform<3, 4>(float * const &src, float * const &m, float * const &dst) { | |
const float x = src[0], y = src[1], z = src[2]; | |
dst[0] = x * m[ 0] + y * m[ 4] + z * m[ 8] + m[12]; | |
dst[1] = x * m[ 1] + y * m[ 5] + z * m[ 9] + m[13]; | |
dst[2] = x * m[ 2] + y * m[ 6] + z * m[10] + m[14]; | |
} | |
template<> inline void transform<2, 4>(float * const &src, float * const &m, float * const &dst) { | |
const float x = src[0], y = src[1]; | |
dst[0] = x * m[ 0] + y * m[ 4] + m[12]; | |
dst[1] = x * m[ 1] + y * m[ 5] + m[13]; | |
} | |
template<> inline void transform<3, 3>(float * const &src, float * const &m, float * const &dst) { | |
const float x = src[0], y = src[1], z = src[2]; | |
dst[0] = x * m[0] + y * m[3] + z * m[6]; | |
dst[1] = x * m[1] + y * m[4] + z * m[7]; | |
dst[2] = x * m[2] + y * m[5] + z * m[8]; | |
} | |
template<> inline void transform<2, 3>(float * const &src, float * const &m, float * const &dst) { | |
const float x = src[0], y = src[1]; | |
dst[0] = x * m[0] + y * m[3] + m[6]; | |
dst[1] = x * m[1] + y * m[4] + m[7]; | |
} | |
template<size_t n1, size_t n2> void transform(float * const &v, int const &stride, int const &count, float * const &m, int offset) { | |
for (int i = 0; i < count; i++) { | |
transform<n1, n2>(&v[offset], m, &v[offset]); | |
offset += stride; | |
} | |
} | |
template<size_t n1, size_t n2> void transform(float * const &v, int const &stride, unsigned short * const &indices, int const &count, float * const &m, int offset) { | |
for (int i = 0; i < count; i++) { | |
transform<n1, n2>(&v[offset], m, &v[offset]); | |
offset += stride; | |
} | |
} | |
inline bool compare(float * const &lhs, float * const & rhs, const unsigned int &size, const float &epsilon) { | |
for (unsigned int i = 0; i < size; i++) | |
if ((*(unsigned int*)&lhs[i] != *(unsigned int*)&rhs[i]) && ((lhs[i] > rhs[i] ? lhs[i] - rhs[i] : rhs[i] - lhs[i]) > epsilon)) | |
return false; | |
return true; | |
} | |
long find(float * const &vertex, const unsigned int &size, float * const &vertices, const unsigned int &count, const float &epsilon) { | |
for (unsigned int i = 0; i < count; i++) | |
if (compare(&vertices[i*size], vertex, size, epsilon)) | |
return (long)i; | |
return -1; | |
} | |
inline bool compare(float * const &lhs, float * const & rhs, const unsigned int &size) { | |
for (unsigned int i = 0; i < size; i++) | |
if ((*(unsigned int*)&lhs[i] != *(unsigned int*)&rhs[i]) && lhs[i] != rhs[i]) | |
return false; | |
return true; | |
} | |
long find(float * const &vertex, const unsigned int &size, float * const &vertices, const unsigned int &count) { | |
for (unsigned int i = 0; i < count; i++) | |
if (compare(&vertices[i*size], vertex, size)) | |
return (long)i; | |
return -1; | |
} | |
inline unsigned int calcHash(float * const &vertex, const unsigned int &size) { | |
unsigned int result = 0; | |
for (unsigned int i = 0; i < size; ++i) | |
result += ((*((unsigned int *)&vertex[i])) & 0xffffff80) >> (i & 0x7); | |
return result & 0x7fffffff; | |
} | |
long find(float * const &vertex, const unsigned int &size, float * const &vertices, unsigned int * const &hashes, const unsigned int &count) { | |
const unsigned int hash = calcHash(vertex, size); | |
for (unsigned int i = 0; i < count; i++) | |
if (hashes[i] == hash && compare(&vertices[i*size], vertex, size)) | |
return (long)i; | |
return -1; | |
} | |
*/ | |
private native static void transformV4M4Jni (Buffer data, int strideInBytes, int count, float[] matrix, int offsetInBytes); /* | |
transform<4, 4>((float*)data, strideInBytes / 4, count, (float*)matrix, offsetInBytes / 4); | |
*/ | |
private native static void transformV4M4Jni (float[] data, int strideInBytes, int count, float[] matrix, int offsetInBytes); /* | |
transform<4, 4>((float*)data, strideInBytes / 4, count, (float*)matrix, offsetInBytes / 4); | |
*/ | |
private native static void transformV3M4Jni (Buffer data, int strideInBytes, int count, float[] matrix, int offsetInBytes); /* | |
transform<3, 4>((float*)data, strideInBytes / 4, count, (float*)matrix, offsetInBytes / 4); | |
*/ | |
private native static void transformV3M4Jni (float[] data, int strideInBytes, int count, float[] matrix, int offsetInBytes); /* | |
transform<3, 4>((float*)data, strideInBytes / 4, count, (float*)matrix, offsetInBytes / 4); | |
*/ | |
private native static void transformV2M4Jni (Buffer data, int strideInBytes, int count, float[] matrix, int offsetInBytes); /* | |
transform<2, 4>((float*)data, strideInBytes / 4, count, (float*)matrix, offsetInBytes / 4); | |
*/ | |
private native static void transformV2M4Jni (float[] data, int strideInBytes, int count, float[] matrix, int offsetInBytes); /* | |
transform<2, 4>((float*)data, strideInBytes / 4, count, (float*)matrix, offsetInBytes / 4); | |
*/ | |
private native static void transformV3M3Jni (Buffer data, int strideInBytes, int count, float[] matrix, int offsetInBytes); /* | |
transform<3, 3>((float*)data, strideInBytes / 4, count, (float*)matrix, offsetInBytes / 4); | |
*/ | |
private native static void transformV3M3Jni (float[] data, int strideInBytes, int count, float[] matrix, int offsetInBytes); /* | |
transform<3, 3>((float*)data, strideInBytes / 4, count, (float*)matrix, offsetInBytes / 4); | |
*/ | |
private native static void transformV2M3Jni (Buffer data, int strideInBytes, int count, float[] matrix, int offsetInBytes); /* | |
transform<2, 3>((float*)data, strideInBytes / 4, count, (float*)matrix, offsetInBytes / 4); | |
*/ | |
private native static void transformV2M3Jni (float[] data, int strideInBytes, int count, float[] matrix, int offsetInBytes); /* | |
transform<2, 3>((float*)data, strideInBytes / 4, count, (float*)matrix, offsetInBytes / 4); | |
*/ | |
private native static long find(Buffer vertex, int vertexOffsetInBytes, int strideInBytes, Buffer vertices, int verticesOffsetInBytes, int numVertices); /* | |
return find((float *)&vertex[vertexOffsetInBytes / 4], (unsigned int)(strideInBytes / 4), (float*)&vertices[verticesOffsetInBytes / 4], (unsigned int)numVertices); | |
*/ | |
private native static long find(float[] vertex, int vertexOffsetInBytes, int strideInBytes, Buffer vertices, int verticesOffsetInBytes, int numVertices); /* | |
return find((float *)&vertex[vertexOffsetInBytes / 4], (unsigned int)(strideInBytes / 4), (float*)&vertices[verticesOffsetInBytes / 4], (unsigned int)numVertices); | |
*/ | |
private native static long find(Buffer vertex, int vertexOffsetInBytes, int strideInBytes, float[] vertices, int verticesOffsetInBytes, int numVertices); /* | |
return find((float *)&vertex[vertexOffsetInBytes / 4], (unsigned int)(strideInBytes / 4), (float*)&vertices[verticesOffsetInBytes / 4], (unsigned int)numVertices); | |
*/ | |
private native static long find(float[] vertex, int vertexOffsetInBytes, int strideInBytes, float[] vertices, int verticesOffsetInBytes, int numVertices); /* | |
return find((float *)&vertex[vertexOffsetInBytes / 4], (unsigned int)(strideInBytes / 4), (float*)&vertices[verticesOffsetInBytes / 4], (unsigned int)numVertices); | |
*/ | |
private native static long find(Buffer vertex, int vertexOffsetInBytes, int strideInBytes, Buffer vertices, int verticesOffsetInBytes, int numVertices, float epsilon); /* | |
return find((float *)&vertex[vertexOffsetInBytes / 4], (unsigned int)(strideInBytes / 4), (float*)&vertices[verticesOffsetInBytes / 4], (unsigned int)numVertices, epsilon); | |
*/ | |
private native static long find(float[] vertex, int vertexOffsetInBytes, int strideInBytes, Buffer vertices, int verticesOffsetInBytes, int numVertices, float epsilon); /* | |
return find((float *)&vertex[vertexOffsetInBytes / 4], (unsigned int)(strideInBytes / 4), (float*)&vertices[verticesOffsetInBytes / 4], (unsigned int)numVertices, epsilon); | |
*/ | |
private native static long find(Buffer vertex, int vertexOffsetInBytes, int strideInBytes, float[] vertices, int verticesOffsetInBytes, int numVertices, float epsilon); /* | |
return find((float *)&vertex[vertexOffsetInBytes / 4], (unsigned int)(strideInBytes / 4), (float*)&vertices[verticesOffsetInBytes / 4], (unsigned int)numVertices, epsilon); | |
*/ | |
private native static long find(float[] vertex, int vertexOffsetInBytes, int strideInBytes, float[] vertices, int verticesOffsetInBytes, int numVertices, float epsilon); /* | |
return find((float *)&vertex[vertexOffsetInBytes / 4], (unsigned int)(strideInBytes / 4), (float*)&vertices[verticesOffsetInBytes / 4], (unsigned int)numVertices, epsilon); | |
*/ | |
} |