/* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of NVIDIA CORPORATION nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #define HELPERGL_EXTERN_GL_FUNC_IMPLEMENTATION #include #include "GLSLProgram.h" GLSLProgram::GLSLProgram(const char *vsource, const char *fsource) { mProg = compileProgram(vsource, 0, fsource); } GLSLProgram::GLSLProgram(const char *vsource, const char *gsource, const char *fsource, GLenum gsInput, GLenum gsOutput) { mProg = compileProgram(vsource, gsource, fsource, gsInput, gsOutput); } GLSLProgram::~GLSLProgram() { if (mProg) { glDeleteProgram(mProg); } } void GLSLProgram::enable() { glUseProgram(mProg); } void GLSLProgram::disable() { glUseProgram(0); } void GLSLProgram::setUniform1f(const char *name, float value) { GLint loc = glGetUniformLocation(mProg, name); if (loc >= 0) { glUniform1f(loc, value); } else { #if _DEBUG fprintf(stderr, "Error setting parameter '%s'\n", name); #endif } } void GLSLProgram::setUniform2f(const char *name, float x, float y) { GLint loc = glGetUniformLocation(mProg, name); if (loc >= 0) { glUniform2f(loc, x, y); } else { #if _DEBUG fprintf(stderr, "Error setting parameter '%s'\n", name); #endif } } void GLSLProgram::setUniform3f(const char *name, float x, float y, float z) { GLint loc = glGetUniformLocation(mProg, name); if (loc >= 0) { glUniform3f(loc, x, y, z); } else { #if _DEBUG fprintf(stderr, "Error setting parameter '%s'\n", name); #endif } } void GLSLProgram::setUniform4f(const char *name, float x, float y, float z, float w) { GLint loc = glGetUniformLocation(mProg, name); if (loc >= 0) { glUniform4f(loc, x, y, z, w); } else { #if _DEBUG fprintf(stderr, "Error setting parameter '%s'\n", name); #endif } } void GLSLProgram::setUniformMatrix4fv(const GLchar *name, GLfloat *m, bool transpose) { GLint loc = glGetUniformLocation(mProg, name); if (loc >= 0) { glUniformMatrix4fv(loc, 1, transpose, m); } else { #if _DEBUG fprintf(stderr, "Error setting parameter '%s'\n", name); #endif } } void GLSLProgram::setUniformfv(const GLchar *name, GLfloat *v, int elementSize, int count) { GLint loc = glGetUniformLocation(mProg, name); if (loc == -1) { #ifdef _DEBUG fprintf(stderr, "Error setting parameter '%s'\n", name); #endif return; } switch (elementSize) { case 1: glUniform1fv(loc, count, v); break; case 2: glUniform2fv(loc, count, v); break; case 3: glUniform3fv(loc, count, v); break; case 4: glUniform4fv(loc, count, v); break; } } void GLSLProgram::bindTexture(const char *name, GLuint tex, GLenum target, GLint unit) { GLint loc = glGetUniformLocation(mProg, name); if (loc >= 0) { glActiveTexture(GL_TEXTURE0 + unit); glBindTexture(target, tex); glUseProgram(mProg); glUniform1i(loc, unit); glActiveTexture(GL_TEXTURE0); } else { #if _DEBUG fprintf(stderr, "Error binding texture '%s'\n", name); #endif } } GLuint GLSLProgram::checkCompileStatus(GLuint shader, GLint *status) { glGetShaderiv(shader, GL_COMPILE_STATUS, status); if (!(*status)) { char log[2048]; int len; glGetShaderInfoLog(shader, 2048, (GLsizei *)&len, log); printf("Error: shader(%04d), Info log: %s\n", (int)shader, log); glDeleteShader(shader); return 0; } return 1; } GLuint GLSLProgram::compileProgram(const char *vsource, const char *gsource, const char *fsource, GLenum gsInput, GLenum gsOutput) { GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); GLint compiled = 0; glShaderSource(vertexShader, 1, &vsource, 0); glShaderSource(fragmentShader, 1, &fsource, 0); glCompileShader(vertexShader); if (checkCompileStatus(vertexShader, &compiled) == 0) { printf(":\n"); printf("%s\n", vsource); return 0; } glCompileShader(fragmentShader); if (checkCompileStatus(fragmentShader, &compiled) == 0) { printf(":\n"); printf("%s\n", fsource); return 0; } GLuint program = glCreateProgram(); glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); if (gsource) { GLuint geomShader = glCreateShader(GL_GEOMETRY_SHADER_EXT); glShaderSource(geomShader, 1, &gsource, 0); glCompileShader(geomShader); glGetShaderiv(geomShader, GL_COMPILE_STATUS, (GLint *)&compiled); if (checkCompileStatus(geomShader, &compiled) == 0) { printf(":\n"); printf("%s\n", gsource); return 0; } glAttachShader(program, geomShader); glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, gsInput); glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, gsOutput); glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, 4); } glLinkProgram(program); // check if program linked GLint success = 0; glGetProgramiv(program, GL_LINK_STATUS, &success); if (!success) { char temp[1024]; glGetProgramInfoLog(program, 1024, 0, temp); fprintf(stderr, "Failed to link program:\n%s\n", temp); glDeleteProgram(program); program = 0; exit(EXIT_FAILURE); } return program; }