com.grillecube.engine.renderer.world.WorldRenderer.java Source code

Java tutorial

Introduction

Here is the source code for com.grillecube.engine.renderer.world.WorldRenderer.java

Source

/**
**   This file is part of the project https://github.com/toss-dev/VoxelEngine
**
**   License is available here: https://raw.githubusercontent.com/toss-dev/VoxelEngine/master/LICENSE.md
**
**   PEREIRA Romain
**                                       4-----7          
**                                      /|    /|
**                                     0-----3 |
**                                     | 5___|_6
**                                     |/    | /
**                                     1-----2
*/

package com.grillecube.engine.renderer.world;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;

import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL14;
import org.lwjgl.opengl.GL30;

import com.grillecube.engine.Logger;
import com.grillecube.engine.Taskable;
import com.grillecube.engine.VoxelEngine;
import com.grillecube.engine.maths.Vector3f;
import com.grillecube.engine.maths.Vector4f;
import com.grillecube.engine.opengl.GLH;
import com.grillecube.engine.opengl.object.GLFrameBuffer;
import com.grillecube.engine.opengl.object.GLRenderBuffer;
import com.grillecube.engine.opengl.object.GLTexture;
import com.grillecube.engine.renderer.MainRenderer;
import com.grillecube.engine.renderer.Renderer;
import com.grillecube.engine.renderer.camera.CameraPerspectiveWorld;
import com.grillecube.engine.renderer.camera.CameraProjectiveWorld;
import com.grillecube.engine.renderer.model.ModelRenderer;
import com.grillecube.engine.renderer.world.lines.LineRenderer;
import com.grillecube.engine.renderer.world.particles.ParticleRenderer;
import com.grillecube.engine.renderer.world.sky.SkyRenderer;
import com.grillecube.engine.renderer.world.terrain.TerrainRenderer;
import com.grillecube.engine.sound.ALH;
import com.grillecube.engine.world.World;

public class WorldRenderer extends Renderer {

    public static final int REFLECTION_FBO_WIDTH = 640;
    public static final int REFLECTION_FBO_HEIGHT = (int) (REFLECTION_FBO_WIDTH / 1.6f);

    public static final int REFRACTION_FBO_WIDTH = 500;
    public static final int REFRACTION_FBO_HEIGHT = (int) (REFRACTION_FBO_WIDTH / 1.6f);

    public static final int SHADOW_FBO_WIDTH = 2048; // the bigger the better
    public static final int SHADOW_FBO_HEIGHT = SHADOW_FBO_WIDTH;

    // reflection fbo
    private GLFrameBuffer _reflection_fbo;
    private GLTexture _reflection_texture;
    private GLRenderBuffer _reflection_depth_buffer;

    // refraction fbo
    private GLFrameBuffer _refraction_fbo;
    private GLTexture _refraction_texture;
    private GLRenderBuffer _refraction_depth_buffer;

    // shadow fbo
    private GLFrameBuffer _shadow_fbo;
    private GLTexture _shadow_map;

    /** a clipping plane that does not clip anything */
    public static final Vector4f NO_CLIPPING = new Vector4f(0, 0, 0, 0);

    /** sky renderer */
    private SkyRenderer _sky_renderer;

    /** line renderer */
    private LineRenderer _line_renderer;

    /** main terrain renderer */
    private TerrainRenderer _terrain_renderer;

    /** model view projection renderer */
    private MVPRenderer _mvp_renderer;

    /** model renderer */
    private ModelRenderer _model_renderer;

    /** particles renderer */
    private ParticleRenderer _particle_renderer;

    /** shadows */
    private ShadowCamera _shadow_camera;

    /** world to render */
    private World _world;

    /** renderers */
    private ArrayList<RendererWorld> _renderers;

    public WorldRenderer(MainRenderer main_renderer) {
        super(main_renderer);
    }

