@ -40,6 +40,7 @@ import java.io.UnsupportedEncodingException;
import java.lang.ref.PhantomReference ;
import java.lang.ref.Reference ;
import java.lang.ref.ReferenceQueue ;
import java.lang.reflect.InaccessibleObjectException ;
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.Method ;
import java.nio.Buffer ;
@ -62,24 +63,40 @@ import java.util.logging.Logger;
* @version $Id : BufferUtils . java , v 1 . 16 2007 / 10 / 29 16 : 56 : 18 nca Exp $
* /
public final class BufferUtils {
private static BufferAllocator allocator = new ReflectionBufferUtils ( ) ;
private static BufferAllocator allocator = new PrimitiveAllocator ( ) ;
private static boolean trackDirectMemory = false ;
private static ReferenceQueue < Buffer > removeCollected = new ReferenceQueue < Buffer > ( ) ;
private static ConcurrentHashMap < BufferInfo , BufferInfo > trackedBuffers = new ConcurrentHashMap < BufferInfo , BufferInfo > ( ) ;
static ClearReferences cleanupthread ;
private static boolean used ;
static {
try {
allocator = new ReflectionAllocator ( ) ;
} catch ( InaccessibleObjectException t ) {
t . printStackTrace ( ) ;
System . err . println ( "Error using ReflectionAllocator" ) ;
}
}
/ * *
* Warning ! do only set this before JME is started !
* /
public static void setAllocator ( BufferAllocator allocator ) {
if ( used ) {
throw new IllegalStateException (
"An Buffer was already allocated, since it is quite likely that other dispose methods will create native dangling pointers or other fun things, this is forbidden to be changed at runtime" ) ;
}
BufferUtils . allocator = allocator ;
}
/ * *
* Set it to true if you want to enable direct memory tracking for debugging purpose .
* Default is false .
* To print direct memory usage use BufferUtils . printCurrentDirectMemory ( StringBuilder store ) ;
* Set it to true if you want to enable direct memory tracking for debugging
* purpose . Default is false . To print direct memory usage use
* BufferUtils . printCurrentDirectMemory ( StringBuilder store ) ;
*
* @param enabled
* /
public static void setTrackDirectMemoryEnabled ( boolean enabled ) {
@ -87,10 +104,11 @@ public final class BufferUtils {
}
/ * *
* Creates a clone of the given buffer . The clone ' s capacity is
* equal to the given buffer ' s limit .
* Creates a clone of the given buffer . The clone ' s capacity is equal to the
* given buffer ' s limit .
*
* @param buf The buffer to clone
* @param buf
* The buffer to clone
* @return The cloned buffer
* /
public static Buffer clone ( Buffer buf ) {
@ -110,6 +128,7 @@ public final class BufferUtils {
}
private static void onBufferAllocated ( Buffer buffer ) {
used = true ;
if ( BufferUtils . trackDirectMemory ) {
if ( BufferUtils . cleanupthread = = null ) {
BufferUtils . cleanupthread = new ClearReferences ( ) ;
@ -136,11 +155,12 @@ public final class BufferUtils {
}
/ * *
* Generate a new FloatBuffer using the given array of Vector3f objects .
* The FloatBuffer will be 3 * data . length long and contain the vector data
* as data [ 0 ] . x , data [ 0 ] . y , data [ 0 ] . z , data [ 1 ] . x . . . etc .
* Generate a new FloatBuffer using the given array of Vector3f objects . The
* FloatBuffer will be 3 * data . length long and contain the vector data as
* data [ 0 ] . x , data [ 0 ] . y , data [ 0 ] . z , data [ 1 ] . x . . . etc .
*
* @param data array of Vector3f objects to place into a new FloatBuffer
* @param data
* array of Vector3f objects to place into a new FloatBuffer
* /
public static FloatBuffer createFloatBuffer ( Vector3f . . . data ) {
if ( data = = null ) {
@ -162,7 +182,8 @@ public final class BufferUtils {
* Generate a new FloatBuffer using the given array of Quaternion objects .
* The FloatBuffer will be 4 * data . length long and contain the vector data .
*
* @param data array of Quaternion objects to place into a new FloatBuffer
* @param data
* array of Quaternion objects to place into a new FloatBuffer
* /
public static FloatBuffer createFloatBuffer ( Quaternion . . . data ) {
if ( data = = null ) {
@ -181,10 +202,11 @@ public final class BufferUtils {
}
/ * *
* Generate a new FloatBuffer using the given array of Vector4 objects .
* The FloatBuffer will be 4 * data . length long and contain the vector data .
* Generate a new FloatBuffer using the given array of Vector4 objects . The
* FloatBuffer will be 4 * data . length long and contain the vector data .
*
* @param data array of Vector4 objects to place into a new FloatBuffer
* @param data
* array of Vector4 objects to place into a new FloatBuffer
* /
public static FloatBuffer createFloatBuffer ( Vector4f . . . data ) {
if ( data = = null ) {
@ -206,7 +228,8 @@ public final class BufferUtils {
* Generate a new FloatBuffer using the given array of ColorRGBA objects .
* The FloatBuffer will be 4 * data . length long and contain the color data .
*
* @param data array of ColorRGBA objects to place into a new FloatBuffer
* @param data
* array of ColorRGBA objects to place into a new FloatBuffer
* /
public static FloatBuffer createFloatBuffer ( ColorRGBA . . . data ) {
if ( data = = null ) {
@ -226,7 +249,9 @@ public final class BufferUtils {
/ * *
* Generate a new FloatBuffer using the given array of float primitives .
* @param data array of float primitives to place into a new FloatBuffer
*
* @param data
* array of float primitives to place into a new FloatBuffer
* /
public static FloatBuffer createFloatBuffer ( float . . . data ) {
if ( data = = null ) {
@ -285,8 +310,7 @@ public final class BufferUtils {
* @param index
* the postion to place the data ; in terms of colors not floats
* /
public static void setInBuffer ( ColorRGBA color , FloatBuffer buf ,
int index ) {
public static void setInBuffer ( ColorRGBA color , FloatBuffer buf , int index ) {
buf . position ( index * 4 ) ;
buf . put ( color . r ) ;
buf . put ( color . g ) ;
@ -295,18 +319,18 @@ public final class BufferUtils {
}
/ * *
* Sets the data contained in the given quaternion into the FloatBuffer at the
* specified index .
* Sets the data contained in the given quaternion into the FloatBuffer at
* the specified index .
*
* @param quat
* the { @link Quaternion } to insert
* @param buf
* the buffer to insert into
* @param index
* the position to place the data ; in terms of quaternions not floats
* the position to place the data ; in terms of quaternions not
* floats
* /
public static void setInBuffer ( Quaternion quat , FloatBuffer buf ,
int index ) {
public static void setInBuffer ( Quaternion quat , FloatBuffer buf , int index ) {
buf . position ( index * 4 ) ;
buf . put ( quat . getX ( ) ) ;
buf . put ( quat . getY ( ) ) ;
@ -325,8 +349,7 @@ public final class BufferUtils {
* @param index
* the position to place the data ; in terms of vector4 not floats
* /
public static void setInBuffer ( Vector4f vec , FloatBuffer buf ,
int index ) {
public static void setInBuffer ( Vector4f vec , FloatBuffer buf , int index ) {
buf . position ( index * 4 ) ;
buf . put ( vec . getX ( ) ) ;
buf . put ( vec . getY ( ) ) ;
@ -416,8 +439,8 @@ public final class BufferUtils {
/ * *
* Copies a Vector3f from one position in the buffer to another . The index
* values are in terms of vector number ( eg , vector number 0 is positions 0 - 2
* in the FloatBuffer . )
* values are in terms of vector number ( eg , vector number 0 is positions
* 0 - 2 in the FloatBuffer . )
*
* @param buf
* the buffer to copy from / to
@ -512,11 +535,12 @@ public final class BufferUtils {
// // -- VECTOR2F METHODS -- ////
/ * *
* Generate a new FloatBuffer using the given array of Vector2f objects .
* The FloatBuffer will be 2 * data . length long and contain the vector data
* as data [ 0 ] . x , data [ 0 ] . y , data [ 1 ] . x . . . etc .
* Generate a new FloatBuffer using the given array of Vector2f objects . The
* FloatBuffer will be 2 * data . length long and contain the vector data as
* data [ 0 ] . x , data [ 0 ] . y , data [ 1 ] . x . . . etc .
*
* @param data array of Vector2f objects to place into a new FloatBuffer
* @param data
* array of Vector2f objects to place into a new FloatBuffer
* /
public static FloatBuffer createFloatBuffer ( Vector2f . . . data ) {
if ( data = = null ) {
@ -621,8 +645,8 @@ public final class BufferUtils {
/ * *
* Copies a Vector2f from one position in the buffer to another . The index
* values are in terms of vector number ( eg , vector number 0 is positions 0 - 1
* in the FloatBuffer . )
* values are in terms of vector number ( eg , vector number 0 is positions
* 0 - 1 in the FloatBuffer . )
*
* @param buf
* the buffer to copy from / to
@ -1093,9 +1117,9 @@ public final class BufferUtils {
}
/ * *
* Creates a new ShortBuffer with the same contents as the given ShortBuffer .
* The new ShortBuffer is separate from the old one and changes are not
* reflected across . If you want to reflect changes , consider using
* Creates a new ShortBuffer with the same contents as the given
* ShortBuffer . The new ShortBuffer is separate from the old one and changes
* are not reflected across . If you want to reflect changes , consider using
* Buffer . duplicate ( ) .
*
* @param buf
@ -1120,12 +1144,18 @@ public final class BufferUtils {
}
/ * *
* Ensures there is at least the < code > required < / code > number of entries left after the current position of the
* buffer . If the buffer is too small a larger one is created and the old one copied to the new buffer .
* @param buffer buffer that should be checked / copied ( may be null )
* @param required minimum number of elements that should be remaining in the returned buffer
* @return a buffer large enough to receive at least the < code > required < / code > number of entries , same position as
* the input buffer , not null
* Ensures there is at least the < code > required < / code > number of entries
* left after the current position of the buffer . If the buffer is too small
* a larger one is created and the old one copied to the new buffer .
*
* @param buffer
* buffer that should be checked / copied ( may be null )
* @param required
* minimum number of elements that should be remaining in the
* returned buffer
* @return a buffer large enough to receive at least the
* < code > required < / code > number of entries , same position as the
* input buffer , not null
* /
public static FloatBuffer ensureLargeEnough ( FloatBuffer buffer , int required ) {
if ( buffer ! = null ) {
@ -1161,7 +1191,6 @@ public final class BufferUtils {
return buffer ;
}
public static ShortBuffer ensureLargeEnough ( ShortBuffer buffer , int required ) {
if ( buffer ! = null ) {
buffer . limit ( buffer . capacity ( ) ) ;
@ -1236,7 +1265,8 @@ public final class BufferUtils {
store . append ( "(b: " ) . append ( bBufs ) . append ( " f: " ) . append ( fBufs ) . append ( " i: " ) . append ( iBufs ) . append ( " s: " ) . append ( sBufs ) . append ( " d: " ) . append ( dBufs ) . append ( ")" ) . append ( "\n" ) ;
store . append ( "Total heap memory held: " ) . append ( heapMem / 1024 ) . append ( "kb\n" ) ;
store . append ( "Total direct memory held: " ) . append ( totalHeld / 1024 ) . append ( "kb\n" ) ;
store . append ( "(b: " ) . append ( bBufsM / 1024 ) . append ( "kb f: " ) . append ( fBufsM / 1024 ) . append ( "kb i: " ) . append ( iBufsM / 1024 ) . append ( "kb s: " ) . append ( sBufsM / 1024 ) . append ( "kb d: " ) . append ( dBufsM / 1024 ) . append ( "kb)" ) . append ( "\n" ) ;
store . append ( "(b: " ) . append ( bBufsM / 1024 ) . append ( "kb f: " ) . append ( fBufsM / 1024 ) . append ( "kb i: " ) . append ( iBufsM / 1024 ) . append ( "kb s: " ) . append ( sBufsM / 1024 ) . append ( "kb d: " )
. append ( dBufsM / 1024 ) . append ( "kb)" ) . append ( "\n" ) ;
} else {
store . append ( "Total heap memory held: " ) . append ( heapMem / 1024 ) . append ( "kb\n" ) ;
store . append ( "Only heap memory available, if you want to monitor direct memory use BufferUtils.setTrackDirectMemoryEnabled(true) during initialization." ) . append ( "\n" ) ;
@ -1248,10 +1278,11 @@ public final class BufferUtils {
/ * *
* Direct buffers are garbage collected by using a phantom reference and a
* reference queue . Every once a while , the JVM checks the reference queue and
* cleans the direct buffers . However , as this doesn ' t happen
* immediately after discarding all references to a direct buffer , it ' s
* easy to OutOfMemoryError yourself using direct buffers . * * /
* reference queue . Every once a while , the JVM checks the reference queue
* and cleans the direct buffers . However , as this doesn ' t happen
* immediately after discarding all references to a direct buffer , it ' s easy
* to OutOfMemoryError yourself using direct buffers .
* * /
public static void destroyDirectBuffer ( Buffer toBeDestroyed ) {
if ( ! isDirect ( toBeDestroyed ) ) {
return ;
@ -1260,11 +1291,13 @@ public final class BufferUtils {
}
/ *
* FIXME when java 1 . 5 supprt is dropped - replace calls to this method with Buffer . isDirect
* FIXME when java 1 . 5 supprt is dropped - replace calls to this method with
* Buffer . isDirect
*
* Buffer . isDirect ( ) is only java 6 . Java 5 only have this method on Buffer subclasses :
* FloatBuffer , IntBuffer , ShortBuffer , ByteBuffer , DoubleBuffer , LongBuffer .
* CharBuffer has been excluded as we don ' t use it .
* Buffer . isDirect ( ) is only java 6 . Java 5 only have this method on Buffer
* subclasses : FloatBuffer , IntBuffer , ShortBuffer ,
* ByteBuffer , DoubleBuffer , LongBuffer . CharBuffer has been excluded as we
* don ' t use it .
*
* /
private static boolean isDirect ( Buffer buf ) {