881 lines
33 KiB
Java
881 lines
33 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 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|