public class

GLHelper

extends Object
package org.andengine.opengl.util;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import org.andengine.opengl.texture.PixelFormat;

import android.graphics.Bitmap;

/**
 * (c) 2010 Nicolas Gramlich
 * (c) 2011 Zynga Inc.
 *
 * @author Nicolas Gramlich
 * @since 18:00:43 - 08.03.2010
 */
public class GLHelper {
	// ===========================================================
	// Constants
	// ===========================================================

	// ===========================================================
	// Fields
	// ===========================================================

	// ===========================================================
	// Methods
	// ===========================================================

	/**
	 * TODO These conversions could be done in native code!
	 */
	public static Buffer getPixels(final Bitmap pBitmap, final PixelFormat pPixelFormat) {
		return GLHelper.getPixels(pBitmap, pPixelFormat, ByteOrder.nativeOrder());
	}

	public static Buffer getPixels(final Bitmap pBitmap, final PixelFormat pPixelFormat, final ByteOrder pByteOrder) {
		final int[] pixelsARGB_8888 = GLHelper.getPixelsARGB_8888(pBitmap);

		switch(pPixelFormat) {
			case RGB_565:
				return ShortBuffer.wrap(GLHelper.convertARGB_8888toRGB_565(pixelsARGB_8888, pByteOrder)); // TODO Is ShortBuffer or IntBuffer faster?
			case RGBA_8888:
				// HACK =(
				final ByteOrder reverseByteOrder = (pByteOrder == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
				return IntBuffer.wrap(GLHelper.convertARGB_8888toRGBA_8888(pixelsARGB_8888, reverseByteOrder));
			case RGBA_4444:
				return ShortBuffer.wrap(GLHelper.convertARGB_8888toRGBA_4444(pixelsARGB_8888, pByteOrder)); // TODO Is ShortBuffer or IntBuffer faster?
			case A_8:
				return ByteBuffer.wrap(GLHelper.convertARGB_8888toA_8(pixelsARGB_8888));
			default:
				throw new IllegalArgumentException("Unexpected " + PixelFormat.class.getSimpleName() + ": '" + pPixelFormat + "'.");
		}
	}

	public static int[] convertARGB_8888toRGBA_8888(final int[] pPixelsARGB_8888) {
		return GLHelper.convertARGB_8888toRGBA_8888(pPixelsARGB_8888, ByteOrder.nativeOrder());
	}

	public static int[] convertARGB_8888toRGBA_8888(final int[] pPixelsARGB_8888, final ByteOrder pByteOrder) {
		if(pByteOrder == ByteOrder.LITTLE_ENDIAN) {
			for(int i = pPixelsARGB_8888.length - 1; i >= 0; i--) {
				final int pixel = pPixelsARGB_8888[i];

				/* [A][R][G][B] to [A][B][G][R] */
				/* From : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
				/* To   : [ A7 A6 A5 A4 A3 A2 A1 A0  |  B7 B6 B5 B4 B3 B2 B1 B0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  R7 R6 R5 R4 R3 R2 R1 R0 ] */
				pPixelsARGB_8888[i] = (pixel & 0xFF00FF00) | ((pixel << 16) & 0x00FF0000) | ((pixel >> 16) & 0x000000FF);
			}
		} else {
			for(int i = pPixelsARGB_8888.length - 1; i >= 0; i--) {
				final int pixel = pPixelsARGB_8888[i];

				/* [A][R][G][B] to [R][G][B][A] */
				/* From : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
				/* To   : [ R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0  |  A7 A6 A5 A4 A3 A2 A1 A0 ] */
				pPixelsARGB_8888[i] = ((pixel << 8) & 0xFFFFFF00) | ((pixel >> 24) & 0x000000FF);
			}
		}
		return pPixelsARGB_8888;
	}

	public static short[] convertARGB_8888toRGB_565(final int[] pPixelsARGB_8888) {
		return GLHelper.convertARGB_8888toRGB_565(pPixelsARGB_8888, ByteOrder.nativeOrder());
	}

	public static short[] convertARGB_8888toRGB_565(final int[] pPixelsARGB_8888, final ByteOrder pByteOrder) {
		final short[] pixelsRGB_565 = new short[pPixelsARGB_8888.length];
		if(pByteOrder == ByteOrder.LITTLE_ENDIAN) {
			for(int i = pPixelsARGB_8888.length - 1; i >= 0; i--) {
				final int pixel = pPixelsARGB_8888[i];

				/* [A][R][G][B] to [GB][RG] */
				/* From : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
				/* To   :                                                         [ G4 G3 G2 B7 B6 B5 B4 B5  |  R7 R6 R5 R4 R3 G7 G6 G5 ] */

				/* pixelsRGB_565[i] = (short)(red | green | blue); */
				pixelsRGB_565[i] = (short)(((pixel >> 16) & 0x00F8) | ((pixel >> 13) & 0x07) | ((pixel << 3) & 0xE000) | ((pixel << 5) & 0x1F00));
			}
		} else {
			for(int i = pPixelsARGB_8888.length - 1; i >= 0; i--) {
				final int pixel = pPixelsARGB_8888[i];

				/* [A][R][G][B] to [RG][GB] */
				/* From : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
				/* To   :                                                         [ R7 R6 R5 R4 R3 G7 G6 G5  |  G4 G3 G2 B7 B6 B5 B4 B3 ] */

				/* pixelsRGB_565[i] = (short)(red | green | blue); */
				pixelsRGB_565[i] = (short)(((pixel >> 8) & 0xF800) | ((pixel >> 5) & 0x07E0) | ((pixel >> 3) & 0x001F));
			}
		}
		return pixelsRGB_565;
	}

	public static short[] convertARGB_8888toRGBA_4444(final int[] pPixelsARGB_8888) {
		return GLHelper.convertARGB_8888toRGBA_4444(pPixelsARGB_8888, ByteOrder.nativeOrder());
	}

	public static short[] convertARGB_8888toRGBA_4444(final int[] pPixelsARGB_8888, final ByteOrder pByteOrder) {
		final short[] pixelsRGBA_4444 = new short[pPixelsARGB_8888.length];
		if(pByteOrder == ByteOrder.LITTLE_ENDIAN) {
			for(int i = pPixelsARGB_8888.length - 1; i >= 0; i--) {
				final int pixel = pPixelsARGB_8888[i];

				/* [A][R][G][B] to [BA][RG] */
				/* From : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
				/* To   :                                                         [ B7 B6 B5 B4 A7 A6 A5 A4  |  R7 R6 R5 R4 G7 G6 G5 G4 ] */

				/* pixelsRGBA_4444[i] = (short)(red | green | blue | alpha) */
				pixelsRGBA_4444[i] = (short)(((pixel >> 16) & 0x00F0) | ((pixel >> 12) & 0x000F) | ((pixel << 8) & 0xF000) | ((pixel >> 20) & 0x0F00));
			}
		} else {
			for(int i = pPixelsARGB_8888.length - 1; i >= 0; i--) {
				final int pixel = pPixelsARGB_8888[i];

				/* [A][R][G][B] to [RG][BA] */
				/* From : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
				/* To   :                                                         [ R7 R6 R5 R4 G7 G6 G5 G4  |  B7 B6 B5 B4 A7 A6 A5 A4 ] */

				/* pixelsRGBA_4444[i] = (short)(red | green | blue | alpha) */
				pixelsRGBA_4444[i] = (short)(((pixel >> 8) & 0xF000) | ((pixel >> 4) & 0x0F00) | ((pixel) & 0x00F0) | ((pixel >> 28) & 0x0000F));
			}
		}
		return pixelsRGBA_4444;
	}

	public static byte[] convertARGB_8888toA_8(final int[] pPixelsARGB_8888) {
		final byte[] pixelsA_8 = new byte[pPixelsARGB_8888.length];
		for(int i = pPixelsARGB_8888.length - 1; i >= 0; i--) {
			/* [A][R][G][B] to [A] */
			/* From : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
			/* To   :                                                                                     [ A7 A6 A5 A4 A3 A2 A1 A0 ] */
			pixelsA_8[i] = (byte) ((pPixelsARGB_8888[i] >> 24) & 0xFF);
		}
		return pixelsA_8;
	}

	public static int[] getPixelsARGB_8888(final Bitmap pBitmap) {
		final int w = pBitmap.getWidth();
		final int h = pBitmap.getHeight();

		final int[] pixelsARGB_8888 = new int[w * h];
		pBitmap.getPixels(pixelsARGB_8888, 0, w, 0, 0, w, h);

		return pixelsARGB_8888;
	}

	public static int[] convertRGBA_8888toARGB_8888(final int[] pPixelsRGBA_8888) {
		return GLHelper.convertRGBA_8888toARGB_8888(pPixelsRGBA_8888, ByteOrder.nativeOrder());
	}

	public static int[] convertRGBA_8888toARGB_8888(final int[] pPixelsRGBA_8888, final ByteOrder pByteOrder) {
		if(pByteOrder == ByteOrder.LITTLE_ENDIAN) {
			for(int i = pPixelsRGBA_8888.length - 1; i >= 0; i--) {
				final int pixel = pPixelsRGBA_8888[i];
				/* [A][B][G][R] to [A][R][G][B] */
				/* From : [ A7 A6 A5 A4 A3 A2 A1 A0  |  B7 B6 B5 B4 B3 B2 B1 B0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  R7 R6 R5 R4 R3 R2 R1 R0 ] */
				/* To   : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
				pPixelsRGBA_8888[i] = (pixel & 0xFF00FF00) | ((pixel << 16) & 0x00FF0000) | ((pixel >> 16) & 0x000000FF);
			}
		} else {
			for(int i = pPixelsRGBA_8888.length - 1; i >= 0; i--) {
				final int pixel = pPixelsRGBA_8888[i];
				/* [R][G][B][A] to [A][R][G][B] */
				/* From : [ R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0  |  A7 A6 A5 A4 A3 A2 A1 A0 ] */
				/* To   : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
				pPixelsRGBA_8888[i] = ((pixel >> 8) & 0x00FFFFFF) | ((pixel << 24) & 0xFF000000);
			}
		}
		return pPixelsRGBA_8888;
	}

	public static int[] convertRGBA_8888toARGB_8888_FlippedVertical(final int[] pPixelsRGBA_8888, final int pWidth, final int pHeight) {
		return GLHelper.convertRGBA_8888toARGB_8888_FlippedVertical(pPixelsRGBA_8888, pWidth, pHeight, ByteOrder.nativeOrder());
	}

	public static int[] convertRGBA_8888toARGB_8888_FlippedVertical(final int[] pPixelsRGBA_8888, final int pWidth, final int pHeight, final ByteOrder pByteOrder) {
		final int[] pixelsARGB_8888 = new int[pWidth * pHeight];

		if(pByteOrder == ByteOrder.LITTLE_ENDIAN) {
			for(int y = 0; y < pHeight; y++) {
				for(int x = 0; x < pWidth; x++) {
					final int pixel = pPixelsRGBA_8888[x + (y * pWidth)];
					/* [A][B][G][R] to [A][R][G][B] */
					/* From : [ A7 A6 A5 A4 A3 A2 A1 A0  |  B7 B6 B5 B4 B3 B2 B1 B0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  R7 R6 R5 R4 R3 R2 R1 R0 ] */
					/* To   : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
					pixelsARGB_8888[x + ((pHeight - y - 1) * pWidth)] = (pixel & 0xFF00FF00) | ((pixel << 16) & 0x00FF0000) | ((pixel >> 16) & 0x000000FF);
				}
			}
		} else {
			for(int y = 0; y < pHeight; y++) {
				for(int x = 0; x < pWidth; x++) {
					final int pixel = pPixelsRGBA_8888[x + (y * pWidth)];
					/* [R][G][B][A] to [A][R][G][B] */
					/* From : [ R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0  |  A7 A6 A5 A4 A3 A2 A1 A0 ] */
					/* To   : [ A7 A6 A5 A4 A3 A2 A1 A0  |  R7 R6 R5 R4 R3 R2 R1 R0  |  G7 G6 G5 G4 G3 G2 G1 G0  |  B7 B6 B5 B4 B3 B2 B1 B0 ] */
					pixelsARGB_8888[x + ((pHeight - y - 1) * pWidth)] = ((pixel >> 8) & 0x00FFFFFF) | ((pixel << 24) & 0xFF000000);
				}
			}
		}
		return pixelsARGB_8888;
	}

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}