package org.andengine.opengl.util; import java.nio.ByteBuffer; import org.andengine.util.debug.Debug; import org.andengine.util.system.SystemUtils; import android.os.Build; /** * (c) Zynga 2011 * * @author Nicolas Gramlich <ngramlich@zynga.com> * @since 23:06:51 - 11.08.2011 * @see http://code.google.com/p/android/issues/detail?id=11078 * @see http://code.google.com/p/android/issues/detail?id=16941 */ public class BufferUtils { // =========================================================== // Constants // =========================================================== private static final boolean NATIVE_LIB_LOADED; /** Android issue 16941. */ private static final boolean WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY; /** Android issue 16941. */ private static final boolean WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT; static { boolean loadLibrarySuccess; try { System.loadLibrary("andengine"); loadLibrarySuccess = true; } catch (final UnsatisfiedLinkError pUnsatisfiedLinkError) { loadLibrarySuccess = false; } NATIVE_LIB_LOADED = loadLibrarySuccess; if(BufferUtils.NATIVE_LIB_LOADED) { if(SystemUtils.isAndroidVersion(Build.VERSION_CODES.HONEYCOMB, Build.VERSION_CODES.HONEYCOMB_MR2)) { WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT = true; } else { WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT = false; } if(SystemUtils.isAndroidVersionOrLower(Build.VERSION_CODES.FROYO)) { WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY = true; } else { WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY = false; } } else { WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT = false; if(SystemUtils.isAndroidVersion(Build.VERSION_CODES.HONEYCOMB, Build.VERSION_CODES.HONEYCOMB_MR2)) { Debug.w("Creating a " + ByteBuffer.class.getSimpleName() + " will actually allocate 4x the memory than requested!"); } WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY = false; } } // =========================================================== // Fields // =========================================================== // =========================================================== // Constructors // =========================================================== // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== // =========================================================== // Methods // =========================================================== /** * @param pCapacity the capacity of the returned {@link ByteBuffer} in bytes. * @return */ public static ByteBuffer allocateDirectByteBuffer(final int pCapacity) { if(BufferUtils.WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT) { return BufferUtils.jniAllocateDirect(pCapacity); } else { return ByteBuffer.allocateDirect(pCapacity); } } public static void freeDirectByteBuffer(final ByteBuffer pByteBuffer) { if(BufferUtils.WORKAROUND_BYTEBUFFER_ALLOCATE_DIRECT) { BufferUtils.jniFreeDirect(pByteBuffer); } } private native static ByteBuffer jniAllocateDirect(final int pCapacity); private native static void jniFreeDirect(final ByteBuffer pByteBuffer); /** * @param pByteBuffer must be a direct Buffer. * @param pSource * @param pLength to copy in pSource. * @param pOffset in pSource. */ public static void put(final ByteBuffer pByteBuffer, final float[] pSource, final int pLength, final int pOffset) { if(BufferUtils.WORKAROUND_BYTEBUFFER_PUT_FLOATARRAY) { BufferUtils.jniPut(pByteBuffer, pSource, pLength, pOffset); } else { for(int i = pOffset; i < (pOffset + pLength); i++) { pByteBuffer.putFloat(pSource[i]); } } pByteBuffer.position(0); pByteBuffer.limit(pLength << 2); } private native static void jniPut(final ByteBuffer pByteBuffer, final float[] pSource, final int pLength, final int pOffset); public static short getUnsignedByte(final ByteBuffer pByteBuffer) { return (short) (pByteBuffer.get() & 0xFF); } public static void putUnsignedByte(final ByteBuffer pByteBuffer, final int pValue) { pByteBuffer.put((byte) (pValue & 0xFF)); } public static short getUnsignedByte(final ByteBuffer pByteBuffer, final int pPosition) { return (short) (pByteBuffer.get(pPosition) & (short) 0xFF); } public static void putUnsignedByte(final ByteBuffer pByteBuffer, final int pPosition, final int pValue) { pByteBuffer.put(pPosition, (byte) (pValue & 0xFF)); } public static int getUnsignedShort(final ByteBuffer pByteBuffer) { return pByteBuffer.getShort() & 0xFFFF; } public static void putUnsignedShort(final ByteBuffer pByteBuffer, final int pValue) { pByteBuffer.putShort((short) (pValue & 0xFFFF)); } public static int getUnsignedShort(final ByteBuffer pByteBuffer, final int pPosition) { return pByteBuffer.getShort(pPosition) & 0xFFFF; } public static void putUnsignedShort(final ByteBuffer pByteBuffer, final int pPosition, final int pValue) { pByteBuffer.putShort(pPosition, (short) (pValue & 0xFFFF)); } public static long getUnsignedInt(final ByteBuffer pByteBuffer) { return pByteBuffer.getInt() & 0xFFFFFFFFL; } public static void putUnsignedInt(final ByteBuffer pByteBuffer, final long pValue) { pByteBuffer.putInt((int) (pValue & 0xFFFFFFFFL)); } public static long getUnsignedInt(final ByteBuffer pByteBuffer, final int pPosition) { return pByteBuffer.getInt(pPosition) & 0xFFFFFFFFL; } public static void putUnsignedInt(final ByteBuffer pByteBuffer, final int pPosition, final long pValue) { pByteBuffer.putInt(pPosition, (short) (pValue & 0xFFFFFFFFL)); } // =========================================================== // Inner and Anonymous Classes // =========================================================== }