package loon.utils; import java.nio.ByteBuffer; import loon.LSystem; import loon.LTexture; import loon.Support; import loon.canvas.Canvas; import loon.canvas.Image; import loon.canvas.LColor; import loon.canvas.Pixmap; import loon.opengl.GL20; public class GLUtils { private static int currentHardwareBufferID = -1; private static int currentHardwareTextureID = -1; private static int currentSourceBlendMode = -1; private static int currentDestinationBlendMode = -1; private static boolean enableDither = false; private static boolean enableDepthTest = false; private static boolean enablecissorTest = false; private static boolean enableBlend = false; private static boolean enableCulling = false; private static boolean enableTextures = false; public static void reset(final GL20 gl) { GLUtils.reload(); } public static void reload() { GLUtils.currentHardwareBufferID = -1; GLUtils.currentHardwareTextureID = -1; GLUtils.currentSourceBlendMode = -1; GLUtils.currentDestinationBlendMode = -1; GLUtils.currentBlendMode = -1; GLUtils.enableDither = false; GLUtils.enableDepthTest = false; GLUtils.enablecissorTest = false; GLUtils.enableBlend = false; GLUtils.enableCulling = false; GLUtils.enableTextures = false; } public static int nextPOT(int value) { int bit = 0x8000, highest = -1, count = 0; for (int ii = 15; ii >= 0; ii--, bit >>= 1) { if ((value & bit) == 0) continue; count++; if (highest == -1) highest = ii; } return (count > 1) ? (1 << (highest + 1)) : value; } public static int powerOfTwo(int value) { if (value == 0) { return 1; } if ((value & value - 1) == 0) { return value; } value |= value >> 1; value |= value >> 2; value |= value >> 4; value |= value >> 8; value |= value >> 16; return value + 1; } private static int currentBlendMode = -1; public static final int getBlendMode() { return currentBlendMode; } public static final void setBlendMode(GL20 gl, int mode) { if (currentBlendMode == mode) { return; } currentBlendMode = mode; if (gl == null) { return; } if (currentBlendMode == LSystem.MODE_NORMAL) { GLUtils.enableBlend(gl); gl.glColorMask(true, true, true, false); gl.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA); return; } else if (currentBlendMode == LSystem.MODE_SPEED) { GLUtils.enableBlend(gl); gl.glColorMask(true, true, true, true); gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); return; } else if (currentBlendMode == LSystem.MODE_ALPHA_MAP) { GLUtils.disableBlend(gl); gl.glColorMask(false, false, false, true); return; } else if (currentBlendMode == LSystem.MODE_ALPHA_BLEND) { GLUtils.enableBlend(gl); gl.glColorMask(true, true, true, false); gl.glBlendFunc(GL20.GL_DST_ALPHA, GL20.GL_ONE_MINUS_DST_ALPHA); return; } else if (currentBlendMode == LSystem.MODE_COLOR_MULTIPLY) { GLUtils.enableBlend(gl); gl.glColorMask(true, true, true, true); gl.glBlendFunc(GL20.GL_ONE_MINUS_SRC_COLOR, GL20.GL_SRC_COLOR); return; } else if (currentBlendMode == LSystem.MODE_ADD) { GLUtils.enableBlend(gl); gl.glColorMask(true, true, true, true); gl.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE); return; } else if (currentBlendMode == LSystem.MODE_SCREEN) { GLUtils.enableBlend(gl); gl.glColorMask(true, true, true, true); gl.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_COLOR); return; } else if (currentBlendMode == LSystem.MODE_ALPHA_ONE) { GLUtils.enableBlend(gl); gl.glColorMask(true, true, true, true); gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE); return; } else if (currentBlendMode == LSystem.MODE_ALPHA) { GLUtils.enableBlend(gl); gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); return; } else if (currentBlendMode == LSystem.MODE_MASK) { GLUtils.enableBlend(gl); gl.glBlendFunc(GL20.GL_ZERO, GL20.GL_SRC_ALPHA); return; } else if (currentBlendMode == LSystem.MODE_LIGHT) { GLUtils.enableBlend(gl); gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE); return; } else if (currentBlendMode == LSystem.MODE_ALPHA_ADD) { GLUtils.enableBlend(gl); gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_DST_ALPHA); return; } else if (currentBlendMode == LSystem.MODE_MULTIPLY) { GLUtils.enableBlend(gl); gl.glBlendFunc(GL20.GL_DST_COLOR, GL20.GL_ONE_MINUS_SRC_ALPHA); return; } else if (currentBlendMode == LSystem.MODE_NONE) { GLUtils.disableBlend(gl); gl.glColorMask(true, true, true, false); return; } return; } public static void setClearColor(final GL20 gl, float r, float g, float b, float a) { gl.glClearColor(r, g, b, a); gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); } public static void setClearColor(final GL20 gl, LColor c) { GLUtils.setClearColor(gl, c.r, c.g, c.b, c.a); } public static void enablecissorTest(final GL20 gl) { try { if (!GLUtils.enablecissorTest) { GLUtils.enablecissorTest = true; gl.glEnable(GL20.GL_SCISSOR_TEST); } } catch (Throwable e) { } } public static void disablecissorTest(final GL20 gl) { try { if (GLUtils.enablecissorTest) { GLUtils.enablecissorTest = false; gl.glDisable(GL20.GL_SCISSOR_TEST); } } catch (Throwable e) { } } public static void enableBlend(final GL20 gl) { try { if (!GLUtils.enableBlend) { gl.glEnable(GL20.GL_BLEND); GLUtils.enableBlend = true; } } catch (Throwable e) { } } public static void disableBlend(final GL20 gl) { try { if (GLUtils.enableBlend) { gl.glDisable(GL20.GL_BLEND); GLUtils.enableBlend = false; } } catch (Throwable e) { } } public static void disableCulling(final GL20 gl) { try { if (GLUtils.enableCulling) { GLUtils.enableCulling = false; gl.glDisable(GL20.GL_CULL_FACE); } } catch (Throwable e) { } } public static void enableTextures(final GL20 gl) { try { if (!GLUtils.enableTextures) { GLUtils.enableTextures = true; gl.glEnable(GL20.GL_TEXTURE_2D); } } catch (Throwable e) { } } public static void disableTextures(final GL20 gl) { try { if (GLUtils.enableTextures) { GLUtils.enableTextures = false; gl.glDisable(GL20.GL_TEXTURE_2D); } } catch (Throwable e) { } } public static void enableDither(final GL20 gl) { try { if (!GLUtils.enableDither) { GLUtils.enableDither = true; gl.glEnable(GL20.GL_DITHER); } } catch (Throwable e) { } } public static void disableDither(final GL20 gl) { try { if (GLUtils.enableDither) { GLUtils.enableDither = false; gl.glDisable(GL20.GL_DITHER); } } catch (Throwable e) { } } public static void enableDepthTest(final GL20 gl) { try { if (!GLUtils.enableDepthTest) { GLUtils.enableDepthTest = true; gl.glEnable(GL20.GL_DEPTH_TEST); gl.glDepthMask(true); } } catch (Throwable e) { } } public static void disableDepthTest(final GL20 gl) { try { if (GLUtils.enableDepthTest) { GLUtils.enableDepthTest = false; gl.glDisable(GL20.GL_DEPTH_TEST); gl.glDepthMask(false); } } catch (Throwable e) { } } public static void bindBuffer(final GL20 gl, final int hardwareBufferID) { try { if (GLUtils.currentHardwareBufferID != hardwareBufferID) { GLUtils.currentHardwareBufferID = hardwareBufferID; gl.glBindBuffer(GL20.GL_ARRAY_BUFFER, hardwareBufferID); } } catch (Throwable e) { } } public static int getCurrentHardwareTextureID() { return currentHardwareTextureID; } public static void bindTexture(final GL20 gl, final int hardwareTextureID) { try { if (GLUtils.currentHardwareTextureID != hardwareTextureID) { gl.glBindTexture(GL20.GL_TEXTURE_2D, hardwareTextureID); GLUtils.currentHardwareTextureID = hardwareTextureID; } } catch (Throwable e) { } } public static void deleteTexture(GL20 gl, int id) { gl.glDeleteTexture(id); currentHardwareTextureID = -1; } public static void bindTexture(GL20 gl, LTexture tex2d) { if (!tex2d.isLoaded()) { tex2d.loadTexture(); } bindTexture(gl, tex2d.getID()); } public static void blendFunction(final GL20 gl, final int pSourceBlendMode, final int pDestinationBlendMode) { try { if (GLUtils.currentSourceBlendMode != pSourceBlendMode || GLUtils.currentDestinationBlendMode != pDestinationBlendMode) { GLUtils.currentSourceBlendMode = pSourceBlendMode; GLUtils.currentDestinationBlendMode = pDestinationBlendMode; gl.glBlendFunc(pSourceBlendMode, pDestinationBlendMode); } } catch (Throwable e) { } } public static byte[] getFrameBufferRGBAPixels() { final int w = LSystem.viewSize.getWidth(); final int h = LSystem.viewSize.getHeight(); return getFrameBufferPixels(LSystem.base().graphics().gl, 0, 0, w, h, true, true); } public static byte[] getFrameBufferRGBPixels() { final int w = LSystem.viewSize.getWidth(); final int h = LSystem.viewSize.getHeight(); return getFrameBufferPixels(LSystem.base().graphics().gl, 0, 0, w, h, true, false); } public static byte[] getFrameBufferPixels(final GL20 gl, boolean flipY, boolean alpha) { final int w = LSystem.viewSize.getWidth(); final int h = LSystem.viewSize.getHeight(); return getFrameBufferPixels(gl, 0, 0, w, h, flipY, alpha); } public static Pixmap getFrameBufferRGBAPixmap() { return getFrameBufferPixmap(LSystem.base().graphics().gl, 0, 0, (int) (LSystem.viewSize.width * LSystem.getScaleWidth()), (int) (LSystem.viewSize.height * LSystem.getScaleHeight()), true, true); } public static Pixmap getFrameBufferRGBPixmap() { return getFrameBufferPixmap(LSystem.base().graphics().gl, 0, 0, (int) (LSystem.viewSize.width * LSystem.getScaleWidth()), (int) (LSystem.viewSize.height * LSystem.getScaleHeight()), true, false); } public static Pixmap getFrameBufferPixmap(final GL20 gl, int x, int y, int w, int h, boolean flipY, boolean alpha) { Support support = LSystem.base().support(); final Pixmap pixmap = new Pixmap(w, h, alpha); byte[] buffer = getFrameBufferPixels(gl, x, y, w, h, flipY, alpha); if (alpha) { pixmap.convertByteBufferToPixmap(support.getByteBuffer(buffer)); } else { pixmap.convertByteBufferRGBToPixmap(support.getByteBuffer(buffer)); } return pixmap; } public static byte[] getFrameBufferRGBAPixels(final GL20 gl, int x, int y, int w, int h, boolean flipY) { return getFrameBufferPixels(gl, x, y, w, h, flipY, true); } public static byte[] getFrameBufferRGBPixels(final GL20 gl, int x, int y, int w, int h, boolean flipY) { return getFrameBufferPixels(gl, x, y, w, h, flipY, false); } public static byte[] getFrameBufferPixels(final GL20 gl, int x, int y, int w, int h, boolean flipY, boolean alpha) { Support support = LSystem.base().support(); final int bits = alpha ? 4 : 3; final ByteBuffer pixels = support.newByteBuffer(w * h * bits); gl.glPixelStorei(GL20.GL_PACK_ALIGNMENT, 1); gl.glReadPixels(x, y, w, h, alpha ? GL20.GL_RGBA : GL20.GL_RGB, GL20.GL_UNSIGNED_BYTE, pixels); final int numBytes = w * h * bits; byte[] buffer = new byte[numBytes]; if (flipY) { final int numBytesPerLine = w * bits; for (int i = 0; i < h; i++) { pixels.position((h - i - 1) * numBytesPerLine); pixels.get(buffer, i * numBytesPerLine, numBytesPerLine); } } else { pixels.clear(); pixels.get(buffer); } return buffer; } public static Image getFrameBufferRGBImage(int x, int y, int w, int h) { return getFrameBuffeImage(LSystem.base().graphics().gl, x, y, w, h, true, false); } public static Image getFrameBufferRGBAImage(int x, int y, int w, int h) { return getFrameBuffeImage(LSystem.base().graphics().gl, x, y, w, h, true, true); } public static Image getFrameBuffeImage(final GL20 gl, int x, int y, int width, int height, boolean flipY, boolean alpha) { Support support = LSystem.base().support(); final int bits = alpha ? 4 : 3; final ByteBuffer pixels = support.newByteBuffer(width * height * bits); gl.glPixelStorei(GL20.GL_PACK_ALIGNMENT, 1); gl.glReadPixels(x, y, width, height, alpha ? GL20.GL_RGBA : GL20.GL_RGB, GL20.GL_UNSIGNED_BYTE, pixels); int idx = 0; final int[] buffer = new int[width * height]; if (flipY) { final int offset = -width * 2; int rev = width * (height - 1); for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { if (alpha) { int r = pixels.get(idx++) & 0xFF; int g = pixels.get(idx++) & 0xFF; int b = pixels.get(idx++) & 0xFF; int a = pixels.get(idx++) & 0xFF; buffer[rev] = LColor.argb(a, r, g, b); } else { int r = pixels.get(idx++) & 0xFF; int g = pixels.get(idx++) & 0xFF; int b = pixels.get(idx++) & 0xFF; buffer[rev] = LColor.rgb(r, g, b); } rev++; } rev += offset; } } else { int dst = 0; for (int y1 = 0; y1 < height; y1++) { for (int x1 = 0; x1 < width; x1++) { if (alpha) { int r = pixels.get(idx++) & 0xFF; int g = pixels.get(idx++) & 0xFF; int b = pixels.get(idx++) & 0xFF; int a = pixels.get(idx++) & 0xFF; buffer[dst + x1] = LColor.argb(a, r, g, b); } else { int r = pixels.get(idx++) & 0xFF; int g = pixels.get(idx++) & 0xFF; int b = pixels.get(idx++) & 0xFF; buffer[dst + x1] = LColor.rgb(r, g, b); } } dst += width; } } Canvas canvas = Image.createCanvas(width, height); canvas.image.setPixels(buffer, width, height); return canvas.image; } public static Image getScreenshot() { return getScreenshot(0, 0, (int) (LSystem.viewSize.width * LSystem.getScaleWidth()), (int) (LSystem.viewSize.height * LSystem.getScaleHeight()), true); } public static Image getScreenshot(int x, int y, int w, int h) { return getScreenshot(x, y, w, h, true); } public static Image getScreenshot(int x, int y, int w, int h, boolean flipY) { return getFrameBuffeImage(LSystem.base().graphics().gl, x, y, w, h, flipY, LSystem.isDesktop() ? false : true); } }