    @Override
    public void initialize() {

        Logger.get().log(Logger.Level.DEBUG, "Initializing " + this.getClass().getSimpleName());

        this._renderers = new ArrayList<RendererWorld>();

        this._sky_renderer = new SkyRenderer(this.getParent());
        this._line_renderer = new LineRenderer(this.getParent());
        this._terrain_renderer = new TerrainRenderer(this.getParent());
        this._model_renderer = new ModelRenderer(this.getParent());
        this._mvp_renderer = new MVPRenderer(this.getParent());
        this._particle_renderer = new ParticleRenderer(this.getParent());

        this._renderers.add(this._sky_renderer);
        this._renderers.add(this._line_renderer);
        this._renderers.add(this._terrain_renderer);
        this._renderers.add(this._model_renderer);
        this._renderers.add(this._mvp_renderer);
        this._renderers.add(this._particle_renderer);

        this.createReflectionFBO();
        this.createRefractionFBO();
        this.createShadowFBO();

        this._shadow_camera = new ShadowCamera(this.getParent().getGLFWWindow());

        for (RendererWorld renderer : this._renderers) {
            Logger.get().log(Logger.Level.DEBUG, "Initializing " + renderer.getClass().getSimpleName());
            renderer.initialize();
        }
    }

    @Override
    public void deinitialize() {

        Logger.get().log(Logger.Level.DEBUG, "Deinitializing " + this.getClass().getSimpleName());

        this.deleteReflectionFBO();
        this.deleteRefractionFBO();
        this.deleteShadowFBO();

        for (RendererWorld renderer : this._renderers) {
            Logger.get().log(Logger.Level.DEBUG, "Deinitializing " + renderer.getClass().getSimpleName());
            renderer.deinitialize();
        }
    }

    private void onWorldSet(World world) {
        for (RendererWorld renderer : this._renderers) {
            renderer.onWorldSet(world);
        }

    }

    private void onWorldUnset(World world) {
        for (RendererWorld renderer : this._renderers) {
            renderer.onWorldUnset(world);
        }
    }

    /** add a renderer to be render every frames */
    public void addRenderer(RendererWorld renderer) {
        this._renderers.remove(this._particle_renderer);
        this._renderers.add(renderer);
        this._renderers.add(this._particle_renderer);
    }

    @Override
    public void preRender() {

        // pre render every renderer
        for (RendererWorld renderer : this._renderers) {
            renderer.preRender();
            GLH.glhCheckError("post " + renderer.getClass().getSimpleName() + ".preRender()");
        }

        // // update reflection and refraction fbos
        // //TODO : put a config and only render reflection / refraction if
        // needed
        // this.renderReflectionRefraction();
        //
        // // update shadow map
        // //TODO : put a config and only render shadow if needed
        //      this.renderShadows();

        if (GLH.glhGetContext().getWindow().isKeyPressed(GLFW.GLFW_KEY_C)) {
            this.getParent().getResourceManager().getSoundManager().playSoundAt(
                    ALH.alhLoadSound("C:/Users/Romain/AppData/Roaming/VoxelEngine/assets/POT/sounds/acoustic1.wav"),
                    this.getCamera().getPosition(), new Vector3f(0, 0, 0));
        }
    }

    @Override
    public void postRender() {
        for (RendererWorld renderer : this._renderers) {
            renderer.postRender();
            GLH.glhCheckError("post " + renderer.getClass().getSimpleName() + ".postRender()");
        }
    }

    /** render the given world */
    @Override
    public void render() {

        // README : commented stuff are used to debug renderer. To see different
        // performances

        GLH.glhCheckError("pre world renderer");

        // long total = 0;
        // long times[] = new long[this._renderers.size()];
        //
        // final world renderer
        for (int i = 0; i < this._renderers.size(); i++) {

            RendererWorld renderer = this._renderers.get(i);
            //
            // long time = System.nanoTime();
            renderer.render();
            // long difft = System.nanoTime() - time;
            // times[i] = difft;
            // total += difft;
            //
            GLH.glhCheckError("post " + renderer.getClass().getSimpleName() + ".render()");
        }

        // float ftotal = 0;
        // for (int i = 0 ; i < this._renderers.size() ; i++) {
        //
        // RendererWorld renderer = this._renderers.get(i);
        // float ftime = times[i] / (float)total;
        // ftotal += ftime;
        // Logger.get().log(Logger.Level.DEBUG,
        // renderer.getClass().getSimpleName(), ftime);
        // }

        // Logger.get().log(Logger.Level.DEBUG, "/" + ftotal);
        // Logger.get().log(Logger.Level.DEBUG, " ");

    }

    /** render reflection and refraction to the main renderer fbos */
    private Vector4f _clipplane = new Vector4f();

