package de.geolykt.starloader.impl.gui; import org.jetbrains.annotations.NotNull; import org.lwjgl.opengl.GL11; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL20; /** * A wrapper around GL calls that capture the state of the {@link GL20#GL_SCISSOR_BOX}. * * @since 2.0.0 */ public final class GLScissorState { private static int currentH; private static int currentW; private static int currentX; private static int currentY; private static boolean scissorInit; @NotNull public static GLScissorState captureScissor() { if (!GLScissorState.scissorInit) { GLScissorState.scissorInit = true; GLScissorState.currentX = 0; GLScissorState.currentY = 0; GLScissorState.currentW = Gdx.graphics.getBackBufferWidth(); GLScissorState.currentH = Gdx.graphics.getBackBufferHeight(); } boolean scissorEnabled = Gdx.gl.glIsEnabled(GL20.GL_SCISSOR_TEST); return new GLScissorState(GLScissorState.currentX, GLScissorState.currentY, GLScissorState.currentW, GLScissorState.currentH, scissorEnabled); } /** * Makes the {@link GLScissorState} class "forget" the scissor - which means that the scissor will be at the (0, 0) * coordinates with a width and height defined by the BackBuffer. * * @since 2.0.0 */ public static void forgetScissor() { GLScissorState.scissorInit = false; } /** * Sets the OpenGL scissor. Calls {@link GL11#glScissor(int, int, int, int)}, but also remembers * the arguments it was called with. All {@link GL11#glScissor(int, int, int, int)} calls are delegated * to this method. * * @param x The X-value of the lower left corner of the scissor box * @param y The Y-value of the lower left corner of the scissor box * @param w The width of the scissor box * @param h The height of the scissor box * @since 2.0.0 */ public static final void glScissor(int x, int y, int w, int h) { if (w < 0 || h < 0) { throw new IllegalArgumentException("Width or height has a negative value - which is not permitted! Values: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h); } w = Math.min(w, w + x); x = Math.max(x, 0); h = Math.min(h, h + y); y = Math.max(y, 0); GLScissorState.currentX = x; GLScissorState.currentY = y; GLScissorState.currentW = w; GLScissorState.currentH = h; GL11.glScissor(x, y, w, h); } public final boolean enabled; public final int height; public final int width; public final int x; public final int y; private GLScissorState(int x, int y, int w, int h, boolean enabled) { this.x = x; this.y = y; this.width = w; this.height = h; this.enabled = enabled; } public void reapplyState() { Gdx.gl.glScissor(this.x, this.y, this.width, this.height); if (Gdx.gl.glGetError() == GL20.GL_INVALID_VALUE) { throw new IllegalStateException("Gdx.gl.glScissor raised an GL20.GL_INVALID_VALUE! Scissor state: " + this.toString()); } if (this.enabled) { if (!Gdx.gl.glIsEnabled(GL20.GL_SCISSOR_TEST)) { Gdx.gl.glEnable(GL20.GL_SCISSOR_TEST); } } else if (Gdx.gl.glIsEnabled(GL20.GL_SCISSOR_TEST)) { Gdx.gl.glDisable(GL20.GL_SCISSOR_TEST); } } @Override public String toString() { return String.format("GLScissorState[x = %d (0x%X), y = %d (0x%X), w = %d (0x%X), h = %d (0x%X)]", this.x, this.x, this.y, this.y, this.width, this.width, this.height, this.height); } }