Renderer/src/main/java/electrosphere/renderer/RenderingEngine.java
austin 6fe1733d58
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
move more client state
2025-05-15 15:48:04 -04:00

972 lines
36 KiB
Java

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 java.util.LinkedList;
import java.util.List;
import org.joml.Matrix4d;
import org.joml.Vector3d;
import org.lwjgl.BufferUtils;
import org.lwjgl.PointerBuffer;
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 org.lwjgl.system.MemoryUtil;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.engine.os.OSDragAndDrop;
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.model.Material;
import electrosphere.renderer.pipelines.CompositePipeline;
import electrosphere.renderer.pipelines.FirstPersonItemsPipeline;
import electrosphere.renderer.pipelines.FoliagePipeline;
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;
/**
* The main object for the rendering engine
*/
public class RenderingEngine {
/**
* Handle for the window created by glfw
*/
private long windowPtr = -1;
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();
/*
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;
/**
* The light manager for the rendering engine
*/
LightManager lightManager;
public static int outputFramebuffer = 0;
//used in calculating projection matrix
float aspectRatio = 1.0f;
float verticalFOV = 90.0f;
float nearClip = 0.01f;
//matrices for drawing models
private Matrix4d viewMatrix = new Matrix4d();
private Matrix4d projectionMatrix = new Matrix4d();
private Matrix4d lightDepthMatrix = new Matrix4d();
/**
* The default material
*/
private Material materialDefault = new Material(AssetDataStrings.TEXTURE_DEFAULT);
/**
* the current state of the rendering pipeline
*/
static RenderPipelineState renderPipelineState = new RenderPipelineState();
/**
* the opengl state
*/
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();
FoliagePipeline foliagePipeline = new FoliagePipeline();
OutlineNormalsPipeline outlineNormalsPipeline = new OutlineNormalsPipeline();
CompositePipeline compositePipeline = new CompositePipeline();
PostProcessingPipeline postProcessingPipeline = new PostProcessingPipeline();
UIPipeline uiPipeline = new UIPipeline();
RenderScreenPipeline renderScreenPipeline = new RenderScreenPipeline();
ImGuiPipeline imGuiPipeline;
/**
* Initializes the opengl context
*/
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.gameConfigCurrent.getSettings().getDisplayWidth() <= 0 || Globals.gameConfigCurrent.getSettings().getDisplayHeight() <= 0){
throw new Error("Trying to create window with width or height less than 1! " + Globals.gameConfigCurrent.getSettings().getDisplayWidth() + " " + Globals.gameConfigCurrent.getSettings().getDisplayHeight());
}
//Creates the window reference object
if(Globals.gameConfigCurrent.getSettings().displayFullscreen() || Globals.WINDOW_FULLSCREEN){
//below line is for fullscreen
this.windowPtr = GLFW.glfwCreateWindow(Globals.gameConfigCurrent.getSettings().getDisplayWidth(), Globals.gameConfigCurrent.getSettings().getDisplayHeight(), "ORPG", GLFW.glfwGetPrimaryMonitor(), NULL);
} else {
this.windowPtr = GLFW.glfwCreateWindow(Globals.gameConfigCurrent.getSettings().getDisplayWidth(), Globals.gameConfigCurrent.getSettings().getDisplayHeight(), "ORPG", NULL, NULL);
}
// Errors for failure to create window (IE: No GUI mode on linux ?)
if (this.windowPtr == 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(this.windowPtr, (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(this.windowPtr);
//Maximize it
GLFW.glfwMaximizeWindow(this.windowPtr);
GLFW.glfwPollEvents();
//grab actual framebuffer
IntBuffer xBuffer = BufferUtils.createIntBuffer(1);
IntBuffer yBuffer = BufferUtils.createIntBuffer(1);
GLFW.glfwGetFramebufferSize(this.windowPtr, 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(this.windowPtr, Globals.controlCallback);
GLFW.glfwSetMouseButtonCallback(this.windowPtr, Globals.mouseCallback);
GLFW.glfwSetScrollCallback(this.windowPtr, 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(this.windowPtr, 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.gameConfigCurrent.getSettings().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);
//init screen rendering quadrant
screenTextureVAO = createScreenTextureVAO();
screenTextureShaders = VisualShader.loadSpecificShader("/Shaders/core/screentexture/simple1/simple1.vs", "/Shaders/core/screentexture/simple1/simple1.fs");
//default framebuffer
defaultFramebuffer = new Framebuffer(GL_DEFAULT_FRAMEBUFFER);
//generate framebuffers
Texture screenTextureColor = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY());
RenderingEngine.screenTextureColor = screenTextureColor;
Texture screenTextureDepth = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY());
RenderingEngine.screenTextureDepth = screenTextureDepth;
try {
Framebuffer screenFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY(), 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");
try {
Framebuffer lightDepthBuffer = FramebufferUtils.generateDepthBuffer(openGLState);
RenderingEngine.lightDepthBuffer = lightDepthBuffer;
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
Texture lightBufferDepthTexture = lightDepthBuffer.getDepthTexture();
RenderingEngine.lightBufferDepthTexture = lightBufferDepthTexture;
//
//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.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY());
volumeDepthBackfaceFramebuffer = FramebufferUtils.generateDepthBuffer(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY(), volumeDepthBackfaceTexture);
volumeDepthFrontfaceTexture = FramebufferUtils.generateDepthBufferTexture(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY());
volumeDepthFrontfaceFramebuffer = FramebufferUtils.generateDepthBuffer(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY(), volumeDepthFrontfaceTexture);
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);
}
//
//Game normals
//
try {
gameImageNormalsTexture = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY());
Texture gameImageNormalsDepthTexture = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY());
gameImageNormalsFramebuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().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.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY());
transparencyRevealageClear = new float[]{1.0f, 1.0f, 1.0f, 1.0f};
transparencyRevealageTexture = FramebufferUtils.generateOITRevealageTexture(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY());
transparencyBuffer = FramebufferUtils.generateOITFramebuffer(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().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.gameConfigCurrent.getSettings().getGraphicsFOV() * 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.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY());
normalsOutlineFrambuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.gameConfigCurrent.getSettings().getRenderResolutionX(), Globals.gameConfigCurrent.getSettings().getRenderResolutionY(), normalsOutlineTexture);
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);
//
//Set file drag-and-drop for app
//
GLFW.glfwSetDropCallback(this.windowPtr, (long window, int count, long names) -> {
PointerBuffer charPointers = MemoryUtil.memPointerBuffer(names, count);
List<String> paths = new LinkedList<String>();
for(int i = 0; i < count; i++){
String name = MemoryUtil.memUTF8(charPointers.get(i));
paths.add(name);
}
OSDragAndDrop.handleDragAndDrop(paths);
});
//
//Init pipelines
//
mainContentPipeline.setFirstPersonPipeline(firstPersonItemsPipeline);
//
// Projection and View matrix creation
//
this.verticalFOV = (float)(Globals.gameConfigCurrent.getSettings().getGraphicsFOV() * Math.PI /180.0f);
//set local aspect ratio and global aspect ratio at the same time
this.aspectRatio = Globals.WINDOW_WIDTH / (float)Globals.WINDOW_HEIGHT;
this.projectionMatrix.setPerspective(this.verticalFOV, this.aspectRatio, this.nearClip, Globals.gameConfigCurrent.getSettings().getGraphicsViewDistance());
this.viewMatrix.translation(new Vector3d(0.0f,0.0f,-3.0f));
/**
* Alert everyone that the rendering engine is ready
*/
if(Globals.engineState.signalSystem != null){
Globals.engineState.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){
this.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.clientState.playerCamera);
this.checkError();
//Render content to the game framebuffer
if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT && shouldRunPipelines()){
if(Globals.gameConfigCurrent.getSettings().getGraphicsPerformanceOIT()){
mainContentPipeline.render(openGLState, renderPipelineState);
} else {
mainContentNoOITPipeline.render(openGLState, renderPipelineState);
}
this.checkError();
debugContentPipeline.render(openGLState, renderPipelineState);
this.checkError();
normalsForOutlinePipeline.render(openGLState, renderPipelineState);
this.checkError();
firstPersonItemsPipeline.render(openGLState, renderPipelineState);
this.checkError();
outlineNormalsPipeline.render(openGLState, renderPipelineState);
this.checkError();
compositePipeline.render(openGLState, renderPipelineState);
this.checkError();
postProcessingPipeline.render(openGLState, renderPipelineState);
this.checkError();
}
//Render the game framebuffer texture to a quad
if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER){
renderScreenPipeline.render(openGLState, renderPipelineState);
this.checkError();
}
//render ui
uiPipeline.render(openGLState, renderPipelineState);
this.checkError();
//Render boundaries of ui elements
if(Globals.RENDER_FLAG_RENDER_UI_BOUNDS){
DebugRendering.drawUIBoundsWireframe();
}
/**
* Render imgui
*/
imGuiPipeline.render(openGLState, renderPipelineState);
this.checkError();
//check for errors
// checkError();
//check and call events and swap the buffers
LoggerInterface.loggerRenderer.DEBUG_LOOP("GLFW Swap buffers");
GLFW.glfwSwapBuffers(this.windowPtr);
LoggerInterface.loggerRenderer.DEBUG_LOOP("GLFW Poll Events");
GLFW.glfwPollEvents();
LoggerInterface.loggerRenderer.DEBUG_LOOP("Check OpenGL Errors");
this.checkError();
}
/**
* Updates the frustum box of the render pipeline
*/
private void updateFrustumBox(){
renderPipelineState.updateFrustumIntersection(this.projectionMatrix, this.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(this.windowPtr, 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){
Globals.renderingEngine.verticalFOV = verticalFOV;
Globals.renderingEngine.calculateProjectionMatrix();
}
public static void setAspectRatio(float aspectRatio){
Globals.renderingEngine.aspectRatio = aspectRatio;
Globals.renderingEngine.calculateProjectionMatrix();
}
/**
* Calculates the projection matrix
*/
public void calculateProjectionMatrix(){
float radVerticalFOV = (float)(this.verticalFOV * Math.PI /180.0f);
float nearClip = 0.001f;
this.projectionMatrix.setPerspective(radVerticalFOV, this.aspectRatio, nearClip, Globals.gameConfigCurrent.getSettings().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 foliage pipeline
* @return The foliage pipeline
*/
public FoliagePipeline getFoliagePipeline(){
return foliagePipeline;
}
/**
* 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;
}
/**
* Gets the default material
* @return The default material
*/
public Material getDefaultMaterial(){
return this.materialDefault;
}
/**
* Gets the view matrix
* @return The view matrix
*/
public Matrix4d getViewMatrix(){
return viewMatrix;
}
/**
* Gets the projection matrix
* @return The projection matrix
*/
public Matrix4d getProjectionMatrix(){
return projectionMatrix;
}
/**
* Gets the light depth matrix
* @return The light depth matrix
*/
public Matrix4d getLightDepthMatrix(){
return lightDepthMatrix;
}
/**
* Gets the near clip of the engine
* @return The near clip
*/
public float getNearClip(){
return this.nearClip;
}
/**
* Gets the window pointer of the rendering engine
* @return The window pointer
*/
public long getWindowPtr(){
return this.windowPtr;
}
/**
* 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.renderingEngine.windowPtr);
// //Maximize it
GLFW.glfwMaximizeWindow(Globals.renderingEngine.windowPtr);
//grab focus
GLFW.glfwFocusWindow(Globals.renderingEngine.windowPtr);
//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.clientState.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;
//reset shader loading
VisualShader.clearAlreadyCompiledMap();
//destroy loaded resources
Globals.assetManager.queueAllModelsForDeletion();
Globals.assetManager.queueAllTexturesForDeletion();
Globals.assetManager.queueAllShadersForDeletion();
Globals.assetManager.handleDeleteQueue();
//end glfw
GLFW.glfwDestroyWindow(this.windowPtr);
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;
}
}
}
}