package org.andengine.opengl.util; import org.andengine.util.exception.AndEngineRuntimeException; import android.opengl.GLES20; /** * TODO Measure performance against regular Java Stack<E> * * (c) 2013 Zynga Inc. * * @author Nicolas Gramlich <ngramlich@zynga.com> * @author Michal Stawinski <michal.stawinski@gmail.com> * @since 14:49:23 - 02.05.2013 */ public class GLScissorStack { // =========================================================== // Constants // =========================================================== public static final int GLSCISSOR_X_INDEX = 0; public static final int GLSCISSOR_Y_INDEX = 1; public static final int GLSCISSOR_WIDTH_INDEX = 2; public static final int GLSCISSOR_HEIGHT_INDEX = 3; public static final int GLSCISSORSTACK_DEPTH_MAX = 32; public static final int GLSCISSOR_SIZE = 4; private static final int GLSCISSORSTACKOFFSET_UNDERFLOW = -1 * GLScissorStack.GLSCISSOR_SIZE; private static final int GLSCISSORSTACKOFFSET_OVERFLOW = GLScissorStack.GLSCISSORSTACK_DEPTH_MAX * GLScissorStack.GLSCISSOR_SIZE; // =========================================================== // Fields // =========================================================== private final int[] mScissorStack = new int[GLScissorStack.GLSCISSORSTACK_DEPTH_MAX * GLScissorStack.GLSCISSOR_SIZE]; private int mScissorStackOffset; // =========================================================== // Constructors // =========================================================== public GLScissorStack() { } // =========================================================== // Constructors // =========================================================== // =========================================================== // Getter & Setter // =========================================================== public int[] getScissor(final int[] pScissors) { if (this.mScissorStackOffset - GLScissorStack.GLSCISSOR_SIZE <= GLScissorStack.GLSCISSORSTACKOFFSET_UNDERFLOW) { throw new GLScissorStackUnderflowException(); } System.arraycopy(this.mScissorStack, this.mScissorStackOffset, pScissors, 0, GLScissorStack.GLSCISSOR_SIZE); return pScissors; } // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== // =========================================================== // Methods // =========================================================== public void glPushScissor(final int pX, final int pY, final int pWidth, final int pHeight) { if (this.mScissorStackOffset + GLScissorStack.GLSCISSOR_SIZE >= GLScissorStack.GLSCISSORSTACKOFFSET_OVERFLOW) { throw new GLScissorStackOverflowException(); } final int x; final int y; final int width; final int height; if (this.mScissorStackOffset == 0) { x = pX; y = pY; width = pWidth; height = pHeight; } else { /* Take the intersection between the current and the new scissor: */ final int currentX = this.mScissorStack[this.mScissorStackOffset - (GLSCISSOR_SIZE - GLSCISSOR_X_INDEX)]; final int currentY = this.mScissorStack[this.mScissorStackOffset - (GLSCISSOR_SIZE - GLSCISSOR_Y_INDEX)]; final int currentWidth = this.mScissorStack[this.mScissorStackOffset - (GLSCISSOR_SIZE - GLSCISSOR_WIDTH_INDEX)]; final int currentHeight = this.mScissorStack[this.mScissorStackOffset - (GLSCISSOR_SIZE - GLSCISSOR_HEIGHT_INDEX)]; final float xMin = Math.max(currentX, pX); final float xMax = Math.min(currentX + currentWidth, pX + pWidth); final float yMin = Math.max(currentY, pY); final float yMax = Math.min(currentY + currentHeight, pY + pHeight); x = (int) xMin; y = (int) yMin; width = (int) (xMax - xMin); height = (int) (yMax - yMin); } this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_X_INDEX] = pX; this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_Y_INDEX] = pY; this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_WIDTH_INDEX] = pWidth; this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_HEIGHT_INDEX] = pHeight; GLES20.glScissor(x, y, width, height); this.mScissorStackOffset += GLScissorStack.GLSCISSOR_SIZE; } public void glPopScissor() { if (this.mScissorStackOffset - GLScissorStack.GLSCISSOR_SIZE <= GLScissorStack.GLSCISSORSTACKOFFSET_UNDERFLOW) { throw new GLScissorStackUnderflowException(); } this.mScissorStackOffset -= GLScissorStack.GLSCISSOR_SIZE; final int x = this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_X_INDEX]; final int y = this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_Y_INDEX]; final int width = this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_WIDTH_INDEX]; final int height = this.mScissorStack[this.mScissorStackOffset + GLSCISSOR_HEIGHT_INDEX]; GLES20.glScissor(x, y, width, height); } public void reset() { this.mScissorStackOffset = 0; } // =========================================================== // Inner and Anonymous Classes // =========================================================== public static class GLScissorStackOverflowException extends AndEngineRuntimeException { // =========================================================== // Constants // =========================================================== private static final long serialVersionUID = 8253962794945142016L; // =========================================================== // Fields // =========================================================== // =========================================================== // Constructors // =========================================================== public GLScissorStackOverflowException() { } // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== // =========================================================== // Methods // =========================================================== // =========================================================== // Inner and Anonymous Classes // =========================================================== } public static class GLScissorStackUnderflowException extends AndEngineRuntimeException { // =========================================================== // Constants // =========================================================== private static final long serialVersionUID = -2962655760038324091L; // =========================================================== // Fields // =========================================================== // =========================================================== // Constructors // =========================================================== public GLScissorStackUnderflowException() { } // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== // =========================================================== // Methods // =========================================================== // =========================================================== // Inner and Anonymous Classes // =========================================================== } }