package com.lyeeedar.Roguelike3D.Graphics.Renderers; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.glutils.FrameBuffer; import com.badlogic.gdx.graphics.glutils.ShaderProgram; import com.badlogic.gdx.math.Matrix3; import com.badlogic.gdx.math.Matrix4; import com.lyeeedar.Roguelike3D.Game.GameData; import com.lyeeedar.Roguelike3D.Graphics.Lights.LightManager; import com.lyeeedar.Roguelike3D.Graphics.Lights.PointLight; import com.lyeeedar.Roguelike3D.Graphics.Materials.Material; import com.lyeeedar.Roguelike3D.Graphics.Materials.TextureAttribute; import com.lyeeedar.Roguelike3D.Graphics.Renderers.Renderer.DrawableManager.Drawable; public class DeferredRenderer extends Renderer { public static int BUFFER = 0; static ShaderProgram normalShader; static ShaderProgram normalmapShader; static ShaderProgram lightShader; static ShaderProgram finalShader; static ShaderProgram depthonlyShader; static ShaderProgram normalonlyShader; ShaderProgram currentShader; static FrameBuffer normalBuffer; static FrameBuffer lightBuffer; int[] resolution; SpriteBatch sB = new SpriteBatch(); public DeferredRenderer() { super(); } final Matrix3 normalMatrix = new Matrix3(); final Matrix4 view = new Matrix4(); @Override protected void flush(LightManager lightManager) { normalBuffer.begin(); Gdx.graphics.getGL20().glClearColor(0.0f, 0.0f, 0.0f, 1.0f); Gdx.graphics.getGL20().glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); drawableManager.drawables.sort(sorter); for (int i = drawableManager.drawables.size; --i >= 0;) { final Drawable drawable = drawableManager.drawables.get(i); final Matrix4 modelMatrix = drawable.model_matrix; normalMatrix.set(modelMatrix); final Mesh mesh = drawable.mesh; final Material material = drawable.material; if (material.normalmapAttribute.texture != null) { changeShader(normalmapShader); } else { changeShader(normalShader); } currentShader.setUniformMatrix("u_model_matrix", modelMatrix); currentShader.setUniformMatrix("u_normal_matrix", normalMatrix); material.normalmapAttribute.bind(currentShader, lightManager); mesh.render(currentShader, drawable.primitiveType); } currentShader.end(); normalBuffer.end(); currentShader = null; lightBuffer.begin(); if (BUFFER == 1) { Gdx.graphics.getGL20().glClearColor(0.2f, 0.2f, 0.2f, 1.0f); Gdx.graphics.getGL20().glClear(GL20.GL_COLOR_BUFFER_BIT); } else { Gdx.graphics.getGL20().glClearColor(lightManager.getAmbient().r/5f, lightManager.getAmbient().g/5f, lightManager.getAmbient().b/5f, 0.0f); Gdx.graphics.getGL20().glClear(GL20.GL_COLOR_BUFFER_BIT); Gdx.graphics.getGL20().glEnable(GL20.GL_BLEND); Gdx.graphics.getGL20().glBlendFunc(GL20.GL_ONE, GL20.GL_ONE); Gdx.graphics.getGL20().glDisable(GL20.GL_CULL_FACE); Gdx.graphics.getGL20().glDisable(GL20.GL_DEPTH_TEST); changeShader(lightShader); normalBuffer.getColorBufferTexture().bind(0); currentShader.setUniformi("u_normals", 0); currentShader.setUniformf("u_screen", resolution[0], resolution[1]); currentShader.setUniformf("u_cam", cam.position); view.set(cam.view).inv(); currentShader.setUniformMatrix("u_inv_v", view); for (PointLight p : lightManager.staticPointLights) { if (!cam.frustum.sphereInFrustum(p.position, p.radius)) continue; p.bind(currentShader); p.area.render(currentShader, GL20.GL_TRIANGLES); } for (PointLight p : lightManager.dynamicPointLights) { if (!cam.frustum.sphereInFrustum(p.position, p.radius)) continue; p.bind(currentShader); p.area.render(currentShader, GL20.GL_TRIANGLES); } currentShader.end(); } lightBuffer.end(); currentShader = null; Gdx.graphics.getGL20().glDisable(GL20.GL_BLEND); Gdx.graphics.getGL20().glEnable(GL20.GL_CULL_FACE); Gdx.graphics.getGL20().glCullFace(GL20.GL_BACK); Gdx.graphics.getGL20().glEnable(GL20.GL_DEPTH_TEST); Gdx.graphics.getGL20().glDepthMask(true); changeShader(finalShader); lightBuffer.getColorBufferTexture().bind(1); currentShader.setUniformi("u_light_texture", 1); currentShader.setUniformf("u_screen", resolution[0], resolution[1]); for (int i = drawableManager.drawables.size; --i >= 0;) { final Drawable drawable = drawableManager.drawables.get(i); final Matrix4 modelMatrix = drawable.model_matrix; final Mesh mesh = drawable.mesh; final Material material = drawable.material; currentShader.setUniformMatrix("u_model_matrix", modelMatrix); material.colourAttribute.bind(currentShader, lightManager); material.textureAttribute.bind(currentShader, lightManager); mesh.render(currentShader, drawable.primitiveType); } currentShader.end(); currentShader = null; Gdx.graphics.getGL20().glDisable(GL20.GL_CULL_FACE); Gdx.graphics.getGL20().glDisable(GL20.GL_DEPTH_TEST); //sB.enableBlending(); //sB.setBlendFunction(GL20.GL_ZERO, GL20.GL_ONE_MINUS_SRC_COLOR); if (BUFFER == 2) { sB.disableBlending(); sB.setShader(normalonlyShader); sB.begin(); normalonlyShader.setUniformMatrix("u_inv_v", view); sB.draw(normalBuffer.getColorBufferTexture(), 0, 0, resolution[0], resolution[1], 0, 0, resolution[0], resolution[1], false, true); sB.end(); } else if (BUFFER == 3) { sB.disableBlending(); sB.setShader(depthonlyShader); sB.begin(); sB.draw(normalBuffer.getColorBufferTexture(), 0, 0, resolution[0], resolution[1], 0, 0, resolution[0], resolution[1], false, true); sB.end(); sB.setShader(null); } else if (BUFFER == 4) { sB.begin(); sB.draw(lightBuffer.getColorBufferTexture(), 0, 0, resolution[0], resolution[1], 0, 0, resolution[0], resolution[1], false, true); sB.end(); } } private void changeShader(ShaderProgram newShader) { if (currentShader != null && currentShader.equals(newShader)) return; if (currentShader != null) currentShader.end(); currentShader = newShader; currentShader.begin(); currentShader.setUniformMatrix("u_pv", cam.combined); currentShader.setUniformMatrix("u_v", cam.view); currentShader.setUniformf("u_cam", cam.position); currentShader.setUniformf("u_linearDepth", cam.far-cam.near); } @Override protected void disposeSuper() { } @Override public void createShader(LightManager lights) { if (normalShader == null) normalShader = ShaderFactory.createShader("deferred_normals"); if (normalmapShader == null) normalmapShader = ShaderFactory.createShader("deferred_normals", TextureAttribute.normalmapTexture+"Flag"); if (lightShader == null) lightShader = ShaderFactory.createShader("deferred_lighting"); if (finalShader == null) finalShader = ShaderFactory.createShader("deferred_finalise"); if (depthonlyShader == null) depthonlyShader = ShaderFactory.createShader("depth_only"); if (normalonlyShader == null) normalonlyShader = ShaderFactory.createShader("normal_only"); } @Override public void updateResolution() { if (resolution == null) resolution = new int[]{0, 0}; if (GameData.resolution[0] != resolution[0] && GameData.resolution[1] != resolution[1]) { resolution[0] = GameData.resolution[0]; resolution[1] = GameData.resolution[1]; if (normalBuffer != null) normalBuffer.dispose(); normalBuffer = new FrameBuffer(Format.RGBA8888, resolution[0], resolution[1], true); if (lightBuffer != null) lightBuffer.dispose(); lightBuffer = new FrameBuffer(Format.RGB888, resolution[0], resolution[1], false); } } }