    /** render reflection and refraction planes to their given fbos */
    public void renderReflectionRefraction() {

        // save current camera
        CameraProjectiveWorld realcamera = this.getCamera();
        float liquid_height = realcamera.getLiquidHeight();
        // float liquid_height = realcamera.getLiquidHeight();

        // REFLECTION STARTS HERE

        // copy of the currentcamera
        CameraProjectiveWorld camera = (CameraProjectiveWorld) realcamera.clone();
        float distance = 2 * (camera.getPosition().y - liquid_height);
        camera.getPosition().y -= distance;
        camera.invertPitch();
        camera.invertRoll();
        camera.update();

        this.getReflectionFBO().bind();
        this.getReflectionFBO().clear();
        this.getReflectionFBO().viewport(0, 0, REFLECTION_FBO_WIDTH, REFLECTION_FBO_HEIGHT);
        this._clipplane.set(0, 1, 0, -liquid_height);
        for (RendererWorld renderer : this._renderers) {
            renderer.renderReflection(camera, this._clipplane);
            GLH.glhCheckError("post " + renderer.getClass().getSimpleName() + ".renderReflection()");
        }
        this.getReflectionFBO().unbind();

        // REFRACTION STARTS HERE
        this.getRefractionFBO().bind();
        this.getRefractionFBO().clear();
        this.getRefractionFBO().viewport(0, 0, REFRACTION_FBO_WIDTH, REFRACTION_FBO_HEIGHT);
        this._clipplane.set(0, -1, 0, liquid_height);
        for (RendererWorld renderer : this._renderers) {
            renderer.renderRefraction(realcamera, this._clipplane);
            GLH.glhCheckError("post " + renderer.getClass().getSimpleName() + ".renderRefraction()");
        }
        this.getRefractionFBO().unbind();
    }

    private void renderShadows() {

        if (!(this.getCamera() instanceof CameraPerspectiveWorld)) {
            return;
        }

        this._shadow_camera.update(this.getWorld(), this.getCamera());

        this.getShadowMapFBO().bind();
        this.getShadowMapFBO().clear();
        this.getShadowMapFBO().viewport(0, 0, SHADOW_FBO_WIDTH, SHADOW_FBO_HEIGHT);

        // render shadows
        for (RendererWorld renderer : this._renderers) {
            renderer.renderShadow(this._shadow_camera);
            GLH.glhCheckError("post " + renderer.getClass().getSimpleName() + ".renderShadow(ShadowBox shadowbox)");
        }

        this.getShadowMapFBO().unbind();
    }

    public void setWorld(World world) {

        World prevworld = this._world;
        this._world = world;

        // if we are setting a world and none was set before
        if (prevworld == null && world != null) {
            // initialize renderers
            this.initialize();
            this.onWorldSet(world);
            // else if we are changing the world
        } else if (prevworld != null && world != null) {

            this.onWorldUnset(prevworld);
            this.onWorldSet(world);

            // else if we are setting a null world but one was set before
        } else if (prevworld != null && world == null) {
            this.onWorldUnset(prevworld);
            this.deinitialize();
        }
    }

    public World getWorld() {
        return (this._world);
    }

    /** return the default particle renderer */
    public ParticleRenderer getParticleRenderer() {
        return (this._particle_renderer);
    }

    public MVPRenderer getMVPRenderer() {
        return (this._mvp_renderer);
    }

    public CameraProjectiveWorld getCamera() {
        return (this.getParent().getCamera());
    }

    public TerrainRenderer getTerrainRenderer() {
        return (this._terrain_renderer);
    }

    public LineRenderer getLineRenderer() {
        return (this._line_renderer);
    }

    private void createReflectionFBO() {

        this._reflection_fbo = GLH.glhGenFBO();
        this._reflection_fbo.bind();
        this._reflection_fbo.createDrawBuffer(GL30.GL_COLOR_ATTACHMENT0);

        this._reflection_texture = GLH.glhGenTexture();
        this._reflection_texture.bind(GL11.GL_TEXTURE_2D);
        this._reflection_texture.bind(GL13.GL_TEXTURE0, GL11.GL_TEXTURE_2D);
        this._reflection_texture.image2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, REFLECTION_FBO_WIDTH,
                REFLECTION_FBO_HEIGHT, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null);
        this._reflection_texture.parameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
        this._reflection_texture.parameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
        this._reflection_fbo.createTextureAttachment(this._reflection_texture, GL30.GL_COLOR_ATTACHMENT0);

