com.grillecube.engine.renderer.world.terrain.TerrainRenderer.java Source code

Java tutorial

Introduction

Here is the source code for com.grillecube.engine.renderer.world.terrain.TerrainRenderer.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.terrain;

import java.util.ArrayList;

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

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.GLTexture;
import com.grillecube.engine.renderer.MainRenderer;
import com.grillecube.engine.renderer.camera.CameraProjectiveWorld;
import com.grillecube.engine.renderer.camera.CameraView;
import com.grillecube.engine.renderer.world.RendererWorld;
import com.grillecube.engine.renderer.world.ShadowCamera;
import com.grillecube.engine.resources.BlockManager;
import com.grillecube.engine.resources.R;
import com.grillecube.engine.world.World;

public class TerrainRenderer extends RendererWorld {
    /** rendering program */
    private ProgramTerrain _terrain_program;
    private ProgramTerrainReflectionRefraction _terrain_reflection_refraction_program;
    private ProgramTerrainShadow _terrain_shadow_program;

    /** terrains */
    private TerrainRendererFactory _factory;

    private ArrayList<TerrainMesh> _meshes_camera;
    private ArrayList<TerrainMesh> _meshes_shadow;

    /** dudv map */
    private GLTexture _dudvmap;
    private GLTexture _normalmap;

    /** texture atlas (blocks) */
    private boolean _can_render;

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

    @Override
    public void initialize() {
        this._terrain_program = new ProgramTerrain();
        this._terrain_reflection_refraction_program = new ProgramTerrainReflectionRefraction();
        this._terrain_shadow_program = new ProgramTerrainShadow();
        this._dudvmap = GLH.glhGenTexture(R.getResPath("textures/misc/dudvmap.png"));
        this._normalmap = GLH.glhGenTexture(R.getResPath("textures/misc/normalsmap.png"));
        this._factory = new TerrainRendererFactory();
        this._factory.initialize();
    }

    @Override
    public void deinitialize() {

        GLH.glhDeleteObject(this._terrain_program);
        this._terrain_program = null;

        GLH.glhDeleteObject(this._terrain_reflection_refraction_program);
        this._terrain_reflection_refraction_program = null;

        GLH.glhDeleteObject(this._terrain_shadow_program);
        this._terrain_shadow_program = null;

        GLH.glhDeleteObject(this._dudvmap);
        this._dudvmap = null;

        GLH.glhDeleteObject(this._normalmap);
        this._normalmap = null;

        this._factory.deinitialize();
    }

    @Override
    public void onWorldSet(World world) {
        this._factory.onWorldSet(world);
    }

    @Override
    public void onWorldUnset(World world) {
        this._factory.onWorldUnset(world);
    }

    @Override
    public void preRender() {
        this._meshes_camera = this._factory.getCameraRenderingList();
        this._meshes_shadow = this._factory.getShadowRenderingList();
        this._can_render = this._meshes_camera != null && this._meshes_camera.size() > 0;
    }

    @Override
    public void render() {

        if (!this._can_render) {
            return;
        }

        GL11.glEnable(GL11.GL_CULL_FACE);
        GL11.glCullFace(GL11.GL_BACK);

        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

        if (this.getParent().getGLFWWindow().isKeyPressed(GLFW.GLFW_KEY_F)) {
            GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
        }

        this.render(super.getCamera());

        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);

