com.github.begla.blockmania.rendering.ShaderManager.java Source code

Java tutorial

Introduction

Here is the source code for com.github.begla.blockmania.rendering.ShaderManager.java

Source

/*
 * Copyright 2011 Benjamin Glatzel <benjamin.glatzel@me.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.begla.blockmania.rendering;

import com.github.begla.blockmania.main.Blockmania;
import javolution.util.FastMap;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.newdawn.slick.util.ResourceLoader;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.logging.Level;

/**
 * Provides support for loading and applying shaders.
 *
 * @author Benjamin Glatzel <benjamin.glatzel@me.com>
 */
public class ShaderManager {

    private final FastMap<String, Integer> _shaderPrograms = new FastMap<String, Integer>(32);
    private final FastMap<String, Integer> _fragmentShader = new FastMap<String, Integer>(32);
    private final FastMap<String, Integer> _vertexShader = new FastMap<String, Integer>(32);
    private static ShaderManager _instance = null;

    /**
     * Returns (and creates  if necessary) the static instance
     * of this helper class.
     *
     * @return The instance
     */
    public static ShaderManager getInstance() {
        if (_instance == null) {
            _instance = new ShaderManager();
        }

        return _instance;
    }

    private ShaderManager() {
        initShaders();

        Blockmania.getInstance().getLogger().log(Level.INFO, "Loading Blockmania shader manager...");
        Blockmania.getInstance().getLogger().log(Level.INFO, "GL_VERSION: {0}", GL11.glGetString(GL11.GL_VERSION));
        Blockmania.getInstance().getLogger().log(Level.INFO, "SHADING_LANGUAGE VERSION: {0}",
                GL11.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION));
        Blockmania.getInstance().getLogger().log(Level.INFO, "EXTENSIONS: {0}",
                GL11.glGetString(GL11.GL_EXTENSIONS));
    }

    private void initShaders() {
        createVertexShader("sky_vert.glsl", "sky");
        createFragShader("sky_frag.glsl", "sky");
        createVertexShader("chunk_vert.glsl", "chunk");
        createFragShader("chunk_frag.glsl", "chunk");
        createVertexShader("cloud_vert.glsl", "cloud");
        createFragShader("cloud_frag.glsl", "cloud");
        createVertexShader("particle_vert.glsl", "particle");
        createFragShader("particle_frag.glsl", "particle");

        for (FastMap.Entry<String, Integer> e = _fragmentShader.head(), end = _fragmentShader
                .tail(); (e = e.getNext()) != end;) {
            int shaderProgram = GL20.glCreateProgram();

            GL20.glAttachShader(shaderProgram, _fragmentShader.get(e.getKey()));
            GL20.glAttachShader(shaderProgram, _vertexShader.get(e.getKey()));
            GL20.glLinkProgram(shaderProgram);
            GL20.glValidateProgram(shaderProgram);

            _shaderPrograms.put(e.getKey(), shaderProgram);
        }
    }

    private int createFragShader(String filename, String title) {

        _fragmentShader.put(title, GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER));

        if (_fragmentShader.get(title) == 0) {
            return 0;
        }

        String fragCode = "";
        String line;
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(ResourceLoader
                    .getResource("com/github/begla/blockmania/data/shaders/" + filename).openStream()));
            while ((line = reader.readLine()) != null) {
                fragCode += line + "\n";
            }
        } catch (Exception e) {
            Blockmania.getInstance().getLogger().log(Level.SEVERE, "Failed to read fragment shader.");
            return 0;
        }

        GL20.glShaderSource(_fragmentShader.get(title), fragCode);
        GL20.glCompileShader(_fragmentShader.get(title));

        printLogInfo(_fragmentShader.get(title));

        return _fragmentShader.get(title);
    }

    private int createVertexShader(String filename, String title) {

        _vertexShader.put(title, GL20.glCreateShader(GL20.GL_VERTEX_SHADER));

        if (_vertexShader.get(title) == 0) {
            return 0;
        }

        String fragCode = "";
        String line;
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(ResourceLoader
                    .getResource("com/github/begla/blockmania/data/shaders/" + filename).openStream()));
            while ((line = reader.readLine()) != null) {
                fragCode += line + "\n";
            }
        } catch (Exception e) {
            Blockmania.getInstance().getLogger().log(Level.SEVERE, "Failed to read vertex shader.");
            return 0;
        }

        GL20.glShaderSource(_vertexShader.get(title), fragCode);
        GL20.glCompileShader(_vertexShader.get(title));

        printLogInfo(_vertexShader.get(title));

        return _vertexShader.get(title);
    }

    private static void printLogInfo(int obj) {
        IntBuffer intBuffer = BufferUtils.createIntBuffer(1);
        GL20.glGetShader(obj, GL20.GL_INFO_LOG_LENGTH, intBuffer);

        int length = intBuffer.get();

        if (length <= 1) {
            return;
        }

        ByteBuffer infoBuffer = BufferUtils.createByteBuffer(length);
        intBuffer.flip();

        GL20.glGetShaderInfoLog(obj, intBuffer, infoBuffer);

        int actualLength = intBuffer.get();
        byte[] infoBytes = new byte[actualLength];
        infoBuffer.get(infoBytes);

        Blockmania.getInstance().getLogger().log(Level.INFO, "{0}", new String(infoBytes));
    }

    /**
     * @param s Name of the shader to activate
     */
    public void enableShader(@org.jetbrains.annotations.Nullable String s) {
        if (s == null) {
            GL20.glUseProgram(0);
            return;
        }

        int shader = getShader(s);
        GL20.glUseProgram(shader);
    }

    /**
     * @param s Nave of the shader to return
     * @return The id of the requested shader
     */
    public int getShader(String s) {
        return _shaderPrograms.get(s);
    }
}