com.n8lm.zener.glsl.ShaderManager.java Source code

Java tutorial

Introduction

Here is the source code for com.n8lm.zener.glsl.ShaderManager.java

Source

/*
 * This file is part of Zener.
 *
 * Zener 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 3 of
 * the License, or any later version.
 *
 * Zener 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 Zener.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

package com.n8lm.zener.glsl;

import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.n8lm.zener.graphics.GLProgram;
import com.n8lm.zener.graphics.GLShader;
import com.n8lm.zener.utils.StringUtil;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;

import com.n8lm.zener.data.ResourceManager;

public class ShaderManager {

    private final static Logger LOGGER = Logger.getLogger(ShaderManager.class.getName());

    private Map<String, GLProgram> programs;
    private Map<String, GLShader> shaders;
    private Map<String, ShaderSource> shaderSources;
    private ResourceManager rm;

    public ShaderManager(ResourceManager rm) {

        programs = new HashMap<String, GLProgram>();
        shaders = new HashMap<String, GLShader>();
        shaderSources = new HashMap<String, ShaderSource>();
        this.rm = rm;
    }

    public void loadShaderSource(String name, String[] filenames) {

        String shaderCode = rm.readText(name + ".glsl");

        if (!shaderSources.containsKey(name))
            shaderSources.put(name, new ShaderSource(name, shaderCode, filenames));

        LOGGER.info("Loaded Shader Source: " + name + " " + filenames);
    }

    public GLShader buildShader(String name, List<String> macros) throws IOException {

        GLShader shader = null;

        String key = generateShaderKey(name, macros);

        ShaderSource ss = shaderSources.get(name);

        if (ss == null)
            throw new IOException("can not find glsl resource :" + name);

        String shaderCode = ss.getSource();

        String[] libnames = ss.getIndependence();

        String[] groups = StringUtil.split(name, '.');
        String type = groups[groups.length - 1];

        try {
            // check error
            if (type.equals("vert")) {
                shader = new GLShader(name, GLShader.ShaderType.Vertex);
            } else if (type.equals("frag")) {
                shader = new GLShader(name, GLShader.ShaderType.Fragment);
            } else
                throw new IOException("Error shader extension name" + name);

            for (String libname : libnames) {
                if (!shaderSources.containsKey(libname))
                    throw new IOException("can not find shader lib" + libname);
            }
            // add code
            List<String> codes = new ArrayList<String>();

            StringBuilder sb = new StringBuilder();
            sb.append("#version 330" + "\n");
            for (String macro : macros)
                sb.append("#define " + macro + "\n");
            codes.add(sb.toString());

            addUniforms(shader, shaderCode, libnames);

            for (String libname : libnames) {
                if (shaderSources.containsKey(libname))
                    codes.add(shaderSources.get(libname).getSource());
            }
            codes.add(shaderCode);

            if (shader.compile(codes)) {

                if (!shaders.containsKey(name))
                    shaders.put(name, shader);

                LOGGER.info(name + ":" + shader.getID() + " compiled");
            } else {
                LOGGER.severe("******** start shader info log*********");
                shader.printErrorLog();
                LOGGER.severe("********end shader info log*********");
            }
        } catch (IOException ex) {
            LOGGER.severe(ex.getMessage());
        }
        LOGGER.info("Builded Shader: " + name);

        return shader;
    }

    public GLProgram getProgram(String vertName, String fragName, List<String> options) {
        String key = generateProgramKey(vertName, fragName, options);
        if (programs.containsKey(key))
            return programs.get(key);
        else {
            try {
                LOGGER.info(
                        vertName + " " + fragName + Arrays.toString(options.toArray(new String[options.size()])));
                return buildProgram(vertName, fragName, options);
            } catch (IOException e) {
                e.printStackTrace();
                LOGGER.log(Level.SEVERE, "GLShader Compile Error", e);
                return null;
            }
        }
    }

    public String generateShaderKey(String name, List<String> macros) {

        StringBuilder key = new StringBuilder(name);
        key.append('(');

        for (String macro : macros) {
            key.append(macro);
            key.append(',');
        }
        return key.toString();
    }

    public String generateProgramKey(String vertName, String fragName, List<String> options) {
        StringBuilder key = new StringBuilder();
        key.append(vertName);
        key.append('_');
        key.append(fragName);
        key.append('(');
        for (String option : options) {
            key.append(option);
            key.append(',');
        }
        return key.toString();
    }

    private GLProgram buildProgram(String vertName, String fragName, List<String> options) throws IOException {
        String vertKey = generateShaderKey(vertName, options);
        String fragKey = generateShaderKey(fragName, options);

        if (!shaders.containsKey(vertKey)) {
            shaders.put(vertKey, buildShader(vertName, options));
        }
        if (!shaders.containsKey(fragKey)) {
            shaders.put(fragKey, buildShader(fragName, options));
        }

        GLShader vertShader = shaders.get(vertKey);
        GLShader fragShader = shaders.get(fragKey);

        String key = generateProgramKey(vertName, fragName, options);
        GLProgram program = new GLProgram();

        if (program.linkProgram(vertShader, fragShader) > 0) {
            programs.put(key, program);
            return program;
        } else
            return null;
    }

    private void addUniforms(GLShader shader, String code, String[] libnames) {

        GLSLStructuresVisitor svisitor = new GLSLStructuresVisitor();
        for (int i = 0; i < libnames.length; i++) {
            ANTLRInputStream input = new ANTLRInputStream(shaderSources.get(libnames[i]).getSource());
            GLSL430Lexer lexer = new GLSL430Lexer(input);
            CommonTokenStream tokens = new CommonTokenStream(lexer);
            GLSL430Parser parser = new GLSL430Parser(tokens);
            ParseTree tree = parser.translation_unit();
            svisitor.visit(tree);
        }

        ANTLRInputStream input = new ANTLRInputStream(code);
        GLSL430Lexer lexer = new GLSL430Lexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        GLSL430Parser parser = new GLSL430Parser(tokens);
        ParseTree tree = parser.translation_unit();
        svisitor.visit(tree);

        UniformsDetector visitor = new UniformsDetector(svisitor, shader);
        visitor.visit(tree);
    }
}