Java tutorial
/* * This file is part of Engine, licensed under the Apache 2.0 License. * * Copyright (c) 2014 thehutch. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package me.thehutch.fusion.engine.render; import static org.lwjgl.opengl.GL11.GL_BACK; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_CULL_FACE; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST; import static org.lwjgl.opengl.GL32.GL_DEPTH_CLAMP; import java.nio.file.Path; import me.thehutch.fusion.api.component.Aspect; import me.thehutch.fusion.api.component.IComponentMapper; import me.thehutch.fusion.api.component.IEntity; import me.thehutch.fusion.api.component.annotations.Mapper; import me.thehutch.fusion.api.component.processors.BatchEntityProcessor; import me.thehutch.fusion.api.maths.Matrix4; import me.thehutch.fusion.api.render.Camera; import me.thehutch.fusion.api.util.container.ImmutableBag; import me.thehutch.fusion.engine.Client; import me.thehutch.fusion.engine.Engine; import me.thehutch.fusion.engine.component.RenderComponent; import me.thehutch.fusion.engine.component.TransformComponent; import me.thehutch.fusion.engine.filesystem.FileSystem; import me.thehutch.fusion.engine.render.opengl.Program; import me.thehutch.fusion.engine.render.opengl.VertexArray; import me.thehutch.fusion.engine.util.RenderUtil; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.GL11; public final class Renderer extends BatchEntityProcessor { public static final Path MATERIAL_DIRECTORY = FileSystem.DATA_DIRECTORY.resolve("materials"); public static final Path TEXTURE_DIRECTORY = FileSystem.DATA_DIRECTORY.resolve("textures"); public static final Path PROGRAM_DIRECTORY = FileSystem.DATA_DIRECTORY.resolve("programs"); public static final Path SHADER_DIRECTORY = FileSystem.DATA_DIRECTORY.resolve("shaders"); public static final Path MESH_DIRECTORY = FileSystem.DATA_DIRECTORY.resolve("meshes"); // Scene camera private final Camera camera; // Game engine private final Client engine; // Render component mapper @Mapper private IComponentMapper<RenderComponent> renderMapper; // Transform component mapper @Mapper private IComponentMapper<TransformComponent> transformMapper; public Renderer(Client engine, Camera camera) { super(Aspect.newAspectForAll(RenderComponent.class, TransformComponent.class)); this.camera = camera; this.engine = engine; } public Camera getCamera() { return camera; } @Override public void initialise() { // Enable depth testing GL11.glEnable(GL_DEPTH_TEST); GL11.glEnable(GL_DEPTH_CLAMP); // Enable face culling GL11.glEnable(GL_CULL_FACE); GL11.glCullFace(GL_BACK); // Create an example model for testing final RenderComponent render = new RenderComponent(getMaterial("ground.fmat"), getMesh("ground.obj")); final TransformComponent transform = new TransformComponent(); // Create a temporary entity final IEntity e = mSystem.createEntity(); // Add the render & transform components e.addComponent(render); e.addComponent(transform); // Add the entity to the system e.addToSystem(); } @Override public void begin() { // Clear the colour and depth buffers GL11.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } @Override public void end() { // Update the display Display.update(); // Check for errors RenderUtil.checkGLError(); } @Override public void processEntities(ImmutableBag<IEntity> entities) { // Calculate the camera matrix (projection * view) final Matrix4 cameraMatrix = camera.getProjectionMatrix().mul(camera.getViewMatrix()); // Render the models entities.forEach((IEntity e) -> { // Get the render and transform components final RenderComponent render = renderMapper.get(e); final TransformComponent transform = transformMapper.get(e); // Render the entity render(render, transform, cameraMatrix); }); // Enable blending // GL11.glEnable(GL_BLEND); // GL11.glBlendFunc(GL_ONE, GL_ONE); // GL11.glDepthMask(false); // GL11.glDepthFunc(GL_EQUAL); // // TODO: Perform the light render pass. // { // // Render each of the lights in the scene // this.lights.stream().forEach((Light light) -> { // final Program program = light.getProgram(); // program.bind(); // light.uploadUniforms(); // // Set the camera matrix // program.setUniform("cameraMatrix", cameraMatrix); // // Set the position of the camera // program.setUniform("cameraPos", camera.getPosition()); // // Render all the models // this.models.stream().forEach((Model model) -> { // model.getMaterial().uploadUniforms(program); // model.render(program); // }); // program.unbind(); // }); } // Disable blending // GL11.glDepthMask(true); // GL11.glDepthFunc(GL_LESS); // GL11.glDisable(GL_BLEND); } @Override public boolean checkProcessing() { return !getActives().isEmpty(); } @Override public void inserted(IEntity e) { Engine.getLogger().info("Entity added to Renderer"); } @Override public void removed(IEntity e) { Engine.getLogger().info("Entity removed from Renderer"); } private VertexArray getMesh(String name) { return engine.getFileSystem().getResource(MESH_DIRECTORY.resolve(name)); } private Material getMaterial(String name) { return engine.getFileSystem().getResource(MATERIAL_DIRECTORY.resolve(name)); } private void render(RenderComponent render, TransformComponent transform, Matrix4 camera) { final Material material = render.getMaterial(); final Program program = material.getProgram(); // Bind the material material.bind(); material.uploadUniforms(); // Set the camera matrix program.setUniform("cameraMatrix", camera); // Create the scale, rotation and translation matrices final Matrix4 scaleMatrix = Matrix4.newScale(transform.getScale()); final Matrix4 rotationMatrix = Matrix4.newRotation(transform.getRotation()); final Matrix4 translationMatrix = Matrix4.newTranslation(transform.getPosition()); // Set the model and normal matrix uniforms final Matrix4 modelMatrix = scaleMatrix.mul(rotationMatrix).mul(translationMatrix); program.setUniform("modelMatrix", modelMatrix); program.setUniform("normalMatrix", modelMatrix.invert().transpose().toMatrix3()); // Draw the mesh render.getMesh().draw(); } }