        this._reflection_depth_buffer = this._reflection_fbo.createRenderBuffer(REFLECTION_FBO_WIDTH,
                REFLECTION_FBO_HEIGHT, GL30.GL_DEPTH_ATTACHMENT);

        this._reflection_fbo.unbind();
    }

    private void deleteReflectionFBO() {
        GLH.glhDeleteObject(this._reflection_fbo);
        GLH.glhDeleteObject(this._reflection_texture);
        GLH.glhDeleteObject(this._reflection_depth_buffer);
    }

    private void createRefractionFBO() {

        this._refraction_fbo = GLH.glhGenFBO();
        this._refraction_fbo.bind();
        this._refraction_fbo.createDrawBuffer(GL30.GL_COLOR_ATTACHMENT0);

        this._refraction_texture = GLH.glhGenTexture();
        this._refraction_texture.bind(GL11.GL_TEXTURE_2D);
        this._refraction_texture.bind(GL13.GL_TEXTURE0, GL11.GL_TEXTURE_2D);
        this._refraction_texture.image2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, REFRACTION_FBO_WIDTH,
                REFRACTION_FBO_HEIGHT, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null);
        this._refraction_texture.parameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
        this._refraction_texture.parameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
        this._refraction_fbo.createTextureAttachment(this._refraction_texture, GL30.GL_COLOR_ATTACHMENT0);

        this._refraction_depth_buffer = this._reflection_fbo.createRenderBuffer(REFRACTION_FBO_WIDTH,
                REFRACTION_FBO_HEIGHT, GL30.GL_DEPTH_ATTACHMENT);

        this._refraction_fbo.unbind();
    }

    private void deleteRefractionFBO() {
        GLH.glhDeleteObject(this._refraction_fbo);
        GLH.glhDeleteObject(this._refraction_texture);
        GLH.glhDeleteObject(this._refraction_depth_buffer);
    }

    private void createShadowFBO() {

        this._shadow_fbo = GLH.glhGenFBO();
        this._shadow_fbo.bind();
        this._shadow_fbo.createDrawBuffer(GL11.GL_NONE);

        this._shadow_map = GLH.glhGenTexture();
        this._shadow_map.bind(GL11.GL_TEXTURE_2D);

        this._shadow_map.image2D(GL11.GL_TEXTURE_2D, 0, GL14.GL_DEPTH_COMPONENT16, SHADOW_FBO_WIDTH,
                SHADOW_FBO_HEIGHT, 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (ByteBuffer) null);
        this._shadow_map.parameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
        this._shadow_map.parameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
        this._shadow_map.parameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
        this._shadow_map.parameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
        this._shadow_fbo.createTextureAttachment(this._shadow_map, GL30.GL_DEPTH_ATTACHMENT);

        this._shadow_fbo.unbind();
    }

    private void deleteShadowFBO() {
        GLH.glhDeleteObject(this._shadow_fbo);
        GLH.glhDeleteObject(this._shadow_map);
    }

    public GLFrameBuffer getReflectionFBO() {
        return (this._reflection_fbo);
    }

    public GLFrameBuffer getRefractionFBO() {
        return (this._refraction_fbo);
    }

    public GLFrameBuffer getShadowMapFBO() {
        return (this._shadow_fbo);
    }

    public GLTexture getReflectionTexture() {
        return (this._reflection_texture);
    }

    public GLTexture getRefractionTexture() {
        return (this._refraction_texture);
    }

    public GLTexture getShadowMap() {
        return (this._shadow_map);
    }

    public ShadowCamera getShadowCamera() {
        return (this._shadow_camera);
    }

    public Collection<RendererWorld> getRenderers() {
        return (this._renderers);
    }

    @Override
    public void getTasks(VoxelEngine engine, ArrayList<VoxelEngine.Callable<Taskable>> tasks) {

        World world = this.getWorld();
        CameraProjectiveWorld camera = this.getCamera();

        if (world == null || camera == null) {
            return;
        }

        for (RendererWorld renderer : this.getRenderers()) {
            renderer.getTasks(engine, tasks, world, camera);
        }
    }

    /** request the world renderer to update reflection/refraciton textures */
    public void requestReflectionRefractionUpdate() {
        // TODO
    }
}