package electrosphere.renderer; import electrosphere.entity.CameraEntityUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.types.hitbox.HitboxData; import electrosphere.entity.types.hitbox.HitboxUtils; import electrosphere.game.config.creature.type.PhysicsObject; import electrosphere.logger.LoggerInterface; import electrosphere.main.Globals; import static electrosphere.main.Main.deltaTime; import static electrosphere.main.Main.view_Range; import static electrosphere.renderer.RenderUtils.createScreenTextureVAO; import electrosphere.renderer.framebuffer.Framebuffer; import electrosphere.renderer.framebuffer.FramebufferUtils; import electrosphere.renderer.framebuffer.Renderbuffer; import electrosphere.renderer.texture.Texture; import electrosphere.renderer.ui.Widget; import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Vector3f; import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MAJOR; import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR; import static org.lwjgl.glfw.GLFW.GLFW_CURSOR; import static org.lwjgl.glfw.GLFW.GLFW_CURSOR_DISABLED; import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE; import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE; import static org.lwjgl.glfw.GLFW.glfwCreateWindow; import static org.lwjgl.glfw.GLFW.glfwInit; import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent; import static org.lwjgl.glfw.GLFW.glfwMaximizeWindow; import static org.lwjgl.glfw.GLFW.glfwPollEvents; import static org.lwjgl.glfw.GLFW.glfwSetInputMode; import static org.lwjgl.glfw.GLFW.glfwSwapBuffers; import static org.lwjgl.glfw.GLFW.glfwTerminate; import static org.lwjgl.glfw.GLFW.glfwWindowHint; import org.lwjgl.opengl.GL; import static org.lwjgl.opengl.GL11.GL_BLEND; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST; 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.GL11.GL_TEXTURE_2D; import static org.lwjgl.opengl.GL11.GL_TRIANGLES; import static org.lwjgl.opengl.GL11.glBindTexture; import static org.lwjgl.opengl.GL11.glBlendFunc; import static org.lwjgl.opengl.GL11.glClear; import static org.lwjgl.opengl.GL11.glClearColor; import static org.lwjgl.opengl.GL11.glDisable; import static org.lwjgl.opengl.GL11.glDrawArrays; import static org.lwjgl.opengl.GL11.glEnable; import static org.lwjgl.opengl.GL11.glViewport; import static org.lwjgl.opengl.GL13.GL_TEXTURE0; import static org.lwjgl.opengl.GL13.GL_TEXTURE1; import static org.lwjgl.opengl.GL13.GL_TEXTURE2; import static org.lwjgl.opengl.GL13.GL_TEXTURE3; import static org.lwjgl.opengl.GL13.glActiveTexture; import static org.lwjgl.opengl.GL20.glGetUniformLocation; import static org.lwjgl.opengl.GL20.glUniformMatrix4fv; import static org.lwjgl.opengl.GL20.glUseProgram; import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER; import static org.lwjgl.opengl.GL30.GL_RENDERBUFFER; import static org.lwjgl.opengl.GL30.glBindFramebuffer; import static org.lwjgl.opengl.GL30.glBindRenderbuffer; import static org.lwjgl.opengl.GL30.glBindVertexArray; import static org.lwjgl.system.MemoryUtil.NULL; public class RenderingEngine { public static final int GL_DEFAULT_FRAMEBUFFER = 0; public static final int GL_DEFAULT_RENDERBUFFER = 0; static Framebuffer screenFramebuffer; static Renderbuffer screenRenderbuffer; static int screenTextureVAO; static ShaderProgram screenTextureShaders; static ShaderProgram lightDepthShaderProgram; static Framebuffer lightDepthBuffer; public static boolean renderHitboxes = false; public static boolean renderPhysics = false; ShaderProgram activeProgram; public void createOpenglContext(){ //Initializes opengl glfwInit(); //Gives hints to glfw to control how opengl will be used glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); Allows you to make the background transparent // glfwWindowHint(GLFW_OPACITY, 23); //Creates the window reference object Globals.window = glfwCreateWindow(Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, "ORPG", NULL, NULL); //Errors for failure to create window (IE: No GUI mode on linux ?) if (Globals.window == NULL) { LoggerInterface.loggerEngine.ERROR("Failed to make window.", new Exception("Renderer Creation Failure")); glfwTerminate(); } //Makes the window that was just created the current OS-level window context glfwMakeContextCurrent(Globals.window); //Maximize it glfwMaximizeWindow(Globals.window); //Creates the OpenGL capabilities for the program. GL.createCapabilities(); //This enables Z-buffering so that farther-back polygons are not drawn over nearer ones glEnable(GL_DEPTH_TEST); // Support for transparency glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // //Hide the cursor and capture it // glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); //init screen rendering quadrant screenTextureVAO = createScreenTextureVAO(); // initScreenTextureShaderProgram(); screenTextureShaders = ShaderProgram.loadSpecificShader("/Shaders/screentexture/simple1/simple1.vs", "/Shaders/screentexture/simple1/simple1.fs"); // screenTextureShaders = ShaderProgram.loadSpecificShader("/Shaders/screentexture/drawDepthBuffer/drawDepthBuffer.vs", "/Shaders/screentexture/drawDepthBuffer/drawDepthBuffer.fs"); //generate framebuffers screenFramebuffer = FramebufferUtils.generateScreensizeTextureFramebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, GL_DEFAULT_FRAMEBUFFER); glBindRenderbuffer(GL_RENDERBUFFER, GL_DEFAULT_RENDERBUFFER); lightDepthShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/lightDepth/lightDepth.vs", "/Shaders/lightDepth/lightDepth.fs"); Globals.depthMapShaderProgramLoc = lightDepthShaderProgram.shaderProgram; lightDepthBuffer = FramebufferUtils.generateDepthBuffer(); Globals.shadowMapTextureLoc = lightDepthBuffer.getTexture(); // glEnable(GL_CULL_FACE); // enabled for shadow mapping // // Projection and View matrix creation // Globals.projectionMatrix = new Matrix4f(); Globals.viewMatrix = new Matrix4f(); float FOV = (float)(Globals.FOV * Math.PI /180.0f); Globals.projectionMatrix.setPerspective(FOV, 1.0f, 0.1f, view_Range); Globals.viewMatrix.translation(new Vector3f(0.0f,0.0f,-3.0f)); } public void drawScreen(){ // //first pass: generate depth map // if(Globals.RENDER_FLAG_RENDER_SHADOW_MAP){ renderShadowMapContent(); } /* Render content to the game framebuffer */ if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT){ renderGameContent(); } //bind default FBO glBindFramebuffer(GL_FRAMEBUFFER,0); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); /* Render the game framebuffer texture to a quad */ if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER){ renderScreenFramebuffer(); } /* Render black background */ if(Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND){ renderBlackBackground(); } /* Render any ui elements */ if(Globals.RENDER_FLAG_RENDER_UI){ renderUI(); } //check and call events and swap the buffers glfwSwapBuffers(Globals.window); glfwPollEvents(); } static void renderShadowMapContent(){ Matrix4f modelTransformMatrix = new Matrix4f(); //set the viewport to shadow map size glViewport(0, 0, 4096, 4096); glEnable(GL_DEPTH_TEST); Globals.renderingEngine.setActiveShader(lightDepthShaderProgram); lightDepthBuffer.bind(); glClear(GL_DEPTH_BUFFER_BIT); float eyeX = -20.0f; float eyeY = 40.0f; float eyeZ = -10.0f; float nearPlane = 0.001f; float farPlane = (float)Math.sqrt(eyeX * eyeX + eyeY * eyeY + eyeZ * eyeZ) + 20.0f; //set matrices for light render Matrix4f lightProjection = new Matrix4f().setOrtho(-10.0f, 10.0f, -10.0f, 10.0f, nearPlane, farPlane);//glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane); Matrix4f lightView = new Matrix4f().setLookAt( new Vector3f(eyeX, eyeY, eyeZ).add(CameraEntityUtils.getCameraCenter(Globals.playerCamera)), new Vector3f( 0.0f, 0.0f, 0.0f).add(CameraEntityUtils.getCameraCenter(Globals.playerCamera)), new Vector3f( 0.0f, 1.0f, 0.0f) ); Globals.lightDepthMatrix = new Matrix4f(lightProjection).mul(lightView); glUniformMatrix4fv(glGetUniformLocation(Globals.renderingEngine.getActiveShader().shaderProgram, "lightSpaceMatrix"), false, Globals.lightDepthMatrix.get(new float[16])); // glCullFace(GL_FRONT); // // D R A W A L L E N T I T I E S // modelTransformMatrix = new Matrix4f(); for(Entity currentEntity : Globals.entityManager.getDrawable()){ //fetch actor Actor currentActor = EntityUtils.getActor(currentEntity); //calculate and apply model transform modelTransformMatrix.identity(); modelTransformMatrix.translate(new Vector3f(EntityUtils.getPosition(currentEntity)).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera))); modelTransformMatrix.rotate(EntityUtils.getRotation(currentEntity)); modelTransformMatrix.scale(EntityUtils.getScale(currentEntity)); currentActor.applyModelMatrix(modelTransformMatrix); //draw currentActor.drawForDepthBuffer(); } //reset texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); //bind default framebuffer glBindFramebuffer(GL_FRAMEBUFFER,0); //reset the viewport to screen size glViewport(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); //resume culling backface // glCullFace(GL_BACK); } static void renderGameContent(){ Matrix4f modelTransformMatrix = new Matrix4f(); //bind screen fbo screenFramebuffer.bind(); glEnable(GL_DEPTH_TEST); glViewport(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); /// /// R E N D E R I N G S T U F F /// //Sets the background color. glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // // D R A W A L L E N T I T I E S // modelTransformMatrix = new Matrix4f(); for(Entity currentEntity : Globals.entityManager.getDrawable()){ //fetch actor Actor currentActor = EntityUtils.getActor(currentEntity); currentActor.incrementAnimationTime(0.001); //increment animations //this is incremented in the shadow calculations // if(currentActor.getCurrentAnimation() != null){ // currentActor.incrementAnimationTime(deltaTime * 500); // } //calculate and apply model transform modelTransformMatrix.identity(); modelTransformMatrix.translate(new Vector3f(EntityUtils.getPosition(currentEntity)).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera))); modelTransformMatrix.rotate(EntityUtils.getRotation(currentEntity)); modelTransformMatrix.scale(EntityUtils.getScale(currentEntity)); currentActor.applyModelMatrix(modelTransformMatrix); //draw currentActor.draw(); // Model currentModel = Globals.assetManager.fetchModel(EntityUtils.getEntityModelPath(currentEntity)); // if(currentModel != null){ // if(currentModel.currentAnimation != null){ // currentModel.incrementTime(deltaTime * 500); // } // currentModel.modelMatrix = new Matrix4f(); // currentModel.modelMatrix.translate(new Vector3f(EntityUtils.getEntityPosition(currentEntity)).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0))); // currentModel.modelMatrix.rotate(EntityUtils.getEntityRotation(currentEntity)); // currentModel.modelMatrix.scale(EntityUtils.getEntityScale(currentEntity)); // currentModel.draw(); // } } if(renderHitboxes){ for(Entity currentHitbox : Globals.hitboxManager.getAllHitboxes()){ Model hitboxModel; HitboxData data = HitboxUtils.getHitboxData(currentHitbox); if(data.isActive()){ if(data.getType().equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){ if((hitboxModel = Globals.assetManager.fetchModel("Models/unitsphere.fbx")) != null){ Vector3f position = EntityUtils.getPosition(currentHitbox); modelTransformMatrix.identity(); modelTransformMatrix.translate(new Vector3f(position).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera))); // modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere modelTransformMatrix.scale(data.getRadius() * 2); hitboxModel.modelMatrix = modelTransformMatrix; hitboxModel.draw(true, true, false, true, true, true, true); } } else if(data.getType().equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){ if((hitboxModel = Globals.assetManager.fetchModel("Models/unitsphere_1.fbx")) != null){ Vector3f position = EntityUtils.getPosition(currentHitbox); modelTransformMatrix.identity(); modelTransformMatrix.translate(new Vector3f(position).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera))); // modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere modelTransformMatrix.scale(data.getRadius() * 2); hitboxModel.modelMatrix = modelTransformMatrix; hitboxModel.draw(true, true, false, true, true, true, true); } } } else { if((hitboxModel = Globals.assetManager.fetchModel("Models/unitsphere_grey.fbx")) != null){ Vector3f position = EntityUtils.getPosition(currentHitbox); modelTransformMatrix.identity(); modelTransformMatrix.translate(new Vector3f(position).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera))); // modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere modelTransformMatrix.scale(data.getRadius() * 2); hitboxModel.modelMatrix = modelTransformMatrix; hitboxModel.draw(true, true, false, true, true, true, true); } } } } if(renderPhysics){ Model physicsGraphicsModel; for(Entity physicsEntity : Globals.collisionEngine.getDynamicPhysicsEntities()){ PhysicsObject template = (PhysicsObject)physicsEntity.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE); switch(template.getType()){ case "CYLINDER": if((physicsGraphicsModel = Globals.assetManager.fetchModel("Models/unitcylinder.fbx")) != null){ Vector3f position = EntityUtils.getPosition(physicsEntity); modelTransformMatrix.identity(); modelTransformMatrix.translate(new Vector3f(position).add(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera))); // modelTransformMatrix.translate(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()); //center sphere modelTransformMatrix.scale(template.getDimension1(),template.getDimension2(),template.getDimension3()); physicsGraphicsModel.modelMatrix = modelTransformMatrix; physicsGraphicsModel.draw(true, true, false, true, true, true, true); } break; } } for(Entity physicsEntity : Globals.collisionEngine.getStructurePhysicsEntities()){ if(physicsEntity.getDataKeys().contains(EntityDataStrings.COLLISION_ENTITY_TYPE_PLANE)){ if((physicsGraphicsModel = Globals.assetManager.fetchModel("Models/unitplane.fbx")) != null){ Vector3f position = EntityUtils.getPosition(physicsEntity); Vector3f scale = EntityUtils.getScale(physicsEntity); Quaternionf rotation = EntityUtils.getRotation(physicsEntity); modelTransformMatrix.identity(); modelTransformMatrix.translate(new Vector3f(position).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera))); modelTransformMatrix.rotate(rotation); // modelTransformMatrix.translate(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()); //center sphere modelTransformMatrix.scale(scale); physicsGraphicsModel.modelMatrix = modelTransformMatrix; physicsGraphicsModel.draw(true, true, false, true, true, true, true); } } else if(physicsEntity.getDataKeys().contains(EntityDataStrings.COLLISION_ENTITY_TYPE_CUBE)){ if((physicsGraphicsModel = Globals.assetManager.fetchModel("Models/unitcube.fbx")) != null){ Vector3f position = EntityUtils.getPosition(physicsEntity); Vector3f scale = EntityUtils.getScale(physicsEntity); Quaternionf rotation = EntityUtils.getRotation(physicsEntity); modelTransformMatrix.identity(); modelTransformMatrix.translate(new Vector3f(position).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera))); modelTransformMatrix.rotate(rotation); // modelTransformMatrix.translate(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()); //center sphere modelTransformMatrix.scale(scale); physicsGraphicsModel.modelMatrix = modelTransformMatrix; physicsGraphicsModel.draw(true, true, false, true, true, true, true); } } } } // glBindVertexArray(0); } static void renderScreenFramebuffer(){ // //unbind texture channels // //What does this mean? //essentially there are two channels we're using to draw mesh textures //we have to glBindTexture to pointer 0 for BOTH channels, otherwise //the leftover texture gets used to draw the screen framebuffer quad //which doesnt work glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); glDisable(GL_DEPTH_TEST); glViewport(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); //render full screen quad Globals.renderingEngine.setActiveShader(screenTextureShaders); glBindVertexArray(screenTextureVAO); glBindTexture(GL_TEXTURE_2D, screenFramebuffer.getTexture()); // glBindTexture(GL_TEXTURE_2D, lightDepthBuffer.getTexture()); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); } static void renderUI(){ Matrix4f modelTransformMatrix = new Matrix4f(); glDisable(GL_DEPTH_TEST); for(Widget currentWidget : Globals.widgetManager.getWidgetList()){ if(currentWidget.isDraw()){ currentWidget.draw(); } } // for(Entity currentEntity : Globals.entityManager.getUIElements()){ // Actor uiActor = EntityUtils.getEntityActor(currentEntity); // if(currentEntity.getDataKeys().contains(EntityDataStrings.DATA_STRING_UI_ELEMENT_FONT)){ // modelTransformMatrix.identity(); // modelTransformMatrix.translate(EntityUtils.getEntityPosition(currentEntity)); // uiActor.applyModelMatrix(modelTransformMatrix); // } // uiActor.drawUI(); // } } static void renderBlackBackground(){ //render full screen quad glUseProgram(screenTextureShaders.shaderProgram); glDisable(GL_DEPTH_TEST); glBindVertexArray(screenTextureVAO); Texture blackTexture = Globals.assetManager.fetchTexture(Globals.blackTexture); if(blackTexture != null){ blackTexture.bind(); } // glBindTexture(GL_TEXTURE_2D, screenFramebuffer.getTexture()); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); } public void setActiveShader(ShaderProgram program){ glUseProgram(program.shaderProgram); activeProgram = program; } public ShaderProgram getActiveShader(){ return activeProgram; } }