| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180 |
- /*
- * Copyright (c) 2009-2010 jMonkeyEngine
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- package com.jme3.util;
- import com.jme3.math.ColorRGBA;
- import com.jme3.math.Quaternion;
- import com.jme3.math.Vector2f;
- import com.jme3.math.Vector3f;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.nio.*;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Map;
- import java.util.WeakHashMap;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- /**
- * <code>BufferUtils</code> is a helper class for generating nio buffers from
- * jME data classes such as Vectors and ColorRGBA.
- *
- * @author Joshua Slack
- * @version $Id: BufferUtils.java,v 1.16 2007/10/29 16:56:18 nca Exp $
- */
- public final class BufferUtils {
- private static final Map<Buffer, Object> trackingHash = Collections.synchronizedMap(new WeakHashMap<Buffer, Object>());
- private static final Object ref = new Object();
-
- // Note: a WeakHashMap is really bad here since the hashCode() and
- // equals() behavior of buffers will vary based on their contents.
- // As it stands, put()'ing an empty buffer will wipe out the last
- // empty buffer with the same size. So any tracked memory calculations
- // could be lying.
- // Besides, the hashmap behavior isn't even being used here and
- // yet the expense is still incurred. For example, a newly allocated
- // 10,000 byte buffer will iterate through the whole buffer of 0's
- // to calculate the hashCode and then potentially do it again to
- // calculate the equals()... which by the way is guaranteed for
- // every empty buffer of an existing size since they will always produce
- // the same hashCode().
- // It would be better to just keep a straight list of weak references
- // and clean out the dead every time a new buffer is allocated.
- // WeakHashMap is doing that anyway... so there is no extra expense
- // incurred.
- // Recommend a ConcurrentLinkedQueue of WeakReferences since it
- // supports the threading semantics required with little extra overhead.
- private static final boolean trackDirectMemory = false;
- /**
- * 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
- * @return The cloned buffer
- */
- public static Buffer clone(Buffer buf) {
- if (buf instanceof FloatBuffer) {
- return clone((FloatBuffer) buf);
- } else if (buf instanceof ShortBuffer) {
- return clone((ShortBuffer) buf);
- } else if (buf instanceof ByteBuffer) {
- return clone((ByteBuffer) buf);
- } else if (buf instanceof IntBuffer) {
- return clone((IntBuffer) buf);
- } else if (buf instanceof DoubleBuffer) {
- return clone((DoubleBuffer) buf);
- } else {
- throw new UnsupportedOperationException();
- }
- }
-
- private static void onBufferAllocated(Buffer buffer){
- /*
- StackTraceElement[] stackTrace = new Throwable().getStackTrace();
- int initialIndex = 0;
-
- for (int i = 0; i < stackTrace.length; i++){
- if (!stackTrace[i].getClassName().equals(BufferUtils.class.getName())){
- initialIndex = i;
- break;
- }
- }
-
- int allocated = buffer.capacity();
- int size = 0;
-
- if (buffer instanceof FloatBuffer){
- size = 4;
- }else if (buffer instanceof ShortBuffer){
- size = 2;
- }else if (buffer instanceof ByteBuffer){
- size = 1;
- }else if (buffer instanceof IntBuffer){
- size = 4;
- }else if (buffer instanceof DoubleBuffer){
- size = 8;
- }
-
- allocated *= size;
-
- for (int i = initialIndex; i < stackTrace.length; i++){
- StackTraceElement element = stackTrace[i];
- if (element.getClassName().startsWith("java")){
- break;
- }
-
- try {
- Class clazz = Class.forName(element.getClassName());
- if (i == initialIndex){
- System.out.println(clazz.getSimpleName()+"."+element.getMethodName()+"():" + element.getLineNumber() + " allocated " + allocated);
- }else{
- System.out.println(" at " + clazz.getSimpleName()+"."+element.getMethodName()+"()");
- }
- } catch (ClassNotFoundException ex) {
- }
- }*/
-
- if (trackDirectMemory){
- trackingHash.put(buffer, ref);
- }
- }
- /**
- * 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
- */
- public static FloatBuffer createFloatBuffer(Vector3f... data) {
- if (data == null) {
- return null;
- }
- FloatBuffer buff = createFloatBuffer(3 * data.length);
- for (int x = 0; x < data.length; x++) {
- if (data[x] != null) {
- buff.put(data[x].x).put(data[x].y).put(data[x].z);
- } else {
- buff.put(0).put(0).put(0);
- }
- }
- buff.flip();
- return buff;
- }
- /**
- * 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
- */
- public static FloatBuffer createFloatBuffer(Quaternion... data) {
- if (data == null) {
- return null;
- }
- FloatBuffer buff = createFloatBuffer(4 * data.length);
- for (int x = 0; x < data.length; x++) {
- if (data[x] != null) {
- buff.put(data[x].getX()).put(data[x].getY()).put(data[x].getZ()).put(data[x].getW());
- } else {
- buff.put(0).put(0).put(0);
- }
- }
- buff.flip();
- return buff;
- }
- /**
- * Generate a new FloatBuffer using the given array of float primitives.
- * @param data array of float primitives to place into a new FloatBuffer
- */
- public static FloatBuffer createFloatBuffer(float... data) {
- if (data == null) {
- return null;
- }
- FloatBuffer buff = createFloatBuffer(data.length);
- buff.clear();
- buff.put(data);
- buff.flip();
- return buff;
- }
- /**
- * Create a new FloatBuffer of an appropriate size to hold the specified
- * number of Vector3f object data.
- *
- * @param vertices
- * number of vertices that need to be held by the newly created
- * buffer
- * @return the requested new FloatBuffer
- */
- public static FloatBuffer createVector3Buffer(int vertices) {
- FloatBuffer vBuff = createFloatBuffer(3 * vertices);
- return vBuff;
- }
- /**
- * Create a new FloatBuffer of an appropriate size to hold the specified
- * number of Vector3f object data only if the given buffer if not already
- * the right size.
- *
- * @param buf
- * the buffer to first check and rewind
- * @param vertices
- * number of vertices that need to be held by the newly created
- * buffer
- * @return the requested new FloatBuffer
- */
- public static FloatBuffer createVector3Buffer(FloatBuffer buf, int vertices) {
- if (buf != null && buf.limit() == 3 * vertices) {
- buf.rewind();
- return buf;
- }
- return createFloatBuffer(3 * vertices);
- }
- /**
- * Sets the data contained in the given color into the FloatBuffer at the
- * specified index.
- *
- * @param color
- * the data to insert
- * @param buf
- * the buffer to insert into
- * @param index
- * the postion to place the data; in terms of colors not floats
- */
- public static void setInBuffer(ColorRGBA color, FloatBuffer buf,
- int index) {
- buf.position(index * 4);
- buf.put(color.r);
- buf.put(color.g);
- buf.put(color.b);
- buf.put(color.a);
- }
- /**
- * Sets the data contained in the given quaternion into the FloatBuffer at the
- * specified index.
- *
- * @param color
- * the data to insert
- * @param buf
- * the buffer to insert into
- * @param index
- * the postion to place the data; in terms of quaternions not floats
- */
- public static void setInBuffer(Quaternion quat, FloatBuffer buf,
- int index) {
- buf.position(index * 4);
- buf.put(quat.getX());
- buf.put(quat.getY());
- buf.put(quat.getZ());
- buf.put(quat.getW());
- }
- /**
- * Sets the data contained in the given Vector3F into the FloatBuffer at the
- * specified index.
- *
- * @param vector
- * the data to insert
- * @param buf
- * the buffer to insert into
- * @param index
- * the postion to place the data; in terms of vectors not floats
- */
- public static void setInBuffer(Vector3f vector, FloatBuffer buf, int index) {
- if (buf == null) {
- return;
- }
- if (vector == null) {
- buf.put(index * 3, 0);
- buf.put((index * 3) + 1, 0);
- buf.put((index * 3) + 2, 0);
- } else {
- buf.put(index * 3, vector.x);
- buf.put((index * 3) + 1, vector.y);
- buf.put((index * 3) + 2, vector.z);
- }
- }
- /**
- * Updates the values of the given vector from the specified buffer at the
- * index provided.
- *
- * @param vector
- * the vector to set data on
- * @param buf
- * the buffer to read from
- * @param index
- * the position (in terms of vectors, not floats) to read from
- * the buf
- */
- public static void populateFromBuffer(Vector3f vector, FloatBuffer buf, int index) {
- vector.x = buf.get(index * 3);
- vector.y = buf.get(index * 3 + 1);
- vector.z = buf.get(index * 3 + 2);
- }
- /**
- * Generates a Vector3f array from the given FloatBuffer.
- *
- * @param buff
- * the FloatBuffer to read from
- * @return a newly generated array of Vector3f objects
- */
- public static Vector3f[] getVector3Array(FloatBuffer buff) {
- buff.clear();
- Vector3f[] verts = new Vector3f[buff.limit() / 3];
- for (int x = 0; x < verts.length; x++) {
- Vector3f v = new Vector3f(buff.get(), buff.get(), buff.get());
- verts[x] = v;
- }
- return verts;
- }
- /**
- * 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 postions 0-2
- * in the FloatBuffer.)
- *
- * @param buf
- * the buffer to copy from/to
- * @param fromPos
- * the index of the vector to copy
- * @param toPos
- * the index to copy the vector to
- */
- public static void copyInternalVector3(FloatBuffer buf, int fromPos, int toPos) {
- copyInternal(buf, fromPos * 3, toPos * 3, 3);
- }
- /**
- * Normalize a Vector3f in-buffer.
- *
- * @param buf
- * the buffer to find the Vector3f within
- * @param index
- * the position (in terms of vectors, not floats) of the vector
- * to normalize
- */
- public static void normalizeVector3(FloatBuffer buf, int index) {
- TempVars vars = TempVars.get();
- Vector3f tempVec3 = vars.vect1;
- populateFromBuffer(tempVec3, buf, index);
- tempVec3.normalizeLocal();
- setInBuffer(tempVec3, buf, index);
- vars.release();
- }
- /**
- * Add to a Vector3f in-buffer.
- *
- * @param toAdd
- * the vector to add from
- * @param buf
- * the buffer to find the Vector3f within
- * @param index
- * the position (in terms of vectors, not floats) of the vector
- * to add to
- */
- public static void addInBuffer(Vector3f toAdd, FloatBuffer buf, int index) {
- TempVars vars = TempVars.get();
- Vector3f tempVec3 = vars.vect1;
- populateFromBuffer(tempVec3, buf, index);
- tempVec3.addLocal(toAdd);
- setInBuffer(tempVec3, buf, index);
- vars.release();
- }
- /**
- * Multiply and store a Vector3f in-buffer.
- *
- * @param toMult
- * the vector to multiply against
- * @param buf
- * the buffer to find the Vector3f within
- * @param index
- * the position (in terms of vectors, not floats) of the vector
- * to multiply
- */
- public static void multInBuffer(Vector3f toMult, FloatBuffer buf, int index) {
- TempVars vars = TempVars.get();
- Vector3f tempVec3 = vars.vect1;
- populateFromBuffer(tempVec3, buf, index);
- tempVec3.multLocal(toMult);
- setInBuffer(tempVec3, buf, index);
- vars.release();
- }
- /**
- * Checks to see if the given Vector3f is equals to the data stored in the
- * buffer at the given data index.
- *
- * @param check
- * the vector to check against - null will return false.
- * @param buf
- * the buffer to compare data with
- * @param index
- * the position (in terms of vectors, not floats) of the vector
- * in the buffer to check against
- * @return
- */
- public static boolean equals(Vector3f check, FloatBuffer buf, int index) {
- TempVars vars = TempVars.get();
- Vector3f tempVec3 = vars.vect1;
- populateFromBuffer(tempVec3, buf, index);
- boolean eq = tempVec3.equals(check);
- vars.release();
- return eq;
- }
- // // -- 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.
- *
- * @param data array of Vector2f objects to place into a new FloatBuffer
- */
- public static FloatBuffer createFloatBuffer(Vector2f... data) {
- if (data == null) {
- return null;
- }
- FloatBuffer buff = createFloatBuffer(2 * data.length);
- for (int x = 0; x < data.length; x++) {
- if (data[x] != null) {
- buff.put(data[x].x).put(data[x].y);
- } else {
- buff.put(0).put(0);
- }
- }
- buff.flip();
- return buff;
- }
- /**
- * Create a new FloatBuffer of an appropriate size to hold the specified
- * number of Vector2f object data.
- *
- * @param vertices
- * number of vertices that need to be held by the newly created
- * buffer
- * @return the requested new FloatBuffer
- */
- public static FloatBuffer createVector2Buffer(int vertices) {
- FloatBuffer vBuff = createFloatBuffer(2 * vertices);
- return vBuff;
- }
- /**
- * Create a new FloatBuffer of an appropriate size to hold the specified
- * number of Vector2f object data only if the given buffer if not already
- * the right size.
- *
- * @param buf
- * the buffer to first check and rewind
- * @param vertices
- * number of vertices that need to be held by the newly created
- * buffer
- * @return the requested new FloatBuffer
- */
- public static FloatBuffer createVector2Buffer(FloatBuffer buf, int vertices) {
- if (buf != null && buf.limit() == 2 * vertices) {
- buf.rewind();
- return buf;
- }
- return createFloatBuffer(2 * vertices);
- }
- /**
- * Sets the data contained in the given Vector2F into the FloatBuffer at the
- * specified index.
- *
- * @param vector
- * the data to insert
- * @param buf
- * the buffer to insert into
- * @param index
- * the postion to place the data; in terms of vectors not floats
- */
- public static void setInBuffer(Vector2f vector, FloatBuffer buf, int index) {
- buf.put(index * 2, vector.x);
- buf.put((index * 2) + 1, vector.y);
- }
- /**
- * Updates the values of the given vector from the specified buffer at the
- * index provided.
- *
- * @param vector
- * the vector to set data on
- * @param buf
- * the buffer to read from
- * @param index
- * the position (in terms of vectors, not floats) to read from
- * the buf
- */
- public static void populateFromBuffer(Vector2f vector, FloatBuffer buf, int index) {
- vector.x = buf.get(index * 2);
- vector.y = buf.get(index * 2 + 1);
- }
- /**
- * Generates a Vector2f array from the given FloatBuffer.
- *
- * @param buff
- * the FloatBuffer to read from
- * @return a newly generated array of Vector2f objects
- */
- public static Vector2f[] getVector2Array(FloatBuffer buff) {
- buff.clear();
- Vector2f[] verts = new Vector2f[buff.limit() / 2];
- for (int x = 0; x < verts.length; x++) {
- Vector2f v = new Vector2f(buff.get(), buff.get());
- verts[x] = v;
- }
- return verts;
- }
- /**
- * 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 postions 0-1
- * in the FloatBuffer.)
- *
- * @param buf
- * the buffer to copy from/to
- * @param fromPos
- * the index of the vector to copy
- * @param toPos
- * the index to copy the vector to
- */
- public static void copyInternalVector2(FloatBuffer buf, int fromPos, int toPos) {
- copyInternal(buf, fromPos * 2, toPos * 2, 2);
- }
- /**
- * Normalize a Vector2f in-buffer.
- *
- * @param buf
- * the buffer to find the Vector2f within
- * @param index
- * the position (in terms of vectors, not floats) of the vector
- * to normalize
- */
- public static void normalizeVector2(FloatBuffer buf, int index) {
- TempVars vars = TempVars.get();
- Vector2f tempVec2 = vars.vect2d;
- populateFromBuffer(tempVec2, buf, index);
- tempVec2.normalizeLocal();
- setInBuffer(tempVec2, buf, index);
- vars.release();
- }
- /**
- * Add to a Vector2f in-buffer.
- *
- * @param toAdd
- * the vector to add from
- * @param buf
- * the buffer to find the Vector2f within
- * @param index
- * the position (in terms of vectors, not floats) of the vector
- * to add to
- */
- public static void addInBuffer(Vector2f toAdd, FloatBuffer buf, int index) {
- TempVars vars = TempVars.get();
- Vector2f tempVec2 = vars.vect2d;
- populateFromBuffer(tempVec2, buf, index);
- tempVec2.addLocal(toAdd);
- setInBuffer(tempVec2, buf, index);
- vars.release();
- }
- /**
- * Multiply and store a Vector2f in-buffer.
- *
- * @param toMult
- * the vector to multiply against
- * @param buf
- * the buffer to find the Vector2f within
- * @param index
- * the position (in terms of vectors, not floats) of the vector
- * to multiply
- */
- public static void multInBuffer(Vector2f toMult, FloatBuffer buf, int index) {
- TempVars vars = TempVars.get();
- Vector2f tempVec2 = vars.vect2d;
- populateFromBuffer(tempVec2, buf, index);
- tempVec2.multLocal(toMult);
- setInBuffer(tempVec2, buf, index);
- vars.release();
- }
- /**
- * Checks to see if the given Vector2f is equals to the data stored in the
- * buffer at the given data index.
- *
- * @param check
- * the vector to check against - null will return false.
- * @param buf
- * the buffer to compare data with
- * @param index
- * the position (in terms of vectors, not floats) of the vector
- * in the buffer to check against
- * @return
- */
- public static boolean equals(Vector2f check, FloatBuffer buf, int index) {
- TempVars vars = TempVars.get();
- Vector2f tempVec2 = vars.vect2d;
- populateFromBuffer(tempVec2, buf, index);
- boolean eq = tempVec2.equals(check);
- vars.release();
- return eq;
- }
- //// -- INT METHODS -- ////
- /**
- * Generate a new IntBuffer using the given array of ints. The IntBuffer
- * will be data.length long and contain the int data as data[0], data[1]...
- * etc.
- *
- * @param data
- * array of ints to place into a new IntBuffer
- */
- public static IntBuffer createIntBuffer(int... data) {
- if (data == null) {
- return null;
- }
- IntBuffer buff = createIntBuffer(data.length);
- buff.clear();
- buff.put(data);
- buff.flip();
- return buff;
- }
- /**
- * Create a new int[] array and populate it with the given IntBuffer's
- * contents.
- *
- * @param buff
- * the IntBuffer to read from
- * @return a new int array populated from the IntBuffer
- */
- public static int[] getIntArray(IntBuffer buff) {
- if (buff == null) {
- return null;
- }
- buff.clear();
- int[] inds = new int[buff.limit()];
- for (int x = 0; x < inds.length; x++) {
- inds[x] = buff.get();
- }
- return inds;
- }
- /**
- * Create a new float[] array and populate it with the given FloatBuffer's
- * contents.
- *
- * @param buff
- * the FloatBuffer to read from
- * @return a new float array populated from the FloatBuffer
- */
- public static float[] getFloatArray(FloatBuffer buff) {
- if (buff == null) {
- return null;
- }
- buff.clear();
- float[] inds = new float[buff.limit()];
- for (int x = 0; x < inds.length; x++) {
- inds[x] = buff.get();
- }
- return inds;
- }
- //// -- GENERAL DOUBLE ROUTINES -- ////
- /**
- * Create a new DoubleBuffer of the specified size.
- *
- * @param size
- * required number of double to store.
- * @return the new DoubleBuffer
- */
- public static DoubleBuffer createDoubleBuffer(int size) {
- DoubleBuffer buf = ByteBuffer.allocateDirect(8 * size).order(ByteOrder.nativeOrder()).asDoubleBuffer();
- buf.clear();
- onBufferAllocated(buf);
- return buf;
- }
- /**
- * Create a new DoubleBuffer of an appropriate size to hold the specified
- * number of doubles only if the given buffer if not already the right size.
- *
- * @param buf
- * the buffer to first check and rewind
- * @param size
- * number of doubles that need to be held by the newly created
- * buffer
- * @return the requested new DoubleBuffer
- */
- public static DoubleBuffer createDoubleBuffer(DoubleBuffer buf, int size) {
- if (buf != null && buf.limit() == size) {
- buf.rewind();
- return buf;
- }
- buf = createDoubleBuffer(size);
- return buf;
- }
- /**
- * Creates a new DoubleBuffer with the same contents as the given
- * DoubleBuffer. The new DoubleBuffer is seperate from the old one and
- * changes are not reflected across. If you want to reflect changes,
- * consider using Buffer.duplicate().
- *
- * @param buf
- * the DoubleBuffer to copy
- * @return the copy
- */
- public static DoubleBuffer clone(DoubleBuffer buf) {
- if (buf == null) {
- return null;
- }
- buf.rewind();
- DoubleBuffer copy;
- if (buf.isDirect()) {
- copy = createDoubleBuffer(buf.limit());
- } else {
- copy = DoubleBuffer.allocate(buf.limit());
- }
- copy.put(buf);
- return copy;
- }
- //// -- GENERAL FLOAT ROUTINES -- ////
- /**
- * Create a new FloatBuffer of the specified size.
- *
- * @param size
- * required number of floats to store.
- * @return the new FloatBuffer
- */
- public static FloatBuffer createFloatBuffer(int size) {
- FloatBuffer buf = ByteBuffer.allocateDirect(4 * size).order(ByteOrder.nativeOrder()).asFloatBuffer();
- buf.clear();
- onBufferAllocated(buf);
- return buf;
- }
- /**
- * Copies floats from one position in the buffer to another.
- *
- * @param buf
- * the buffer to copy from/to
- * @param fromPos
- * the starting point to copy from
- * @param toPos
- * the starting point to copy to
- * @param length
- * the number of floats to copy
- */
- public static void copyInternal(FloatBuffer buf, int fromPos, int toPos, int length) {
- float[] data = new float[length];
- buf.position(fromPos);
- buf.get(data);
- buf.position(toPos);
- buf.put(data);
- }
- /**
- * Creates a new FloatBuffer with the same contents as the given
- * FloatBuffer. The new FloatBuffer is seperate from the old one and changes
- * are not reflected across. If you want to reflect changes, consider using
- * Buffer.duplicate().
- *
- * @param buf
- * the FloatBuffer to copy
- * @return the copy
- */
- public static FloatBuffer clone(FloatBuffer buf) {
- if (buf == null) {
- return null;
- }
- buf.rewind();
- FloatBuffer copy;
- if (buf.isDirect()) {
- copy = createFloatBuffer(buf.limit());
- } else {
- copy = FloatBuffer.allocate(buf.limit());
- }
- copy.put(buf);
- return copy;
- }
- //// -- GENERAL INT ROUTINES -- ////
- /**
- * Create a new IntBuffer of the specified size.
- *
- * @param size
- * required number of ints to store.
- * @return the new IntBuffer
- */
- public static IntBuffer createIntBuffer(int size) {
- IntBuffer buf = ByteBuffer.allocateDirect(4 * size).order(ByteOrder.nativeOrder()).asIntBuffer();
- buf.clear();
- onBufferAllocated(buf);
- return buf;
- }
- /**
- * Create a new IntBuffer of an appropriate size to hold the specified
- * number of ints only if the given buffer if not already the right size.
- *
- * @param buf
- * the buffer to first check and rewind
- * @param size
- * number of ints that need to be held by the newly created
- * buffer
- * @return the requested new IntBuffer
- */
- public static IntBuffer createIntBuffer(IntBuffer buf, int size) {
- if (buf != null && buf.limit() == size) {
- buf.rewind();
- return buf;
- }
- buf = createIntBuffer(size);
- return buf;
- }
- /**
- * Creates a new IntBuffer with the same contents as the given IntBuffer.
- * The new IntBuffer is seperate from the old one and changes are not
- * reflected across. If you want to reflect changes, consider using
- * Buffer.duplicate().
- *
- * @param buf
- * the IntBuffer to copy
- * @return the copy
- */
- public static IntBuffer clone(IntBuffer buf) {
- if (buf == null) {
- return null;
- }
- buf.rewind();
- IntBuffer copy;
- if (buf.isDirect()) {
- copy = createIntBuffer(buf.limit());
- } else {
- copy = IntBuffer.allocate(buf.limit());
- }
- copy.put(buf);
- return copy;
- }
- //// -- GENERAL BYTE ROUTINES -- ////
- /**
- * Create a new ByteBuffer of the specified size.
- *
- * @param size
- * required number of ints to store.
- * @return the new IntBuffer
- */
- public static ByteBuffer createByteBuffer(int size) {
- ByteBuffer buf = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder());
- buf.clear();
- onBufferAllocated(buf);
- return buf;
- }
- /**
- * Create a new ByteBuffer of an appropriate size to hold the specified
- * number of ints only if the given buffer if not already the right size.
- *
- * @param buf
- * the buffer to first check and rewind
- * @param size
- * number of bytes that need to be held by the newly created
- * buffer
- * @return the requested new IntBuffer
- */
- public static ByteBuffer createByteBuffer(ByteBuffer buf, int size) {
- if (buf != null && buf.limit() == size) {
- buf.rewind();
- return buf;
- }
- buf = createByteBuffer(size);
- return buf;
- }
- public static ByteBuffer createByteBuffer(byte... data) {
- ByteBuffer bb = createByteBuffer(data.length);
- bb.put(data);
- bb.flip();
- return bb;
- }
- public static ByteBuffer createByteBuffer(String data) {
- byte[] bytes = data.getBytes();
- ByteBuffer bb = createByteBuffer(bytes.length);
- bb.put(bytes);
- bb.flip();
- return bb;
- }
- /**
- * Creates a new ByteBuffer with the same contents as the given ByteBuffer.
- * The new ByteBuffer is seperate from the old one and changes are not
- * reflected across. If you want to reflect changes, consider using
- * Buffer.duplicate().
- *
- * @param buf
- * the ByteBuffer to copy
- * @return the copy
- */
- public static ByteBuffer clone(ByteBuffer buf) {
- if (buf == null) {
- return null;
- }
- buf.rewind();
- ByteBuffer copy;
- if (buf.isDirect()) {
- copy = createByteBuffer(buf.limit());
- } else {
- copy = ByteBuffer.allocate(buf.limit());
- }
- copy.put(buf);
- return copy;
- }
- //// -- GENERAL SHORT ROUTINES -- ////
- /**
- * Create a new ShortBuffer of the specified size.
- *
- * @param size
- * required number of shorts to store.
- * @return the new ShortBuffer
- */
- public static ShortBuffer createShortBuffer(int size) {
- ShortBuffer buf = ByteBuffer.allocateDirect(2 * size).order(ByteOrder.nativeOrder()).asShortBuffer();
- buf.clear();
- onBufferAllocated(buf);
- return buf;
- }
- /**
- * Create a new ShortBuffer of an appropriate size to hold the specified
- * number of shorts only if the given buffer if not already the right size.
- *
- * @param buf
- * the buffer to first check and rewind
- * @param size
- * number of shorts that need to be held by the newly created
- * buffer
- * @return the requested new ShortBuffer
- */
- public static ShortBuffer createShortBuffer(ShortBuffer buf, int size) {
- if (buf != null && buf.limit() == size) {
- buf.rewind();
- return buf;
- }
- buf = createShortBuffer(size);
- return buf;
- }
- public static ShortBuffer createShortBuffer(short... data) {
- if (data == null) {
- return null;
- }
- ShortBuffer buff = createShortBuffer(data.length);
- buff.clear();
- buff.put(data);
- buff.flip();
- return buff;
- }
- /**
- * Creates a new ShortBuffer with the same contents as the given ShortBuffer.
- * The new ShortBuffer is seperate from the old one and changes are not
- * reflected across. If you want to reflect changes, consider using
- * Buffer.duplicate().
- *
- * @param buf
- * the ShortBuffer to copy
- * @return the copy
- */
- public static ShortBuffer clone(ShortBuffer buf) {
- if (buf == null) {
- return null;
- }
- buf.rewind();
- ShortBuffer copy;
- if (buf.isDirect()) {
- copy = createShortBuffer(buf.limit());
- } else {
- copy = ShortBuffer.allocate(buf.limit());
- }
- copy.put(buf);
- return copy;
- }
- /**
- * 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 || (buffer.remaining() < required)) {
- int position = (buffer != null ? buffer.position() : 0);
- FloatBuffer newVerts = createFloatBuffer(position + required);
- if (buffer != null) {
- buffer.rewind();
- newVerts.put(buffer);
- newVerts.position(position);
- }
- buffer = newVerts;
- }
- return buffer;
- }
- public static ShortBuffer ensureLargeEnough(ShortBuffer buffer, int required) {
- if (buffer == null || (buffer.remaining() < required)) {
- int position = (buffer != null ? buffer.position() : 0);
- ShortBuffer newVerts = createShortBuffer(position + required);
- if (buffer != null) {
- buffer.rewind();
- newVerts.put(buffer);
- newVerts.position(position);
- }
- buffer = newVerts;
- }
- return buffer;
- }
- public static ByteBuffer ensureLargeEnough(ByteBuffer buffer, int required) {
- if (buffer == null || (buffer.remaining() < required)) {
- int position = (buffer != null ? buffer.position() : 0);
- ByteBuffer newVerts = createByteBuffer(position + required);
- if (buffer != null) {
- buffer.rewind();
- newVerts.put(buffer);
- newVerts.position(position);
- }
- buffer = newVerts;
- }
- return buffer;
- }
- public static void printCurrentDirectMemory(StringBuilder store) {
- long totalHeld = 0;
- // make a new set to hold the keys to prevent concurrency issues.
- ArrayList<Buffer> bufs = new ArrayList<Buffer>(trackingHash.keySet());
- int fBufs = 0, bBufs = 0, iBufs = 0, sBufs = 0, dBufs = 0;
- int fBufsM = 0, bBufsM = 0, iBufsM = 0, sBufsM = 0, dBufsM = 0;
- for (Buffer b : bufs) {
- if (b instanceof ByteBuffer) {
- totalHeld += b.capacity();
- bBufsM += b.capacity();
- bBufs++;
- } else if (b instanceof FloatBuffer) {
- totalHeld += b.capacity() * 4;
- fBufsM += b.capacity() * 4;
- fBufs++;
- } else if (b instanceof IntBuffer) {
- totalHeld += b.capacity() * 4;
- iBufsM += b.capacity() * 4;
- iBufs++;
- } else if (b instanceof ShortBuffer) {
- totalHeld += b.capacity() * 2;
- sBufsM += b.capacity() * 2;
- sBufs++;
- } else if (b instanceof DoubleBuffer) {
- totalHeld += b.capacity() * 8;
- dBufsM += b.capacity() * 8;
- dBufs++;
- }
- }
- long heapMem = Runtime.getRuntime().totalMemory()
- - Runtime.getRuntime().freeMemory();
- boolean printStout = store == null;
- if (store == null) {
- store = new StringBuilder();
- }
- store.append("Existing buffers: ").append(bufs.size()).append("\n");
- 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");
- if (printStout) {
- System.out.println(store.toString());
- }
- }
-
- /**
- * DirectByteBuffers 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 DirectByteBuffers. However, as this doesn't happen
- * immediately after discarding all references to a DirectByteBuffer, it's
- * easy to OutOfMemoryError yourself using DirectByteBuffers. This function
- * explicitly calls the Cleaner method of a DirectByteBuffer.
- *
- * @param toBeDestroyed
- * The DirectByteBuffer that will be "cleaned". Utilizes reflection.
- *
- */
- public static void destroyByteBuffer(ByteBuffer toBeDestroyed) {
- try {
- Method cleanerMethod = toBeDestroyed.getClass().getMethod("cleaner");
- cleanerMethod.setAccessible(true);
- Object cleaner = cleanerMethod.invoke(toBeDestroyed);
- Method cleanMethod = cleaner.getClass().getMethod("clean");
- cleanMethod.setAccessible(true);
- cleanMethod.invoke(cleaner);
- } catch (IllegalAccessException ex) {
- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
- } catch (IllegalArgumentException ex) {
- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
- } catch (InvocationTargetException ex) {
- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
- } catch (NoSuchMethodException ex) {
- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
- } catch (SecurityException ex) {
- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
- }
- }
- }
|