package electrosphere.renderer; import static electrosphere.renderer.RenderUtils.createScreenTextureVAO; import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA; import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA; import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER; import static org.lwjgl.opengl.GL30.GL_RENDERBUFFER; import static org.lwjgl.opengl.GL30.glBindRenderbuffer; import static org.lwjgl.system.MemoryUtil.NULL; import java.nio.IntBuffer; import org.joml.Matrix4d; import org.joml.Vector3d; import org.lwjgl.BufferUtils; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWErrorCallback; import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GL45; import org.lwjgl.opengl.GLDebugMessageCallback; import org.lwjgl.system.MemoryStack; import electrosphere.engine.Globals; import electrosphere.engine.signal.Signal.SignalType; import electrosphere.logger.LoggerInterface; import electrosphere.renderer.debug.DebugRendering; import electrosphere.renderer.framebuffer.Framebuffer; import electrosphere.renderer.framebuffer.FramebufferUtils; import electrosphere.renderer.framebuffer.Renderbuffer; import electrosphere.renderer.light.LightManager; import electrosphere.renderer.pipelines.CompositePipeline; import electrosphere.renderer.pipelines.FirstPersonItemsPipeline; import electrosphere.renderer.pipelines.ImGuiPipeline; import electrosphere.renderer.pipelines.MainContentNoOITPipeline; import electrosphere.renderer.pipelines.MainContentPipeline; import electrosphere.renderer.pipelines.NormalsForOutlinePipeline; import electrosphere.renderer.pipelines.OutlineNormalsPipeline; import electrosphere.renderer.pipelines.PostProcessingPipeline; import electrosphere.renderer.pipelines.RenderScreenPipeline; import electrosphere.renderer.pipelines.ShadowMapPipeline; import electrosphere.renderer.pipelines.UIPipeline; import electrosphere.renderer.pipelines.VolumeBufferPipeline; import electrosphere.renderer.pipelines.debug.DebugContentPipeline; import electrosphere.renderer.shader.VisualShader; import electrosphere.renderer.texture.Texture; public class RenderingEngine { public static final int GL_DEFAULT_FRAMEBUFFER = 0; public static final int GL_DEFAULT_RENDERBUFFER = 0; public static Texture screenTextureColor; public static Texture screenTextureDepth; public static Framebuffer screenFramebuffer; public static Renderbuffer screenRenderbuffer; public static int screenTextureVAO; public static VisualShader screenTextureShaders; public static VisualShader drawChannel; public Framebuffer defaultFramebuffer; //the version of glsl to init imgui with private static String glslVersion = null; //shadow stuff public static Texture lightBufferDepthTexture; //depth framebuffer/shader for shadow mapping public static VisualShader lightDepthShaderProgram; public static Framebuffer lightDepthBuffer; //framebuffers for transparent textures public static float[] transparencyAccumulatorClear; public static Texture transparencyAccumulatorTexture; public static float[] transparencyRevealageClear; public static Texture transparencyRevealageTexture; public static Framebuffer transparencyBuffer; public static VisualShader oitCompositeProgram; /* render normals */ public static Texture gameImageNormalsTexture; public static Framebuffer gameImageNormalsFramebuffer; public static VisualShader renderNormalsShader; /* Perspective volumetrics */ public static Matrix4d nearVolumeProjectionMatrix = new Matrix4d(); public static Matrix4d midVolumeProjectionMatrix = new Matrix4d(); public static Matrix4d farVolumeProjectionMatrix = new Matrix4d(); public static VisualShader volumeDepthShaderProgram; public static Framebuffer volumeDepthBackfaceFramebuffer; public static Texture volumeDepthBackfaceTexture; public static Framebuffer volumeDepthFrontfaceFramebuffer; public static Texture volumeDepthFrontfaceTexture; public static float volumeDepthLinearCoef = 0.1f; public static float volumeDepthQuadCoef = 0.01f; /* Necessary static variables for drawing */ public static Matrix4d modelTransformMatrix = new Matrix4d(); /* Vertical volumetrics TODO: implement */ // static Texture volumeVerticalBackfaceTexture; // static Framebuffer volumeVerticalBackfaceBuffer; // static Texture volumeVerticalFrontfaceTexture; // static Framebuffer volumeVerticalFrontfaceBuffer; /* Post processing effects (ie kernels) textures, framebuffers, shaders */ public static Texture normalsOutlineTexture; public static Framebuffer normalsOutlineFrambuffer; public static VisualShader normalsOutlineShader; /* compositing functions */ public static VisualShader compositeAnimeOutline; // public static boolean renderHitboxes = false; // public static boolean renderPhysics = false; LightManager lightManager; public static int outputFramebuffer = 0; //used in calculating projection matrix static float aspectRatio = 1.0f; static float verticalFOV = 90.0f; //the current state of the rendering pipeline static RenderPipelineState renderPipelineState = new RenderPipelineState(); //the opengl state static OpenGLState openGLState = new OpenGLState(); /** * The opengl context the rendering engine is running within */ OpenGLContext openGLContext; //render pipelines MainContentPipeline mainContentPipeline = new MainContentPipeline(); MainContentNoOITPipeline mainContentNoOITPipeline = new MainContentNoOITPipeline(); DebugContentPipeline debugContentPipeline = new DebugContentPipeline(); FirstPersonItemsPipeline firstPersonItemsPipeline = new FirstPersonItemsPipeline(); ShadowMapPipeline shadowMapPipeline = new ShadowMapPipeline(); VolumeBufferPipeline volumeBufferPipeline = new VolumeBufferPipeline(); NormalsForOutlinePipeline normalsForOutlinePipeline = new NormalsForOutlinePipeline(); OutlineNormalsPipeline outlineNormalsPipeline = new OutlineNormalsPipeline(); CompositePipeline compositePipeline = new CompositePipeline(); PostProcessingPipeline postProcessingPipeline = new PostProcessingPipeline(); UIPipeline uiPipeline = new UIPipeline(); RenderScreenPipeline renderScreenPipeline = new RenderScreenPipeline(); ImGuiPipeline imGuiPipeline; public void createOpenglContext(){ LoggerInterface.loggerRenderer.INFO("Create OpenGL Context"); // //set error callback // GLFW.glfwSetErrorCallback((int error, long descriptionPtr) -> { String description = GLFWErrorCallback.getDescription(descriptionPtr); System.err.println(description); }); //Initializes opengl boolean glfwInited = GLFW.glfwInit(); if(!glfwInited){ String message = "Failed to initialize glfw!\n" + "Error code: " + this.getGLFWErrorMessage(this.getGLFWError()); throw new IllegalStateException(message); } //Gives hints to glfw to control how opengl will be used GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4); GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 5); glslVersion = "#version 450"; GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE); //headless option if(Globals.RUN_HIDDEN){ GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE); } if(!Globals.WINDOW_DECORATED){ GLFW.glfwWindowHint(GLFW.GLFW_DECORATED, GLFW.GLFW_FALSE); } if(Globals.ENGINE_DEBUG){ GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, GLFW.GLFW_TRUE); } if(Globals.userSettings.getDisplayWidth() <= 0 || Globals.userSettings.getDisplayHeight() <= 0){ throw new Error("Trying to create window with width or height less than 1! " + Globals.userSettings.getDisplayWidth() + " " + Globals.userSettings.getDisplayHeight()); } //Creates the window reference object if(Globals.userSettings.displayFullscreen() || Globals.WINDOW_FULLSCREEN){ //below line is for fullscreen Globals.window = GLFW.glfwCreateWindow(Globals.userSettings.getDisplayWidth(), Globals.userSettings.getDisplayHeight(), "ORPG", GLFW.glfwGetPrimaryMonitor(), NULL); } else { Globals.window = GLFW.glfwCreateWindow(Globals.userSettings.getDisplayWidth(), Globals.userSettings.getDisplayHeight(), "ORPG", NULL, NULL); } // Errors for failure to create window (IE: No GUI mode on linux ?) if (Globals.window == NULL) { String message = "Failed to create window!\n" + "Error code: " + this.getGLFWErrorMessage(this.getGLFWError()); ; GLFW.glfwTerminate(); throw new Error(message); } //set resize callback GLFW.glfwSetWindowSizeCallback(Globals.window, (long window, int width, int height) -> { Globals.WINDOW_HEIGHT = height; Globals.WINDOW_WIDTH = width; }); //Makes the window that was just created the current OS-level window context GLFW.glfwMakeContextCurrent(Globals.window); //Maximize it GLFW.glfwMaximizeWindow(Globals.window); GLFW.glfwPollEvents(); //grab actual framebuffer IntBuffer xBuffer = BufferUtils.createIntBuffer(1); IntBuffer yBuffer = BufferUtils.createIntBuffer(1); GLFW.glfwGetFramebufferSize(Globals.window, xBuffer, yBuffer); int bufferWidth = xBuffer.get(); int bufferHeight = yBuffer.get(); //get title bar size Globals.WINDOW_TITLE_BAR_HEIGHT = Globals.WINDOW_HEIGHT - bufferHeight; Globals.WINDOW_WIDTH = bufferWidth; Globals.WINDOW_HEIGHT = bufferHeight; if(bufferWidth == 0 || bufferHeight == 0){ throw new Error("Failed to get width or height! " + Globals.WINDOW_WIDTH + " " + Globals.WINDOW_HEIGHT); } // // Attach controls callbacks // //set key callback GLFW.glfwSetKeyCallback(Globals.window, Globals.controlCallback); GLFW.glfwSetMouseButtonCallback(Globals.window, Globals.mouseCallback); GLFW.glfwSetScrollCallback(Globals.window, Globals.scrollCallback); //get title bar dimensions // setTitleBarDimensions(); //Creates the OpenGL capabilities for the program.) GL.createCapabilities(); GL45.glEnable(GL45.GL_DEBUG_OUTPUT); //register error callback GL45.glDebugMessageCallback((int source, int type, int id, int severity, int length, long messagePtr, long userParam) -> { if(type == GL45.GL_DEBUG_TYPE_ERROR){ String message = GLDebugMessageCallback.getMessage(length, messagePtr); System.err.println(message); } }, bufferHeight); //get environment constraints openGLState.init(); openGLContext = new OpenGLContext(); //init imgui pipeline imGuiPipeline = new ImGuiPipeline(Globals.window, glslVersion); //This enables Z-buffering so that farther-back polygons are not drawn over nearer ones openGLState.glDepthTest(true); // Support for transparency openGLState.glBlend(true); openGLState.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //this disables vsync to make game run faster //https://stackoverflow.com/questions/55598376/glfwswapbuffers-is-slow if(!Globals.userSettings.graphicsPerformanceEnableVSync()){ GLFW.glfwSwapInterval(0); } //clear screen GL45.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); GL45.glClear(GL45.GL_COLOR_BUFFER_BIT | GL45.GL_DEPTH_BUFFER_BIT); // //Hide the cursor and capture it // glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); //init screen rendering quadrant screenTextureVAO = createScreenTextureVAO(); // initScreenTextureShaderProgram(); screenTextureShaders = VisualShader.loadSpecificShader("/Shaders/core/screentexture/simple1/simple1.vs", "/Shaders/core/screentexture/simple1/simple1.fs"); // screenTextureShaders = ShaderProgram.loadSpecificShader("/Shaders/screentexture/drawDepthBuffer/drawDepthBuffer.vs", "/Shaders/screentexture/drawDepthBuffer/drawDepthBuffer.fs"); //default framebuffer defaultFramebuffer = new Framebuffer(GL_DEFAULT_FRAMEBUFFER); //generate framebuffers Texture screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); RenderingEngine.screenTextureColor = screenTextureColor; Texture screenTextureDepth = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); RenderingEngine.screenTextureDepth = screenTextureDepth; try { Framebuffer screenFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, screenTextureColor, screenTextureDepth); RenderingEngine.screenFramebuffer = screenFramebuffer; } catch (Exception e){ LoggerInterface.loggerRenderer.ERROR(e); } defaultFramebuffer.bind(openGLState); glBindRenderbuffer(GL_RENDERBUFFER, GL_DEFAULT_RENDERBUFFER); Globals.renderingEngine.checkError(); // //Channel debug program // drawChannel = VisualShader.loadSpecificShader("/Shaders/core/screentexture/drawChannel/drawChannel.vs", "/Shaders/core/screentexture/drawChannel/drawChannel.fs"); // //create light depth framebuffer/shader for shadowmapping // lightDepthShaderProgram = VisualShader.loadSpecificShader("/Shaders/core/lightDepth/lightDepth.vs", "/Shaders/core/lightDepth/lightDepth.fs"); Globals.depthMapShaderProgramLoc = lightDepthShaderProgram.getId(); try { Framebuffer lightDepthBuffer = FramebufferUtils.generateDepthBuffer(openGLState); RenderingEngine.lightDepthBuffer = lightDepthBuffer; } catch(Exception e){ LoggerInterface.loggerRenderer.ERROR(e); } Texture lightBufferDepthTexture = lightDepthBuffer.getDepthTexture(); RenderingEngine.lightBufferDepthTexture = lightBufferDepthTexture; // glEnable(GL_CULL_FACE); // enabled for shadow mapping // //create volume depth framebuffer/shader for volumetric rendering // try { volumeDepthShaderProgram = VisualShader.loadSpecificShader("/Shaders/core/volumeBuffer/volumetric.vs", "/Shaders/core/volumeBuffer/volumetric.fs"); volumeDepthBackfaceTexture = FramebufferUtils.generateDepthBufferTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY()); volumeDepthBackfaceFramebuffer = FramebufferUtils.generateDepthBuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), volumeDepthBackfaceTexture); volumeDepthFrontfaceTexture = FramebufferUtils.generateDepthBufferTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY()); volumeDepthFrontfaceFramebuffer = FramebufferUtils.generateDepthBuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), volumeDepthFrontfaceTexture); } catch(Exception e){ LoggerInterface.loggerRenderer.ERROR(e); } // //Game normals // /* gameImageNormalsTexture; static Framebuffer gameImageNormalsFramebuffer; static ShaderProgram renderNormalsShader; */ try { gameImageNormalsTexture = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY()); Texture gameImageNormalsDepthTexture = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY()); gameImageNormalsFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), gameImageNormalsTexture, gameImageNormalsDepthTexture); renderNormalsShader = VisualShader.loadSpecificShader("Shaders/core/anime/renderNormals.vs", "Shaders/core/anime/renderNormals.fs"); } catch(Exception e){ LoggerInterface.loggerRenderer.ERROR(e); } // //Transparency framebuffers // try { transparencyAccumulatorClear = new float[]{0.0f, 0.0f, 0.0f, 0.0f}; transparencyAccumulatorTexture = FramebufferUtils.generateOITAccumulatorTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY()); transparencyRevealageClear = new float[]{1.0f, 1.0f, 1.0f, 1.0f}; transparencyRevealageTexture = FramebufferUtils.generateOITRevealageTexture(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY()); transparencyBuffer = FramebufferUtils.generateOITFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), transparencyAccumulatorTexture, transparencyRevealageTexture, screenTextureDepth); oitCompositeProgram = VisualShader.loadSpecificShader("Shaders/core/oit/composite.vs", "Shaders/core/oit/composite.fs"); } catch(Exception e){ LoggerInterface.loggerRenderer.ERROR(e); } //projection matrices nearVolumeProjectionMatrix.setPerspective((float)(Globals.verticalFOV * Math.PI /180.0f), (float)Globals.WINDOW_WIDTH / (float)Globals.WINDOW_HEIGHT, 0.1f, 100); // //Compositing textures and buffers // try { normalsOutlineTexture = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY()); normalsOutlineFrambuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), normalsOutlineTexture); // normalsOutlineShader = ShaderProgram.loadSpecificShader("Shaders/anime/outlineNormals.vs", "Shaders/anime/outlineNormals.fs"); Globals.assetManager.addShaderToQueue("Shaders/core/anime/outlineNormals.vs", "Shaders/core/anime/outlineNormals.fs"); } catch(Exception e){ LoggerInterface.loggerRenderer.ERROR(e); } // //Compositing shaders // compositeAnimeOutline = VisualShader.loadSpecificShader("Shaders/core/anime/compositeAnimeOutline.vs", "Shaders/core/anime/compositeAnimeOutline.fs"); // //Post processing pipeline init // postProcessingPipeline.init(openGLState); //instantiate light manager lightManager = LightManager.create(); // //Fog // //enable fog // glEnable(GL_FOG); // //set the equation to use for fog // glFogf(GL_FOG_MODE,GL_LINEAR); //// glFogf(GL_FOG_MODE,GL_EXP2); // //set the density of the fog // glFogf(GL_FOG_DENSITY,1.0f); // //these are applicable for the linear equation // glFogf(GL_FOG_START,0.8f); // glFogf(GL_FOG_END,1.0f); // //fog color // FloatBuffer fogColor = FloatBuffer.allocate(4); // fogColor.put(1.0f); // fogColor.put(1.0f); // fogColor.put(1.0f); // fogColor.put(1.0f); // fogColor.flip(); // GL11.glFogfv(GL_FOG_COLOR, fogColor); // //Init pipelines // mainContentPipeline.setFirstPersonPipeline(firstPersonItemsPipeline); // // Projection and View matrix creation // Globals.projectionMatrix = new Matrix4d(); Globals.viewMatrix = new Matrix4d(); verticalFOV = (float)(Globals.verticalFOV * Math.PI /180.0f); //set local aspect ratio and global aspect ratio at the same time aspectRatio = Globals.aspectRatio = Globals.WINDOW_WIDTH / (float)Globals.WINDOW_HEIGHT; Globals.projectionMatrix.setPerspective(verticalFOV, Globals.aspectRatio, Globals.nearClip, Globals.userSettings.getGraphicsViewDistance()); Globals.viewMatrix.translation(new Vector3d(0.0f,0.0f,-3.0f)); /** * Alert everyone that the rendering engine is ready */ if(Globals.signalSystem != null){ Globals.signalSystem.post(SignalType.RENDERING_ENGINE_READY); } } /** * Main function to draw the screen */ public void drawScreen(){ //element manager handle outstanding signals Globals.elementService.handleAllSignals(); //calculate render angle for frustum culling if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT){ updateFrustumBox(); } //generate depth map if(Globals.RENDER_FLAG_RENDER_SHADOW_MAP && shouldRunPipelines()){ shadowMapPipeline.render(openGLState, renderPipelineState); } //render volume buffer if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT && shouldRunPipelines()){ volumeBufferPipeline.render(openGLState, renderPipelineState); } //Update light buffer lightManager.update(renderPipelineState,openGLState,Globals.playerCamera); checkError(); //Render content to the game framebuffer if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT && shouldRunPipelines()){ if(Globals.userSettings.getGraphicsPerformanceOIT()){ mainContentPipeline.render(openGLState, renderPipelineState); } else { mainContentNoOITPipeline.render(openGLState, renderPipelineState); } checkError(); debugContentPipeline.render(openGLState, renderPipelineState); checkError(); normalsForOutlinePipeline.render(openGLState, renderPipelineState); checkError(); firstPersonItemsPipeline.render(openGLState, renderPipelineState); checkError(); outlineNormalsPipeline.render(openGLState, renderPipelineState); checkError(); compositePipeline.render(openGLState, renderPipelineState); checkError(); postProcessingPipeline.render(openGLState, renderPipelineState); checkError(); } //Render the game framebuffer texture to a quad if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER){ renderScreenPipeline.render(openGLState, renderPipelineState); checkError(); } //render ui uiPipeline.render(openGLState, renderPipelineState); checkError(); //Render boundaries of ui elements if(Globals.RENDER_FLAG_RENDER_UI_BOUNDS){ DebugRendering.drawUIBoundsWireframe(); } /** * Render imgui */ imGuiPipeline.render(openGLState, renderPipelineState); checkError(); //check for errors // checkError(); //check and call events and swap the buffers LoggerInterface.loggerRenderer.DEBUG_LOOP("GLFW Swap buffers"); GLFW.glfwSwapBuffers(Globals.window); LoggerInterface.loggerRenderer.DEBUG_LOOP("GLFW Poll Events"); GLFW.glfwPollEvents(); LoggerInterface.loggerRenderer.DEBUG_LOOP("Check OpenGL Errors"); checkError(); } /** * Updates the frustum box of the render pipeline */ void updateFrustumBox(){ renderPipelineState.updateFrustumIntersection(Globals.projectionMatrix, Globals.viewMatrix); } public void bindFramebuffer(int framebufferPointer){ openGLState.glBindFramebuffer(GL_FRAMEBUFFER, framebufferPointer); } public void setTitleBarDimensions(){ IntBuffer tLeft = BufferUtils.createIntBuffer(1); IntBuffer tTop = BufferUtils.createIntBuffer(1); IntBuffer tRight = BufferUtils.createIntBuffer(1); IntBuffer tBottom = BufferUtils.createIntBuffer(1); // Get the title bar dims GLFW.glfwGetWindowFrameSize(Globals.window, tLeft, tTop, tRight, tBottom); Globals.WINDOW_TITLE_BAR_HEIGHT = tTop.get(); // System.out.println(tLeft.get() + " " + tTop.get() + " " + tRight.get() + " " + tBottom.get()); } public Texture getVolumeBackfaceTexture(){ return volumeDepthBackfaceTexture; } public Texture getVolumeFrontfaceTexture(){ return volumeDepthFrontfaceTexture; } public LightManager getLightManager(){ return lightManager; } public static void incrementOutputFramebuffer(){ outputFramebuffer++; if(outputFramebuffer > 8){ outputFramebuffer = 0; } } public static void setFOV(float verticalFOV){ RenderingEngine.verticalFOV = verticalFOV; calculateProjectionMatrix(); } public static void setAspectRatio(float aspectRatio){ RenderingEngine.aspectRatio = aspectRatio; calculateProjectionMatrix(); } static void calculateProjectionMatrix(){ float radVerticalFOV = (float)(RenderingEngine.verticalFOV * Math.PI /180.0f); float nearClip = 0.001f; Globals.projectionMatrix.setPerspective(radVerticalFOV, RenderingEngine.aspectRatio, nearClip, Globals.userSettings.getGraphicsViewDistance()); } /** * Gets the imgui pipeline * @return The imgui pipeline */ public ImGuiPipeline getImGuiPipeline(){ return this.imGuiPipeline; } /** * Gets the debug content pipeline * @return The debug content pipeline */ public DebugContentPipeline getDebugContentPipeline(){ return this.debugContentPipeline; } /** * Gets the current render pipeline state * @return The current render pipeline state */ public RenderPipelineState getRenderPipelineState(){ return renderPipelineState; } /** * Gets the shadow map pipeline * @return The shadow map pipeline */ public ShadowMapPipeline getShadowMapPipeline(){ return this.shadowMapPipeline; } /** * Gets the post processing pipeline * @return The post processing pipeline */ public PostProcessingPipeline getPostProcessingPipeline(){ return this.postProcessingPipeline; } /** * Gets the current opengl state * @return */ public OpenGLState getOpenGLState(){ return openGLState; } /** * Gets the opengl context that the rendering engine is running within * @return The opengl context */ public OpenGLContext getOpenGLContext(){ return openGLContext; } /** * Tries to recapture the screen */ public static void recaptureIfNecessary(){ if(Globals.controlHandler.shouldRecapture()){ //Makes the window that was just created the current OS-level window context GLFW.glfwMakeContextCurrent(Globals.window); // //Maximize it GLFW.glfwMaximizeWindow(Globals.window); //grab focus GLFW.glfwFocusWindow(Globals.window); //apply mouse controls state if(Globals.controlHandler.isMouseVisible()){ Globals.controlHandler.showMouse(); } else { Globals.controlHandler.hideMouse(); } Globals.controlHandler.setRecapture(false); } } /** * Checks for any errors currently caught by OpenGL. * Refer: https://docs.gl/gl4/glGetError */ public boolean checkError(){ int error = this.getError(); if(error != GL11.GL_NO_ERROR){ LoggerInterface.loggerRenderer.ERROR("checkError - " + getErrorInEnglish(error), new Exception("OpenGL Error")); return true; } return false; } /** * Gets the current error code * @return The error code */ public int getError(){ int lastCode = GL11.glGetError(); int currentCode = lastCode; while((currentCode = GL11.glGetError()) != GL11.GL_NO_ERROR){ lastCode = currentCode; } return lastCode; } /** * Gets the most recent GLFW Error * @return The most recent GLFW error */ public int getGLFWError(){ int lastCode = 0; try (MemoryStack stack = MemoryStack.stackPush()){ lastCode = GLFW.glfwGetError(stack.callocPointer(1)); } return lastCode; } /** * Decodes the glfw error code * @param code The code * @return The decoded message */ public String getGLFWErrorMessage(int code){ switch(code){ case GLFW.GLFW_INVALID_ENUM: return "GLFW_INVALID_ENUM"; case GLFW.GLFW_INVALID_VALUE: return "GLFW_INVALID_VALUE"; default: return "Unhandled value!"; } } /** * Checks if pipelines should run * @return true if should render, false otherwise */ private boolean shouldRunPipelines(){ boolean rVal = Globals.playerCamera != null ; return rVal; } /** * Destroys the rendering engine */ public void destroy(){ //free framebuffers if(screenFramebuffer != null){ screenFramebuffer.free(); } if(screenRenderbuffer != null){ screenRenderbuffer.free(); } if(gameImageNormalsFramebuffer != null){ gameImageNormalsFramebuffer.free(); } if(lightDepthBuffer != null){ lightDepthBuffer.free(); } if(transparencyBuffer != null){ transparencyBuffer.free(); } if(volumeDepthBackfaceFramebuffer != null){ volumeDepthBackfaceFramebuffer.free(); } if(volumeDepthFrontfaceFramebuffer != null){ volumeDepthFrontfaceFramebuffer.free(); } if(normalsOutlineFrambuffer != null){ normalsOutlineFrambuffer.free(); } //null out screenFramebuffer = null; screenRenderbuffer = null; gameImageNormalsFramebuffer = null; lightDepthBuffer = null; transparencyBuffer = null; volumeDepthBackfaceFramebuffer = null; volumeDepthFrontfaceFramebuffer = null; normalsOutlineFrambuffer = null; //free textures if(screenTextureColor != null){ screenTextureColor.free(); } if(screenTextureDepth != null){ screenTextureDepth.free(); } if(gameImageNormalsTexture != null){ gameImageNormalsTexture.free(); } if(lightBufferDepthTexture != null){ lightBufferDepthTexture.free(); } if(transparencyRevealageTexture != null){ transparencyRevealageTexture.free(); } if(volumeDepthBackfaceTexture != null){ volumeDepthBackfaceTexture.free(); } if(volumeDepthFrontfaceTexture != null){ volumeDepthFrontfaceTexture.free(); } if(normalsOutlineTexture != null){ normalsOutlineTexture.free(); } //null out screenTextureColor = null; screenTextureDepth = null; gameImageNormalsTexture = null; lightBufferDepthTexture = null; transparencyRevealageTexture = null; volumeDepthBackfaceTexture = null; volumeDepthFrontfaceTexture = null; normalsOutlineTexture = null; //end glfw GLFW.glfwDestroyWindow(Globals.window); GLFW.glfwTerminate(); } /** * Checks for any errors currently caught by OpenGL. * Refer: https://docs.gl/gl4/glGetError * @param errorCode The error code * @return The message */ public static String getErrorInEnglish(int errorCode){ switch(errorCode){ case GL11.GL_NO_ERROR: { return null; } case GL11.GL_INVALID_ENUM: { return "GL_INVALID_ENUM"; } case GL11.GL_INVALID_VALUE: { return "GL_INVALID_VALUE"; } case GL11.GL_INVALID_OPERATION: { return "GL_INVALID_OPERATION"; } case GL30.GL_INVALID_FRAMEBUFFER_OPERATION: { return "GL_INVALID_FRAMEBUFFER_OPERATION"; } case GL11.GL_OUT_OF_MEMORY: { return "GL_OUT_OF_MEMORY"; } case GL11.GL_STACK_UNDERFLOW: { return "GL_STACK_UNDERFLOW"; } case GL11.GL_STACK_OVERFLOW: { return "GL_STACK_OVERFLOW"; } default: { return "Un-enum'd error or no error. Code: " + errorCode; } } } }