        GL11.glDisable(GL11.GL_BLEND);
        GL11.glDisable(GL11.GL_CULL_FACE);
    }

    public void bindTextureAtlas(TerrainMesh mesh, CameraView camera) {

        float distance = (float) Vector3f.distanceSquare(mesh.getTerrain().getCenter(), camera.getPosition());
        BlockManager manager = this.getParent().getResourceManager().getBlockManager();
        GLTexture texture = null;

        if (distance < (1 << 10)) {
            texture = manager.getTextureAtlas(BlockManager.RESOLUTION_16x16);
        } else if (distance < (1 << 12)) {
            texture = manager.getTextureAtlas(BlockManager.RESOLUTION_8x8);
        } else if (distance < (1 << 14)) {
            texture = manager.getTextureAtlas(BlockManager.RESOLUTION_4x4);
        } else if (distance < (1 << 16)) {
            texture = manager.getTextureAtlas(BlockManager.RESOLUTION_2x2);
        } else {
            texture = manager.getTextureAtlas(BlockManager.RESOLUTION_1x1);
        }

        if (texture != null) {
            texture.bind(GL13.GL_TEXTURE0, GL11.GL_TEXTURE_2D);
        }

    }

    public void render(CameraView camera) {

        if (!this._can_render) {
            return;
        }

        GL11.glEnable(GL11.GL_DEPTH_TEST);

        this._terrain_program.useStart();
        {
            // render with the current camera, the current world weather, no
            // clipping, using reflection and refraction fbos as texture
            this._terrain_program.loadUniforms(this.getCamera(), this.getWorld(),
                    this.getWorldRenderer().getShadowCamera());

            // bind textures

            this.getParent().getWorldRenderer().getReflectionTexture().bind(GL13.GL_TEXTURE1, GL11.GL_TEXTURE_2D);
            this.getParent().getWorldRenderer().getRefractionTexture().bind(GL13.GL_TEXTURE2, GL11.GL_TEXTURE_2D);
            this._dudvmap.bind(GL13.GL_TEXTURE3, GL11.GL_TEXTURE_2D);
            this._normalmap.bind(GL13.GL_TEXTURE4, GL11.GL_TEXTURE_2D);
            this.getParent().getWorldRenderer().getShadowMap().bind(GL13.GL_TEXTURE5, GL11.GL_TEXTURE_2D);

            for (TerrainMesh mesh : this._meshes_camera) {
                this.bindTextureAtlas(mesh, camera);
                this._terrain_program.loadInstanceUniforms(mesh);
                mesh.render();
            }
        }
        GL11.glDisable(GL11.GL_DEPTH_TEST);
    }

    private void renderReflectionRefraction(CameraProjectiveWorld camera, Vector4f clipplane) {

        if (!this._can_render) {
            return;
        }

        GL11.glEnable(GL11.GL_DEPTH_TEST);
        GL11.glEnable(GL30.GL_CLIP_DISTANCE0);

        this._terrain_reflection_refraction_program.useStart();
        {
            // render with the current camera, the current world weather, no
            // clipping, using reflection and refraction fbos as texture
            this._terrain_reflection_refraction_program.loadUniforms(camera, this.getWorld().getWeather(),
                    clipplane);

            // render every meshes
            for (TerrainMesh mesh : this._meshes_camera) {
                this.bindTextureAtlas(mesh, camera);
                this._terrain_reflection_refraction_program.loadInstanceUniforms(mesh);
                mesh.render();
            }
        }

        GL11.glDisable(GL11.GL_DEPTH_TEST);
        GL11.glDisable(GL30.GL_CLIP_DISTANCE0);
    }

    @Override
    public void renderReflection(CameraProjectiveWorld camera, Vector4f clipplane) {
        this.renderReflectionRefraction(camera, clipplane);
    }

    @Override
    public void renderRefraction(CameraProjectiveWorld camera, Vector4f clipplane) {
        this.renderReflectionRefraction(camera, clipplane);
    }

    @Override
    public void renderShadow(ShadowCamera shadow_camera) {

        // terrain do not cast shadow for now

        if (!this._can_render) {
            return;
        }

        GL11.glEnable(GL11.GL_DEPTH_TEST);
        GL11.glDisable(GL11.GL_CULL_FACE);

        this._terrain_shadow_program.useStart();
        {
            this._terrain_shadow_program.loadUniforms(shadow_camera);

            // for (TerrainMesh mesh : this._meshes_shadow) {
            for (TerrainMesh mesh : this._meshes_shadow) {
                this._terrain_shadow_program.loadInstanceUniforms(mesh);
                mesh.render();
            }
        }
        GL11.glDisable(GL11.GL_DEPTH_TEST);
    }

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

        tasks.add(engine.new Callable<Taskable>() {

            @Override
            public Taskable call() {
                _factory.update(TerrainRenderer.this);
                return (TerrainRenderer.this);
            }

            @Override
            public String getName() {
                return ("TerrainRenderer factory update");
            }
        });
    }

    public TerrainRendererFactory getTerrainFactory() {
        return (this._factory);
    }
}