vertigo.graphics.lwjgl.LWJGL_Renderer.java Source code

Java tutorial

Introduction

Here is the source code for vertigo.graphics.lwjgl.LWJGL_Renderer.java

Source

/*
 * $Id:$
 *
 * Vertigo_viewer: 3D Viewer Plugin for ImageJ.
 * Copyright (C) 2013 Jean-Christophe Taveau.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 *
 * Authors :
 * Florin Buga
 * Olivier Catoliquot
 * Clement Delestre
 */
package vertigo.graphics.lwjgl;

import ij.IJ;
import java.awt.Dimension;
import java.nio.IntBuffer;
import java.util.ArrayList;
import org.lwjgl.opengl.GL11;
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
import static org.lwjgl.opengl.GL11.glColorPointer;
import static org.lwjgl.opengl.GL11.glDrawElements;
import static org.lwjgl.opengl.GL11.glVertexPointer;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL32;
import vertigo.scenegraph.Camera;
import vertigo.scenegraph.Light;
import vertigo.scenegraph.Node;
import vertigo.scenegraph.World;
import vertigo.graphics.Attribute;
import vertigo.graphics.BO;
import vertigo.graphics.BufferTools;
import vertigo.graphics.IBO;
import vertigo.graphics.Renderer;
import vertigo.graphics.ShaderProg;
import vertigo.scenegraph.Shape;
import vertigo.graphics.Uniform;
import vertigo.graphics.UpdateVisitor;
import vertigo.graphics.VBO;

/**
 * Class LWJGL_Renderer
 *
 * @author Florin Buga
 * @author Olivier Catoliquot
 * @author Clement Delestre
 * @version 0.1
 *
 */
public class LWJGL_Renderer implements Renderer {

    /**
     * Check if the shape have IBO or not.
     */
    private boolean isIndexed = false;
    /**
     * IBO.
     * @see IBO
     */
    private IBO ibo = null;
    /**
     * VBO.
     * @see VBO.
     */
    private VBO vbo3f = null;
    /**
     * The VBO's length.
     */
    private int capacity = 0;

    /**
     * ArrayList of shader's attribute.
     * @see Attribute
     */
    private ArrayList<Attribute> attribute;
    private IntBuffer ib;

    /**
      * The window's background red component
      *
      * @see LWJGL_Renderer#setBackgroundColor(float, float, float) 
      */
    private float red;

    /**
    * The window's background green component
    *
    * @see LWJGL_Renderer#setBackgroundColor(float, float, float) 
    */
    private float green;

    /**
    * The window's background blue component
    *
    * @see LWJGL_Renderer#setBackgroundColor(float, float, float) 
    */
    private float blue;

    private World world;
    private Camera cam_;

    private ArrayList<ShaderProg> shaders;
    private ArrayList<Shape> shapes;
    private ArrayList<Light> lights;
    private Dimension newDim;

    /**
     * The LWJGL_Visitor
     *
     * @see LWJGL_Renderer#display() 
     * @see LWJGL_Visitor
     */
    private UpdateVisitor visitor;

    /**
     * Constructor.
     */
    public LWJGL_Renderer() {
        shapes = new ArrayList<Shape>();
        lights = new ArrayList<Light>();
        shaders = new ArrayList<ShaderProg>();
        visitor = new UpdateVisitor();
    }

    @Override
    public void setBackgroundColor(float red, float green, float blue) {
        this.red = red;
        this.green = green;
        this.blue = blue;
    }

    public void setWorld(World world) {
        this.world = world;
        this.cam_ = (Camera) world.getNode("camera");
    }

    public void init() {
        // Flatten scenegraph
        initDrawables(world);

        // Init shaders
        initShaders();

        // Init VBOs
        for (Shape shape : shapes)
            initVBO(shape);

        // Init OpenGL configuration
        initGL();
    }

