package electrosphere.renderer; import java.util.HashMap; import java.util.Map; import org.joml.Vector2i; import org.lwjgl.opengl.GL40; import electrosphere.renderer.shader.ShaderProgram; /** * Encapsulates the state of opengl. * The main function of this class is to sit between any consuming classes and opengl. * It can then deduplicate calls based on the state that is already set. */ public class OpenGLState { //the max texture allowed by the current environment int MAX_TEXTURE_WIDTH = 0; //the current viewport dimensions private Vector2i viewport = new Vector2i(0,0); //whether depth test is enabled or not boolean depthTest = false; //the current depth function int depthFunction = -1; //the currently bound texture int boundTexturePointer = 0; int boundTextureType = 0; //the currently active texture int activeTexture = 0; //the currently bound framebuffer int framebufferType = 0; int framebufferPointer = 0; //active shader ShaderProgram activeShader = null; //map of texture units and their corresponding texture pointers Map unitToPointerMap = new HashMap(); /** * Gets the constraints of the current environment (ie how large can the max texture be) */ public void storeCurrentEnvironmentContraints(){ //the array used to store values fetched from opengl int[] intFetchArray = new int[1]; //get max texture size GL40.glGetIntegerv(GL40.GL_MAX_TEXTURE_SIZE, intFetchArray); MAX_TEXTURE_WIDTH = intFetchArray[0]; } /** * Sets the viewport * @param x the width * @param y the height */ public void glViewport(int x, int y){ if(x != viewport.x || y != viewport.y){ viewport.x = x; viewport.y = y; GL40.glViewport(0, 0, viewport.x, viewport.y); } } /** * Gets the viewport's dimensions * @return The viewport's dimensions */ public Vector2i getViewport(){ return viewport; } /** * Sets the depth test * @param depthTest the depth test state */ public void glDepthTest(boolean depthTest){ // if(this.depthTest != depthTest){ this.depthTest = depthTest; if(this.depthTest){ GL40.glEnable(GL40.GL_DEPTH_TEST); } else { GL40.glDisable(GL40.GL_DEPTH_TEST); } // } } /** * Sets the depth function * @param depthFunction The depth function */ public void glDepthFunc(int depthFunction){ if(this.depthFunction != depthFunction){ this.depthFunction = depthFunction; GL40.glDepthFunc(this.depthFunction); } } /** * Sets the active texture * @param texture The active texture */ public void glActiveTexture(int texture){ if(this.activeTexture != texture){ this.activeTexture = texture; GL40.glActiveTexture(this.activeTexture); } } /** * Binds a texture * @param textureType The type of texture * @param textureValue The texture pointer */ public void glBindTexture(int textureType, int texturePointer){ if(this.boundTexturePointer != texturePointer || this.boundTextureType != textureType){ this.boundTextureType = textureType; this.boundTexturePointer = texturePointer; GL40.glBindTexture(this.boundTextureType,this.boundTexturePointer); } } /** * Binds a texture to a given texture unit if the texture hasn't already been bound to that unit * @param textureUnit The texture unit * @param texturePointer The texture pointer * @param textureType the type of texture (2d, 3d, etc) */ public void glBindTextureUnit(int textureUnit, int texturePointer, int textureType){ if(!unitToPointerMap.containsKey(textureUnit) || unitToPointerMap.get(textureUnit)!=texturePointer){ unitToPointerMap.put(textureUnit,texturePointer); GL40.glActiveTexture(textureUnit); GL40.glBindTexture(textureType,texturePointer); } } /** * Binds a framebuffer * @param framebufferType the type of framebuffer (vanilla, renderbuffer, etc) * @param framebufferPointer the pointer to the framebuffer */ public void glBindFramebuffer(int framebufferType, int framebufferPointer){ if(this.framebufferType != framebufferType || this.framebufferPointer != framebufferPointer){ this.framebufferType = framebufferType; this.framebufferPointer = framebufferPointer; GL40.glBindFramebuffer(this.framebufferType,this.framebufferPointer); } } /** * Gets the currently bound framebuffer's pointer * @return The pointer */ public int getBoundFramebuffer(){ return this.framebufferPointer; } /** * Sets the currently active shader program for the renderer * @param renderPipelineState The render pipeline state object * @param program The shader program to bind */ public void setActiveShader(RenderPipelineState renderPipelineState, ShaderProgram program){ if(program != activeShader){ activeShader = program; GL40.glUseProgram(activeShader.getShaderId()); renderPipelineState.setCurrentShaderPointer(activeShader.getShaderId()); } } /** * Gets the active shader program * @return The active shader */ public ShaderProgram getActiveShader(){ return activeShader; } /** * Checks whether the provided shader program is the active shader program * @param program The program to check * @return true if the provided program is the active program, false otherwise */ public boolean isCurrentShader(ShaderProgram program){ return this.activeShader == program; } /** * Gets MAX_TEXTURE_WIDTH * @return MAX_TEXTURE_WIDTH */ public int getMAX_TEXTURE_WIDTH(){ return MAX_TEXTURE_WIDTH; } }