Java tutorial
/* * This file is part of the lunar-fever package. * * Copyright (c) 2014 Eric Fritz * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.kauridev.lunarfever.graphics; import java.nio.FloatBuffer; import java.util.List; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.ContextCapabilities; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GLContext; import org.lwjgl.util.vector.Matrix4f; /** * @author Eric Fritz */ public class ShaderProgram { private int program; private int vert; private int frag; public static boolean isSupported() { ContextCapabilities c = GLContext.getCapabilities(); return c.GL_ARB_shader_objects && c.GL_ARB_vertex_shader && c.GL_ARB_fragment_shader; } public ShaderProgram(String vertexShaderSource, String fragShaderSource, List<VertexAttribute> attribLocations) { if (vertexShaderSource == null || fragShaderSource == null) { throw new IllegalArgumentException("shader source must be non-null"); } if (!isSupported()) { throw new RuntimeException("no shader support found; shaders require OpenGL 2.0"); } program = createProgram(); vert = compileShader(GL20.GL_VERTEX_SHADER, vertexShaderSource); frag = compileShader(GL20.GL_FRAGMENT_SHADER, fragShaderSource); linkProgram(attribLocations); } public ShaderProgram(String vertexShaderSource, String fragShaderSource) { this(vertexShaderSource, fragShaderSource, null); } public int getID() { return program; } public boolean isValid() { return program != 0; } public void use() { if (!isValid()) { throw new IllegalStateException(); } GL20.glUseProgram(program); } public void dispose() { if (isValid()) { disposeShaders(); GL20.glDeleteProgram(program); program = 0; } } private int createProgram() { int program = GL20.glCreateProgram(); if (program == 0) { throw new RuntimeException(); } return program; } private int compileShader(int type, String source) { int shader = GL20.glCreateShader(type); if (shader == 0) { throw new RuntimeException(); } GL20.glShaderSource(shader, source); GL20.glCompileShader(shader); int comp = GL20.glGetShaderi(shader, GL20.GL_COMPILE_STATUS); int len = GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH); if (comp == GL11.GL_FALSE) { throw new RuntimeException(GL20.glGetShaderInfoLog(shader, len)); } return shader; } private void linkProgram(List<VertexAttribute> attribLocations) { if (!isValid()) { throw new RuntimeException(); } if (attribLocations != null) { for (VertexAttribute a : attribLocations) { if (a != null) { GL20.glBindAttribLocation(program, a.location, a.name); } } } attachShaders(); GL20.glLinkProgram(program); int comp = GL20.glGetProgrami(program, GL20.GL_LINK_STATUS); int len = GL20.glGetProgrami(program, GL20.GL_INFO_LOG_LENGTH); if (comp == GL11.GL_FALSE) { throw new RuntimeException(GL20.glGetProgramInfoLog(program, len)); } } private void attachShaders() { GL20.glAttachShader(program, vert); GL20.glAttachShader(program, frag); } private void disposeShaders() { if (vert != 0) { GL20.glDetachShader(program, vert); GL20.glDeleteShader(vert); vert = 0; } if (frag != 0) { GL20.glDetachShader(program, frag); GL20.glDeleteShader(frag); frag = 0; } } // // Uniform setters public void setUniformi(String name, int i) { setUniformi(getUniformLocation(name), i); } private void setUniformi(int loc, int i) { if (loc == -1) { return; } GL20.glUniform1i(loc, i); } public void setUniformMatrix(String name, boolean transpose, Matrix4f m) { setUniformMatrix(getUniformLocation(name), transpose, m); } private void setUniformMatrix(int loc, boolean transpose, Matrix4f m) { if (loc == -1) { return; } FloatBuffer fbuf16 = BufferUtils.createFloatBuffer(16); m.store(fbuf16); fbuf16.flip(); GL20.glUniformMatrix4(loc, transpose, fbuf16); } // // Helpers private int getUniformLocation(String name) { return GL20.glGetUniformLocation(program, name); } }