    public void display() {
        GL11.glClearColor(red, green, blue, 1.0f);
        GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_COLOR_BUFFER_BIT);
        world.accept(visitor);
        for (Shape shape : shapes) {
            // shape
            drawShape(shape);
        }

    }

    void syncViewportSize(int i, int i0, int width, int height) {
        GL11.glViewport(0, 0, newDim.width, newDim.height);
    }

    /**
     * Clean memory when the window is closed
     */
    public void dispose() {
        GL15.glDeleteBuffers(ib);
        // HACK glshader.setHandle(ShaderProg.UNKNOWN);
        // HACK GL20.glDeleteProgram(glshader.getHandle());
    }

    private void drawShape(Shape obj) {
        // Geometry: VBO and IBO
        if (obj.isDirty(Node.VBO)) {
            processBO(obj);
            obj.setDirty(Node.VBO, false);
        }

        ShaderProg glshader = obj.getMaterial().getShaderMaterial();
        GL20.glUseProgram(glshader.getHandle());

        updateUniform();
        VBO vbo = null;

        for (Attribute attrib : attribute) {
            if (vbo.getType().equals(attrib.getType())) {
                int alocation = GL20.glGetAttribLocation(glshader.getHandle(), attrib.getName());
                GL20.glEnableVertexAttribArray(alocation);
                GL20.glVertexAttribPointer(alocation, attrib.getSize(), GL11.GL_FLOAT, false, vbo.getStride() << 2,
                        0L);
            }
        }

        if (isIndexed) {
            // draw with index
            GL11.glDrawElements(getOpenGLStyle(obj.getDrawingStyle()), /* elements */ ibo.getSize(),
                    GL_UNSIGNED_INT, 0L);
            GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
            GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
            GL20.glDisableVertexAttribArray(0);
        } else {
            // draw without index
            GL11.glDrawArrays(getOpenGLStyle(obj.getDrawingStyle()), 0, capacity / vbo3f.getStride());
            GL20.glDisableVertexAttribArray(0);
            GL30.glBindVertexArray(0);
        }

        GL20.glUseProgram(0);
    }

    /**
     * Process the shader.
     * @param obj shader
     */
    private void initShaders() {
        int handle;
        for (ShaderProg glshader : shaders) {
            // compile once
            if (glshader.getHandle() == ShaderProg.UNKNOWN) {
                try {
                    handle = ShaderUtils.attachShaders(glshader.getVertexSource(), glshader.getFragmentSource());
                    glshader.setHandle(handle);
                } catch (Exception e) {
                    IJ.log("Error with the Shader " + e);
                } //Compile, Link error
            }
        }
    }

    private void initDrawables(Node obj) {
        if (obj instanceof Camera) {
            cam_ = (Camera) obj;
        } else if (obj instanceof Shape) {
            shapes.add((Shape) obj);
        } else if (obj instanceof Light) {
            lights.add((Light) obj);
        }
        for (Node child : obj.getChildren()) {
            initDrawables(child);
        }
    }

    /**
      * Process the BO.
      * @param obj shape
      */
    private void initVBO(Shape obj) {
        int nbBO = obj.getGeometry().getNumberBO(); //return 2 for the cube (1 vbo + 1 ibo)
        ib = BufferTools.newIntBuffer(nbBO);
        GL15.glGenBuffers(ib);
        int i = 0;
        for (BO bo : obj.getGeometry().getAllBO()) {
            int boHandle = ib.get(i);
            bo.setHandle(boHandle);
            if (bo instanceof IBO) {
                isIndexed = true;
                ibo = (IBO) bo;
                GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, boHandle);
                GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, ibo.getIntBuffer(), GL15.GL_STATIC_DRAW);
                GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
            } else {
                VBO vbo = (VBO) bo;
                //if (!vbo.getBuffer().isLoaded() ) {
                GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, boHandle);
                GL15.glBufferData(GL15.GL_ARRAY_BUFFER, vbo.getFloatBuffer(), GL15.GL_STATIC_DRAW);
                GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
                //}
            }
            i++;
        }
        GL15.glDeleteBuffers(ib);
    }

    public void initGL() {

    }

    /**
     * Makes conversion Vertigo style/OpenGL style
     * @param vertigo_style
     * @return 
     */
    private int getOpenGLStyle(String vertigo_style) {
        int style = calcIndex(vertigo_style);
        switch (style) {
        case 379: // LINES
            return GL11.GL_LINES;
        case 1116: // LINES_ADJACENCY
            return GL32.GL_LINES_ADJACENCY;
        case 705: // LINE_LOOP
            return GL11.GL_LINE_LOOP;
        case 793: // LINE_STRIP
            return GL11.GL_LINE_STRIP;
        case 1530: // LINE_STRIP_ADJACENCY
            return GL32.GL_LINE_STRIP_ADJACENCY;
        case 477: // POINTS
            return GL11.GL_POINTS;
        case 681: // TRIANGLES
            return GL11.GL_TRIANGLES;
        case 1418: // TRIANGLES_ADJACENCY
            return GL32.GL_TRIANGLES_ADJACENCY;
        case 906: // TRIANGLE_FAN
            return GL11.GL_TRIANGLE_FAN;
        case 1095: // TRIANGLE_STRIP
            return GL11.GL_TRIANGLE_STRIP;
        case 1832: // TRIANGLE_STRIP_ADJACENCY
            return GL32.GL_TRIANGLE_STRIP_ADJACENCY;
        default: // Do nothing  
            return -1;
        }
    }

    /**
     * Calc index by summing all the Unicode values in the string 'name'
     *
     * @param name
     * @return index
     */
    private static int calcIndex(String name) {
        int index = 0;
        for (int i = 0; i < name.length(); i++) {
            index += (int) name.charAt(i);
        }
        return index;
    }

    /**
     * Attrib the good type of pointer
     *
     * @param vbo
     *
     */
    private void pointer(VBO vbo) {
        if (vbo.getType().contains("V")) {
            glVertexPointer(vbo.getSize(), GL11.GL_FLOAT, /* stride */ vbo.getStride() << 2, 0L);
        } else if (vbo.getType().contains("C")) {
            glColorPointer(vbo.getSize(), GL11.GL_FLOAT, /* stride */ vbo.getStride() << 2, 0L);
        }
    }

    /**
     * Enable the good type of VBO
     *
     * @param vbo
     */
    private void enable(VBO vbo) {
        if (vbo.getType().contains("V")) {
            vbo3f = vbo;
            capacity = vbo.capacity();
            GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
        }
        if (vbo.getType().contains("C")) {
            GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
        }
    }

    /**
     * Links shader's uniform variable.
     * @param obj shape
     */
    private void updateUniform() {
        /***
                ArrayList<Uniform> uniforms = glshader.getAllUniforms();
                for (Uniform uni : uniforms) {
        if (uni.getType().equals("view_matrix")) {
            int vlocation = GL20.glGetUniformLocation(glshader.getHandle(), uni.getName());
            GL20.glUniformMatrix4(vlocation, false, cam_.getViewMatrix().toColumnBuffer());
        } else if (uni.getType().equals("proj_matrix")) {
            int plocation = GL20.glGetUniformLocation(glshader.getHandle(), uni.getName());
            GL20.glUniformMatrix4(plocation, false, cam_.getProjection().toColumnBuffer());
        } else if (uni.getType().equals("matrix")) {
            int mlocation = GL20.glGetUniformLocation(glshader.getHandle(), uni.getName());
            GL20.glUniformMatrix4(mlocation, false, obj.getModelMatrix().toColumnBuffer());
        } else if (uni.getType().equals("C4F")) {
            int clocation = GL20.glGetUniformLocation(glshader.getHandle(), uni.getName());
            float[] color = new float[4];
            color = obj.getMaterial().getColor();
            GL20.glUniform4f(clocation, color[0], color[1], color[2], color[3]);
        }
                }
        ***/
    }

} // end of class LWJGL_Renderer