com.jme3.lwjgl3.utils.APIBuffer Maven / Gradle / Ivy
Show all versions of jme3-lwjgl3 Show documentation
/*
* Copyright LWJGL. All rights reserved.
* License terms: http://lwjgl.org/license.php
*/
package com.jme3.lwjgl3.utils;
import org.lwjgl.BufferUtils;
import org.lwjgl.PointerBuffer;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static org.lwjgl.system.Pointer.*;
import static org.lwjgl.system.MathUtil.*;
import org.lwjgl.system.MemoryUtil;
import static org.lwjgl.system.MemoryUtil.*;
/**
* Helper class for alternative API functions. Instead of the user passing their
* own buffer, thread-local instances of this class are used internally instead.
*/
public class APIBuffer {
private static final int DEFAULT_CAPACITY = 128;
private ByteBuffer buffer;
private long address;
private int offset;
private int stackDepth;
private int[] stack = new int[4];
public APIBuffer() {
buffer = BufferUtils.createByteBuffer(DEFAULT_CAPACITY);
address = memAddress(buffer);
}
/**
* Resets the parameter offset to 0.
*/
public APIBuffer reset() {
offset = 0;
return this;
}
/**
* Pushes the current parameter offset to a stack.
*/
public APIBuffer push() {
if (stackDepth == stack.length) {
stack = Arrays.copyOf(stack, stack.length << 1);
}
stack[stackDepth++] = offset;
// Upward align the current offset to the pointer size.
offset = (offset + (POINTER_SIZE - 1)) & -POINTER_SIZE;
return this;
}
/**
* Restores the last pushed parameter offset.
*/
public APIBuffer pop() {
offset = stack[--stackDepth];
return this;
}
/**
* Returns the current parameter offset.
*/
public int getOffset() {
return offset;
}
/**
* Sets the current parameter offset.
*/
public void setOffset(int offset) {
this.offset = offset;
}
/**
* Returns the memory address of the internal {@link ByteBuffer}. This
* address may change after a call to one of the {@code Param()}
* methods.
*/
public long address() {
return address;
}
/**
* Returns the memory address of the specified {@code offset}. This address
* may change after a call to one of the {@code Param()} methods.
*/
public long address(int offset) {
return address + offset;
}
/**
* Returns the memory address of the specified {@code offset} or
* {@link MemoryUtil#NULL NULL} if the specified {@code value} is null. This
* address may change after a call to one of the {@code Param()}
* methods.
*/
public long addressSafe(Object value, int offset) {
return value == null ? NULL : address(offset);
}
/**
* Returns the {@link ByteBuffer} that backs this {@link APIBuffer}.
*/
public ByteBuffer buffer() {
return buffer;
}
private void ensureCapacity(int capacity) {
if (capacity <= buffer.capacity()) {
return;
}
ByteBuffer resized = BufferUtils.createByteBuffer(mathRoundPoT(capacity));
resized.put(buffer);
resized.clear();
buffer = resized;
address = memAddress(resized);
}
// ---------------------------------------------------------------------------------------------------------------------
private int param(int bytes) {
return param(bytes, bytes);
}
private int param(int bytes, int alignment) {
// Upward align the current offset to the specified alignment
int param = (offset + (alignment - 1)) & -alignment;
ensureCapacity(offset = param + bytes);
return param;
}
/**
* Ensures space for an additional boolean value and returns the address
* offset.
*/
public int booleanParam() {
return param(1);
}
/**
* Ensures space for an additional byte value and returns the address
* offset.
*/
public int byteParam() {
return param(1);
}
/**
* Ensures space for an additional short value and returns the address
* offset.
*/
public int shortParam() {
return param(2);
}
/**
* Ensures space for an additional int value and returns the address offset.
*/
public int intParam() {
return param(4);
}
/**
* Ensures space for an additional long value and returns the address
* offset.
*/
public int longParam() {
return param(8);
}
/**
* Ensures space for an additional float value and returns the address
* offset.
*/
public int floatParam() {
return param(4);
}
/**
* Ensures space for an additional double value and returns the address
* offset.
*/
public int doubleParam() {
return param(8);
}
/**
* Ensures space for an additional pointer value and returns the address
* offset.
*/
public int pointerParam() {
return param(POINTER_SIZE);
}
/**
* Ensures space for an additional buffer with the specified size (in bytes)
* and returns the address offset.
*/
public int bufferParam(int size) {
return param(size, POINTER_SIZE);
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* Ensures space for an additional boolean value, sets the specified value
* at the allocated offset and returns that offset.
*/
public int booleanParam(boolean value) {
int offset = booleanParam();
buffer.put(offset, value ? (byte) 1 : (byte) 0);
return offset;
}
/**
* Ensures space for an additional byte value, sets the specified value at
* the allocated offset and returns that offset.
*/
public int byteParam(byte value) {
int offset = byteParam();
buffer.put(offset, value);
return offset;
}
/**
* Ensures space for an additional short value, sets the specified value at
* the allocated offset and returns that offset.
*/
public int shortParam(short value) {
int offset = shortParam();
buffer.putShort(offset, value);
return offset;
}
/**
* Ensures space for an additional int value, sets the specified value at
* the allocated offset and returns that offset.
*/
public int intParam(int value) {
int offset = intParam();
buffer.putInt(offset, value);
return offset;
}
/**
* Ensures space for an additional long value, sets the specified value at
* the allocated offset and returns that offset.
*/
public int longParam(long value) {
int offset = longParam();
buffer.putLong(offset, value);
return offset;
}
/**
* Ensures space for an additional float value, sets the specified value at
* the allocated offset and returns that offset.
*/
public int floatParam(float value) {
int offset = floatParam();
buffer.putFloat(offset, value);
return offset;
}
/**
* Ensures space for an additional double value, sets the specified value at
* the allocated offset and returns that offset.
*/
public int doubleParam(double value) {
int offset = doubleParam();
buffer.putDouble(offset, value);
return offset;
}
/**
* Ensures space for an additional pointer value, sets the specified value
* at the allocated offset and returns that offset.
*/
public int pointerParam(long value) {
int offset = pointerParam();
PointerBuffer.put(buffer, offset, value);
return offset;
}
// ----
/**
* Ensures space for an additional pointer buffer, sets the specified memory
* addresses and returns the address offset.
*/
public int pointerArrayParam(long... pointers) {
int buffersAddress = bufferParam(pointers.length << POINTER_SHIFT);
for (int i = 0; i < pointers.length; i++) {
pointerParam(buffersAddress, i, pointers[i]);
}
return buffersAddress;
}
/**
* Ensures space for an additional pointer buffer, sets the memory addresses
* of the specified buffers and returns the address offset.
*/
public int pointerArrayParam(ByteBuffer... buffers) {
int buffersAddress = bufferParam(buffers.length << POINTER_SHIFT);
for (int i = 0; i < buffers.length; i++) {
pointerParam(buffersAddress, i, memAddress(buffers[i]));
}
return buffersAddress;
}
/**
* Ensures space for two additional pointer buffers, sets the memory
* addresses and remaining bytes of the specified buffers and returns the
* address offset.
*/
public int pointerArrayParamp(ByteBuffer... buffers) {
int buffersAddress = pointerArrayParam(buffers);
int buffersLengths = bufferParam(buffers.length << POINTER_SHIFT);
for (int i = 0; i < buffers.length; i++) {
pointerParam(buffersLengths, i, buffers[i].remaining());
}
return buffersAddress;
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* ASCII encodes the specified strings with a null-terminator and ensures
* space for a buffer filled with the memory addresses of the encoded
* strings.
*
*
* The encoded buffers must be later freed with
* {@link #pointerArrayFree(int, int)}.
*
* @return the offset to the memory address buffer
*/
public int pointerArrayParamASCII(CharSequence... strings) {
int buffersAddress = bufferParam(strings.length << POINTER_SHIFT);
for (int i = 0; i < strings.length; i++) {
ByteBuffer buffer = MemoryUtil.memASCII(strings[i]);
pointerParam(buffersAddress, i, memAddress(buffer));
}
return buffersAddress;
}
/**
* ASCII encodes the specified strings and ensures space for two additional
* buffers filled with the lengths and memory addresses of the encoded
* strings, respectively. The lengths are 4-bytes integers and the memory
* address buffer starts immediately after the lengths buffer.
*
*
* The encoded buffers must be later freed with
* {@link #pointerArrayFree(int, int)}.
*
* @return the offset to the lengths buffer
*/
public int pointerArrayParamASCIIi(CharSequence... strings) {
int buffersAddress = bufferParam(strings.length << POINTER_SHIFT);
int lengthsAddress = bufferParam(strings.length << 2);
for (int i = 0; i < strings.length; i++) {
ByteBuffer buffer = MemoryUtil.memASCII(strings[i]);
pointerParam(buffersAddress, i, memAddress(buffer));
intParam(lengthsAddress, i, buffer.remaining());
}
return buffersAddress;
}
/**
* ASCII encodes the specified strings and ensures space for two additional
* buffers filled with the lengths and memory addresses of the encoded
* strings, respectively. The lengths are pointer-sized integers and the
* memory address buffer starts immediately after the lengths buffer.
*
*
* The encoded buffers must be later freed with
* {@link #pointerArrayFree(int, int)}.
*
* @return the offset to the lengths buffer
*/
public int pointerArrayParamASCIIp(CharSequence... strings) {
int buffersAddress = bufferParam(strings.length << POINTER_SHIFT);
int lengthsAddress = bufferParam(strings.length << POINTER_SHIFT);
for (int i = 0; i < strings.length; i++) {
ByteBuffer buffer = MemoryUtil.memASCII(strings[i]);
pointerParam(buffersAddress, i, memAddress(buffer));
pointerParam(lengthsAddress, i, buffer.remaining());
}
return buffersAddress;
}
/**
* UTF8 encodes the specified strings with a null-terminator and ensures
* space for a buffer filled with the memory addresses of the encoded
* strings.
*
*
* The encoded buffers must be later freed with
* {@link #pointerArrayFree(int, int)}.
*
* @return the offset to the memory address buffer
*/
public int pointerArrayParamUTF8(CharSequence... strings) {
int buffersAddress = bufferParam(strings.length << POINTER_SHIFT);
for (int i = 0; i < strings.length; i++) {
ByteBuffer buffer = MemoryUtil.memUTF8(strings[i]);
pointerParam(buffersAddress, i, memAddress(buffer));
}
return buffersAddress;
}
/**
* UTF8 encodes the specified strings and ensures space for two additional
* buffers filled with the lengths and memory addresses of the encoded
* strings, respectively. The lengths are 4-bytes integers and the memory
* address buffer starts immediately after the lengths buffer.
*
*
* The encoded buffers must be later freed with
* {@link #pointerArrayFree(int, int)}.
*
* @return the offset to the lengths buffer
*/
public int pointerArrayParamUTF8i(CharSequence... strings) {
int buffersAddress = bufferParam(strings.length << POINTER_SHIFT);
int lengthsAddress = bufferParam(strings.length << 2);
for (int i = 0; i < strings.length; i++) {
ByteBuffer buffer = MemoryUtil.memUTF8(strings[i]);
pointerParam(buffersAddress, i, memAddress(buffer));
intParam(lengthsAddress, i, buffer.remaining());
}
return buffersAddress;
}
/**
* UTF8 encodes the specified strings and ensures space for two additional
* buffers filled with the lengths and memory addresses of the encoded
* strings, respectively. The lengths are pointer-sized integers and the
* memory address buffer starts immediately after the lengths buffer.
*
*
* The encoded buffers must be later freed with
* {@link #pointerArrayFree(int, int)}.
*
* @return the offset to the lengths buffer
*/
public int pointerArrayParamUTF8p(CharSequence... strings) {
int buffersAddress = bufferParam(strings.length << POINTER_SHIFT);
int lengthsAddress = bufferParam(strings.length << POINTER_SHIFT);
for (int i = 0; i < strings.length; i++) {
ByteBuffer buffer = MemoryUtil.memUTF8(strings[i]);
pointerParam(buffersAddress, i, memAddress(buffer));
pointerParam(lengthsAddress, i, buffer.remaining());
}
return buffersAddress;
}
/**
* UTF16 encodes the specified strings with a null-terminator and ensures
* space for a buffer filled with the memory addresses of the encoded
* strings.
*
*
* The encoded buffers must be later freed with
* {@link #pointerArrayFree(int, int)}.
*
* @return the offset to the memory address buffer
*/
public int pointerArrayParamUTF16(CharSequence... strings) {
int buffersAddress = bufferParam(strings.length << POINTER_SHIFT);
for (int i = 0; i < strings.length; i++) {
ByteBuffer buffer = MemoryUtil.memUTF16(strings[i]);
pointerParam(buffersAddress, i, memAddress(buffer));
}
return buffersAddress;
}
/**
* UTF16 encodes the specified strings and ensures space for two additional
* buffers filled with the lengths and memory addresses of the encoded
* strings, respectively. The lengths are 4-bytes integers and the memory
* address buffer starts immediately after the lengths buffer.
*
*
* The encoded buffers must be later freed with
* {@link #pointerArrayFree(int, int)}.
*
* @return the offset to the lengths buffer
*/
public int pointerArrayParamUTF16i(CharSequence... strings) {
int buffersAddress = bufferParam(strings.length << POINTER_SHIFT);
int lengthsAddress = bufferParam(strings.length << 2);
for (int i = 0; i < strings.length; i++) {
ByteBuffer buffer = MemoryUtil.memUTF16(strings[i]);
pointerParam(buffersAddress, i, memAddress(buffer));
intParam(lengthsAddress, i, buffer.remaining());
}
return buffersAddress;
}
/**
* UTF16 encodes the specified strings and ensures space for two additional
* buffers filled with the lengths and memory addresses of the encoded
* strings, respectively. The lengths are pointer-sized integers and the
* memory address buffer starts immediately after the lengths buffer.
*
*
* The encoded buffers must be later freed with
* {@link #pointerArrayFree(int, int)}.
*
* @return the offset to the lengths buffer
*/
public int pointerArrayParamUTF16p(CharSequence... strings) {
int buffersAddress = bufferParam(strings.length << POINTER_SHIFT);
int lengthsAddress = bufferParam(strings.length << POINTER_SHIFT);
for (int i = 0; i < strings.length; i++) {
ByteBuffer buffer = MemoryUtil.memUTF16(strings[i]);
pointerParam(buffersAddress, i, memAddress(buffer));
pointerParam(lengthsAddress, i, buffer.remaining());
}
return buffersAddress;
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* Frees {@code length} memory blocks stored in the APIBuffer, starting at
* the specified {@code offset}.
*/
public void pointerArrayFree(int offset, int length) {
for (int i = 0; i < length; i++) {
nmemFree(pointerValue(offset + (i << POINTER_SHIFT)));
}
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* Sets an int value at the specified index of the int buffer that starts at
* the specified offset.
*/
public void intParam(int offset, int index, int value) {
buffer.putInt(offset + (index << 2), value);
}
/**
* Sets a pointer value at the specified index of the pointer buffer that
* starts at the specified offset.
*/
public void pointerParam(int offset, int index, long value) {
PointerBuffer.put(buffer, offset + (index << POINTER_SHIFT), value);
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* Ensures space for the specified string encoded in ASCII, encodes the
* string at the allocated offset and returns that offset.
*/
public int stringParamASCII(CharSequence value, boolean nullTerminated) {
if (value == null) {
return -1;
}
int offset = bufferParam(value.length() + (nullTerminated ? 1 : 0));
MemoryUtil.memASCII(value, nullTerminated, buffer, offset);
return offset;
}
/**
* Ensures space for the specified string encoded in UTF-8, encodes the
* string at the allocated offset and returns that offset.
*/
public int stringParamUTF8(CharSequence value, boolean nullTerminated) {
if (value == null) {
return -1;
}
int encodedLen = MemoryUtil.memLengthUTF8(value, nullTerminated);
int offset = bufferParam(encodedLen);
MemoryUtil.memUTF8(value, nullTerminated, buffer, offset);
return offset;
}
/**
* Ensures space for the specified string encoded in UTF-16, encodes the
* string at the allocated offset and returns that offset.
*/
public int stringParamUTF16(CharSequence value, boolean nullTerminated) {
if (value == null) {
return -1;
}
int offset = bufferParam((value.length() + (nullTerminated ? 1 : 0)) << 1);
MemoryUtil.memUTF16(value, nullTerminated, buffer, offset);
return offset;
}
// ---------------------------------------------------------------------------------------------------------------------
/**
* Returns the boolean value at the specified offset.
*/
public boolean booleanValue(int offset) {
return buffer.get(offset) != 0;
}
/**
* Returns the boolean value at the specified offset.
*/
public byte byteValue(int offset) {
return buffer.get(offset);
}
/**
* Returns the short value at the specified offset.
*/
public short shortValue(int offset) {
return buffer.getShort(offset);
}
/**
* Returns the int value at the specified offset.
*/
public int intValue(int offset) {
return buffer.getInt(offset);
}
/**
* Returns the long value at the specified offset.
*/
public long longValue(int offset) {
return buffer.getLong(offset);
}
/**
* Returns the float value at the specified offset.
*/
public float floatValue(int offset) {
return buffer.getFloat(offset);
}
/**
* Returns the double value at the specified offset.
*/
public double doubleValue(int offset) {
return buffer.getDouble(offset);
}
/**
* Returns the pointer value at the specified offset.
*/
public long pointerValue(int offset) {
return PointerBuffer.get(buffer, offset);
}
/**
* Returns the ASCII string value at the specified byte range.
*/
public String stringValueASCII(int offset, int limit) {
buffer.position(offset);
buffer.limit(limit);
try {
return MemoryUtil.memASCII(buffer);
} finally {
buffer.clear();
}
}
/**
* Returns the UTF8 string value at the specified byte range.
*/
public String stringValueUTF8(int offset, int limit) {
buffer.position(offset);
buffer.limit(limit);
try {
return MemoryUtil.memUTF8(buffer);
} finally {
buffer.clear();
}
}
/**
* Returns the UTF16 string value at the specified byte range.
*/
public String stringValueUTF16(int offset, int limit) {
buffer.position(offset);
buffer.limit(limit);
try {
return MemoryUtil.memUTF16(buffer);
} finally {
buffer.clear();
}
}
}