org.goko.tools.viewer.jogl.shaders.ShaderLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.goko.tools.viewer.jogl.shaders.ShaderLoader.java

Source

/*
 *   This file is part of Goko.
 *
 *  Goko is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Goko 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Goko.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.goko.tools.viewer.jogl.shaders;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Map;

import javax.media.opengl.GL;
import javax.media.opengl.GL3;
import javax.media.opengl.fixedfunc.GLMatrixFunc;
import javax.media.opengl.glu.GLU;
import javax.vecmath.Color4f;
import javax.vecmath.Point3f;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.goko.core.log.GkLog;
import org.goko.tools.viewer.jogl.utils.light.Light;

import com.jogamp.opengl.util.PMVMatrix;

public class ShaderLoader {
    private static final GkLog LOG = GkLog.getLogger(ShaderLoader.class);
    private static ShaderLoader instance;
    private Map<EnumGokoShaderProgram, Integer> mapShaderByType;

    private ShaderLoader() {
        this.mapShaderByType = new HashMap<EnumGokoShaderProgram, Integer>();
    }

    public static ShaderLoader getInstance() {
        if (instance == null) {
            instance = new ShaderLoader();
        }
        return instance;
    }

    public static int loadShader(GL3 gl, EnumGokoShaderProgram enumGokoShaderProgram) {
        return getInstance().loadShaderIntern(gl, enumGokoShaderProgram);
    }

    private int loadShaderIntern(GL3 gl, EnumGokoShaderProgram enumGokoShaderProgram) {
        int shaderProgram = 0;
        if (mapShaderByType.containsKey(enumGokoShaderProgram)) {
            shaderProgram = mapShaderByType.get(enumGokoShaderProgram);
        } else {
            shaderProgram = loadShader(gl,
                    getClass().getResourceAsStream(enumGokoShaderProgram.getVertexShaderPath()),
                    getClass().getResourceAsStream(enumGokoShaderProgram.getFragmentShaderPath()));
            mapShaderByType.put(enumGokoShaderProgram, shaderProgram);
        }
        return shaderProgram;
    }

    /**
     * Update the projection matrix in every loaded shader
     * @param gl gl context
     * @param matrix the camera matrix
     */
    public void updateProjectionMatrix(GL3 gl, PMVMatrix matrix) {
        matrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
        if (MapUtils.isNotEmpty(mapShaderByType)) {
            for (EnumGokoShaderProgram enumShaderProgram : mapShaderByType.keySet()) {
                Integer shaderProgram = mapShaderByType.get(enumShaderProgram);
                gl.glUseProgram(shaderProgram);
                int shaderProjectionMatrixId = gl.glGetUniformLocation(shaderProgram, "projectionMatrix");

                if (shaderProjectionMatrixId >= 0) {
                    gl.glUniformMatrix4fv(shaderProjectionMatrixId, 1, false, matrix.glGetPMatrixf());
                }
            }
        }
        gl.glUseProgram(0);
    }

    public void updateLightData(GL3 gl, Light light0, Light light1) {
        if (MapUtils.isNotEmpty(mapShaderByType)) {
            for (EnumGokoShaderProgram enumShaderProgram : mapShaderByType.keySet()) {
                Integer shaderProgram = mapShaderByType.get(enumShaderProgram);
                gl.glUseProgram(shaderProgram);
                //            int hack               = gl.glGetUniformLocation(shaderProgram, "material.ambient");
                //            if(hack >= 0){
                //               int ambient = gl.glGetUniformLocation(shaderProgram, "material.ambient");
                //               gl.glUniform3fv(ambient, 1, new float[]{0.2f,0.4f,0.2f},0);
                //               int diffuse = gl.glGetUniformLocation(shaderProgram, "material.diffuse");
                //               gl.glUniform3fv(diffuse, 1, new float[]{0.0f,1f,0},0);
                //               int specular = gl.glGetUniformLocation(shaderProgram, "material.specular");
                //               gl.glUniform3fv(specular, 1, new float[]{0.0f,0,0.5f},0);
                //            }
                // First light
                if (light0 != null) {
                    int light0ShaderId = gl.glGetUniformLocation(shaderProgram, "iLight0Position");
                    int diffuse0ShaderId = gl.glGetUniformLocation(shaderProgram, "iLight0Diffuse");
                    int ambientShaderId = gl.glGetUniformLocation(shaderProgram, "iLight0Ambient");
                    if (light0ShaderId >= 0) {
                        Point3f position = light0.getPosition();
                        gl.glUniform4fv(light0ShaderId, 1, new float[] { position.x, position.y, position.z, 1 },
                                0);
                    }
                    if (diffuse0ShaderId >= 0) {
                        Color4f diffuse = light0.getDiffuse();
                        gl.glUniform4fv(diffuse0ShaderId, 1,
                                new float[] { diffuse.x, diffuse.y, diffuse.z, diffuse.w }, 0);
                    }
                    if (ambientShaderId >= 0) {
                        Color4f ambient = light0.getAmbient();
                        gl.glUniform4fv(ambientShaderId, 1,
                                new float[] { ambient.x, ambient.y, ambient.z, ambient.w }, 0);
                    }
                }
                // Second light
                if (light1 != null) {
                    int light1ShaderId = gl.glGetUniformLocation(shaderProgram, "iLight1Position"); // Renvoi -1 si le champs n'est pas utilis dans le shader
                    int diffuse1ShaderId = gl.glGetUniformLocation(shaderProgram, "iLight1Diffuse");

                    if (light1ShaderId >= 0) {
                        Point3f p = light1.getPosition();
                        gl.glUniform4fv(light1ShaderId, 1, new float[] { p.x, p.y, p.z, 1 }, 0);
                    }
                    if (diffuse1ShaderId >= 0) {
                        Color4f c = light1.getDiffuse();
                        gl.glUniform4fv(diffuse1ShaderId, 1, new float[] { c.x, c.y, c.z, c.w }, 0);
                    }
                }
            }
        }
    }

    //   a faire :   
    //      - tester la possibilit de changer les features sans les installer/desinstaller

    protected int loadShader(GL3 gl, InputStream vertexShaderInputStream, InputStream fragmentShaderInputStream) {
        int vertexShader = gl.glCreateShader(GL3.GL_VERTEX_SHADER);
        int fragmentShader = gl.glCreateShader(GL3.GL_FRAGMENT_SHADER);

        String vertexShaderSource = getStringFromInputStream(vertexShaderInputStream);

        gl.glShaderSource(vertexShader, 1, new String[] { vertexShaderSource }, (int[]) null, 0);
        gl.glCompileShader(vertexShader);

        String fragmentShaderSource = getStringFromInputStream(fragmentShaderInputStream);

        gl.glShaderSource(fragmentShader, 1, new String[] { fragmentShaderSource }, (int[]) null, 0);
        gl.glCompileShader(fragmentShader);

        int shaderProgram = gl.glCreateProgram();
        gl.glAttachShader(shaderProgram, vertexShader);
        gl.glAttachShader(shaderProgram, fragmentShader);
        gl.glLinkProgram(shaderProgram);
        checkGlError("Link :", gl);
        checkLinkProgramm(gl, shaderProgram);
        checkCompiling(gl, vertexShader);
        checkCompiling(gl, fragmentShader);
        gl.glValidateProgram(shaderProgram);
        checkValidateProgramm(gl, shaderProgram);
        checkGlError("Validate :", gl);
        return shaderProgram;
    }

    private static void checkGlError(String str, GL3 gl) {
        int errorCheckValue = gl.glGetError();
        if (errorCheckValue != GL.GL_NO_ERROR) {
            GLU glu = new GLU();
            LOG.error(str + glu.gluErrorString(errorCheckValue));
        }
    }

    private static void checkLinkProgramm(GL3 gl, int program) {
        IntBuffer b = IntBuffer.allocate(10);
        gl.glGetProgramiv(program, GL3.GL_LINK_STATUS, b);
        ByteBuffer logBuffer = ByteBuffer.allocate(10000);
        gl.glGetProgramInfoLog(program, 10000, null, logBuffer);
        try {
            String logBufferStr = new String(logBuffer.array(), "UTF-8");
            if (StringUtils.isNotBlank(StringUtils.defaultString(logBufferStr).trim())) {
                LOG.error("CheckProgramm :" + logBufferStr);
            }
        } catch (UnsupportedEncodingException e) {
            LOG.error(e);
        }
    }

    private static void checkValidateProgramm(GL3 gl, int program) {
        IntBuffer b = IntBuffer.allocate(10);
        gl.glGetProgramiv(program, GL3.GL_VALIDATE_STATUS, b);
        ByteBuffer logBuffer = ByteBuffer.allocate(10000);

        gl.glGetProgramInfoLog(program, 10000, null, logBuffer);
        try {
            String logBufferStr = new String(logBuffer.array(), "UTF-8");
            if (StringUtils.isNotBlank(StringUtils.defaultString(logBufferStr).trim())) {
                LOG.error("Check validate programm :" + logBufferStr);
            }
        } catch (UnsupportedEncodingException e) {
            LOG.error(e);
        }
    }

    private static void checkCompiling(GL3 gl, int shader) {
        IntBuffer b = IntBuffer.allocate(10);
        gl.glGetShaderiv(shader, GL3.GL_COMPILE_STATUS, b);
        ByteBuffer logBuffer = ByteBuffer.allocate(10000);

        gl.glGetShaderInfoLog(shader, 10000, null, logBuffer);
        try {
            String logBufferStr = new String(logBuffer.array(), "UTF-8");
            if (StringUtils.isNotBlank(StringUtils.defaultString(logBufferStr).trim())) {
                LOG.error("CheckCompiling :" + logBufferStr);
            }
        } catch (UnsupportedEncodingException e) {
            LOG.error(e);
        }
    }

    private static String getStringFromInputStream(InputStream is) {
        StringWriter writer = new StringWriter();
        try {
            IOUtils.copy(is, writer);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        return writer.toString();
    }
}