diff --git a/client/src/main/java/core/engine/Engine.java b/client/src/main/java/core/engine/Engine.java index d6f882e..933ef76 100644 --- a/client/src/main/java/core/engine/Engine.java +++ b/client/src/main/java/core/engine/Engine.java @@ -112,8 +112,6 @@ public class Engine { // Set the clear color glClearColor(1.0f, 0.0f, 0.0f, 0.0f); - StaticShader shader = new StaticShader(); - Camera camera = new Camera(); glfwSetKeyCallback(window, glfwKeyCallback = new GLFWKeyCallback() { @Override @@ -138,7 +136,7 @@ public class Engine { } }); - Renderer renderer = new Renderer(shader); + Light light = new Light(new Vector3f(0,0,-20), new Vector3f(1,1,1)); RawModel model = OBJLoader.loadOBJModel("dragon", loader); ModelTexture modelTexture = new ModelTexture(loader.loadTexture("white")); @@ -146,21 +144,18 @@ public class Engine { Entity entity = new Entity(texturedModel, new Vector3f(0,0,-50), 0,0,0,1); // Run the rendering loop until the user has attempted to close // the window or has pressed the ESCAPE key. + MasterRenderer renderer = new MasterRenderer(); while ( !glfwWindowShouldClose(window) ) { entity.increaseRotation(0,1,0); - renderer.prepare(); - shader.start(); - shader.loadLight(light); - shader.loadViewMatrix(camera); - renderer.render(entity, shader); - shader.stop(); + renderer.processEntity(entity); + renderer.render(light, camera); glfwSwapBuffers(window); // swap the color buffers // Poll for window events. The key callback above will only be // invoked during this call. glfwPollEvents(); } - shader.cleanUp(); + renderer.cleanUp(); loader.cleanUp(); } diff --git a/client/src/main/java/core/engine/MasterRenderer.java b/client/src/main/java/core/engine/MasterRenderer.java new file mode 100644 index 0000000..4bcd065 --- /dev/null +++ b/client/src/main/java/core/engine/MasterRenderer.java @@ -0,0 +1,45 @@ +package core.engine; + +import core.engine.entity.Camera; +import core.engine.entity.Entity; +import core.engine.entity.Light; +import core.engine.model.TexturedModel; +import core.engine.shader.StaticShader; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MasterRenderer { + + private StaticShader shader = new StaticShader(); + private Renderer renderer = new Renderer(shader); + private Map> entities = new HashMap<>(); + + public void render(Light light, Camera camera) { + renderer.prepare(); + shader.start(); + shader.loadLight(light); + shader.loadViewMatrix(camera); + renderer.render(entities); + shader.stop(); + entities.clear(); + } + + public void processEntity(Entity entity) { + TexturedModel entityModel = entity.getModel(); + List batch = entities.get(entityModel); + if(batch != null) { + batch.add(entity); + } else { + List newBatch = new ArrayList<>(); + newBatch.add(entity); + entities.put(entityModel, newBatch); + } + } + + public void cleanUp() { + shader.cleanUp(); + } +} diff --git a/client/src/main/java/core/engine/Renderer.java b/client/src/main/java/core/engine/Renderer.java index a177308..2091359 100644 --- a/client/src/main/java/core/engine/Renderer.java +++ b/client/src/main/java/core/engine/Renderer.java @@ -4,6 +4,7 @@ import core.engine.entity.Entity; import core.engine.model.RawModel; import core.engine.model.TexturedModel; import core.engine.shader.StaticShader; +import core.engine.textures.ModelTexture; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; @@ -11,6 +12,9 @@ import org.lwjgl.opengl.GL30; import utils.MatrixGraphicUtils; import utils.vectors.Matrix4f; +import java.util.List; +import java.util.Map; + import static org.lwjgl.opengl.GL11C.*; public class Renderer { @@ -18,8 +22,10 @@ public class Renderer { private static final float NEAR_PLEANE = 0.1f; private static final float FAR_PLANE = 1000; private Matrix4f projectionMatrix; + private StaticShader shader; public Renderer(StaticShader shader) { + this.shader = shader; GL11.glEnable(GL11.GL_CULL_FACE); GL11.glCullFace(GL11.GL_BACK); createProjectionMatrix(); @@ -34,25 +40,41 @@ public class Renderer { GL11.glClearColor(5,195,221,1); } - public void render(Entity entity, StaticShader shader) { - TexturedModel texturedModel = entity.getModel(); - RawModel rawModel = texturedModel.getRawModel(); + public void render(Map> entities) { + for(TexturedModel model: entities.keySet()) { + prepareTexturedModel(model); + List batch = entities.get(model); + for(Entity entity : batch) { + prepareInstance(entity); + GL11.glDrawElements(GL11.GL_TRIANGLES, model.getRawModel().getVertexCount(), GL11.GL_UNSIGNED_INT, 0); + } + unbindTexturedModel(); + } + } + + private void prepareTexturedModel(TexturedModel model) { + RawModel rawModel = model.getRawModel(); GL30.glBindVertexArray(rawModel.getVaoID()); GL20.glEnableVertexAttribArray(0); GL20.glEnableVertexAttribArray(1); GL20.glEnableVertexAttribArray(2); - Matrix4f transformationMatrix = MatrixGraphicUtils.createTransformationMatrix(entity.getPosition(), entity.getRotX(), - entity.getRotY(), entity.getRotZ(), entity.getScale()); - shader.loadTransformationMatrix(transformationMatrix); GL13.glActiveTexture(GL13.GL_TEXTURE0); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, texturedModel.getModelTexture().getTextureID()); - GL11.glDrawElements(GL11.GL_TRIANGLES, rawModel.getVertexCount(), GL11.GL_UNSIGNED_INT, 0); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, model.getModelTexture().getTextureID()); + } + + private void unbindTexturedModel() { GL20.glDisableVertexAttribArray(0); GL20.glDisableVertexAttribArray(1); GL20.glDisableVertexAttribArray(2); GL30.glBindVertexArray(0); } + private void prepareInstance(Entity entity) { + Matrix4f transformationMatrix = MatrixGraphicUtils.createTransformationMatrix(entity.getPosition(), entity.getRotX(), + entity.getRotY(), entity.getRotZ(), entity.getScale()); + shader.loadTransformationMatrix(transformationMatrix); + } + private void createProjectionMatrix() { float aspectRatio = (float) Engine.WINDOW_WIDTH / (float) Engine.WINDOW_HEIGHT; float y_scale = (float) ((1f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio);