316 lines
6.8 KiB
C
316 lines
6.8 KiB
C
/**
|
|
* Utilities for OpenGL shading language
|
|
*
|
|
* Brian Paul
|
|
* 9 April 2008
|
|
*/
|
|
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <GL/glew.h>
|
|
#include <GL/glut.h>
|
|
#include "shaderutil.h"
|
|
|
|
/** time to compile previous shader */
|
|
static GLdouble CompileTime = 0.0;
|
|
|
|
/** time to linke previous program */
|
|
static GLdouble LinkTime = 0.0;
|
|
|
|
|
|
GLboolean
|
|
ShadersSupported(void)
|
|
{
|
|
const char *version = (const char *) glGetString(GL_VERSION);
|
|
if (version[0] == '2' && version[1] == '.') {
|
|
return GL_TRUE;
|
|
}
|
|
else if (glutExtensionSupported("GL_ARB_vertex_shader")
|
|
&& glutExtensionSupported("GL_ARB_fragment_shader")
|
|
&& glutExtensionSupported("GL_ARB_shader_objects")) {
|
|
fprintf(stderr, "Warning: Trying ARB GLSL instead of OpenGL 2.x. This may not work.\n");
|
|
return GL_TRUE;
|
|
}
|
|
return GL_TRUE;
|
|
}
|
|
|
|
|
|
GLuint
|
|
CompileShaderText(GLenum shaderType, const char *text)
|
|
{
|
|
GLuint shader;
|
|
GLint stat;
|
|
GLdouble t0, t1;
|
|
|
|
shader = glCreateShader(shaderType);
|
|
glShaderSource(shader, 1, (const GLchar **) &text, NULL);
|
|
|
|
t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
|
|
glCompileShader(shader);
|
|
t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
|
|
|
|
CompileTime = t1 - t0;
|
|
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
|
|
if (!stat) {
|
|
GLchar log[1000];
|
|
GLsizei len;
|
|
glGetShaderInfoLog(shader, 1000, &len, log);
|
|
fprintf(stderr, "Error: problem compiling shader: %s\n", log);
|
|
exit(1);
|
|
}
|
|
else {
|
|
/*printf("Shader compiled OK\n");*/
|
|
}
|
|
return shader;
|
|
}
|
|
|
|
|
|
/**
|
|
* Read a shader from a file.
|
|
*/
|
|
GLuint
|
|
CompileShaderFile(GLenum shaderType, const char *filename)
|
|
{
|
|
const int max = 100*1000;
|
|
int n;
|
|
char *buffer = (char*) malloc(max);
|
|
GLuint shader;
|
|
FILE *f;
|
|
|
|
f = fopen(filename, "r");
|
|
if (!f) {
|
|
fprintf(stderr, "Unable to open shader file %s\n", filename);
|
|
return 0;
|
|
}
|
|
|
|
n = fread(buffer, 1, max, f);
|
|
/*printf("read %d bytes from shader file %s\n", n, filename);*/
|
|
if (n > 0) {
|
|
buffer[n] = 0;
|
|
shader = CompileShaderText(shaderType, buffer);
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
|
|
fclose(f);
|
|
free(buffer);
|
|
|
|
return shader;
|
|
}
|
|
|
|
|
|
GLuint
|
|
LinkShaders(GLuint vertShader, GLuint fragShader)
|
|
{
|
|
GLuint program = glCreateProgram();
|
|
GLdouble t0, t1;
|
|
|
|
assert(vertShader || fragShader);
|
|
|
|
if (fragShader)
|
|
glAttachShader(program, fragShader);
|
|
if (vertShader)
|
|
glAttachShader(program, vertShader);
|
|
|
|
t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
|
|
glLinkProgram(program);
|
|
t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
|
|
|
|
LinkTime = t1 - t0;
|
|
|
|
/* check link */
|
|
{
|
|
GLint stat;
|
|
glGetProgramiv(program, GL_LINK_STATUS, &stat);
|
|
if (!stat) {
|
|
GLchar log[1000];
|
|
GLsizei len;
|
|
glGetProgramInfoLog(program, 1000, &len, log);
|
|
fprintf(stderr, "Shader link error:\n%s\n", log);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return program;
|
|
}
|
|
|
|
|
|
GLboolean
|
|
ValidateShaderProgram(GLuint program)
|
|
{
|
|
GLint stat;
|
|
glValidateProgramARB(program);
|
|
glGetProgramiv(program, GL_VALIDATE_STATUS, &stat);
|
|
|
|
if (!stat) {
|
|
GLchar log[1000];
|
|
GLsizei len;
|
|
glGetProgramInfoLog(program, 1000, &len, log);
|
|
fprintf(stderr, "Program validation error:\n%s\n", log);
|
|
return 0;
|
|
}
|
|
|
|
return (GLboolean) stat;
|
|
}
|
|
|
|
|
|
GLdouble
|
|
GetShaderCompileTime(void)
|
|
{
|
|
return CompileTime;
|
|
}
|
|
|
|
|
|
GLdouble
|
|
GetShaderLinkTime(void)
|
|
{
|
|
return LinkTime;
|
|
}
|
|
|
|
|
|
void
|
|
SetUniformValues(GLuint program, struct uniform_info uniforms[])
|
|
{
|
|
GLuint i;
|
|
|
|
for (i = 0; uniforms[i].name; i++) {
|
|
uniforms[i].location
|
|
= glGetUniformLocation(program, uniforms[i].name);
|
|
|
|
switch (uniforms[i].type) {
|
|
case GL_INT:
|
|
case GL_SAMPLER_1D:
|
|
case GL_SAMPLER_2D:
|
|
case GL_SAMPLER_3D:
|
|
case GL_SAMPLER_CUBE:
|
|
case GL_SAMPLER_2D_RECT_ARB:
|
|
assert(uniforms[i].value[0] >= 0.0F);
|
|
glUniform1i(uniforms[i].location,
|
|
(GLint) uniforms[i].value[0]);
|
|
break;
|
|
case GL_FLOAT:
|
|
glUniform1fv(uniforms[i].location, 1, uniforms[i].value);
|
|
break;
|
|
case GL_FLOAT_VEC2:
|
|
glUniform2fv(uniforms[i].location, 1, uniforms[i].value);
|
|
break;
|
|
case GL_FLOAT_VEC3:
|
|
glUniform3fv(uniforms[i].location, 1, uniforms[i].value);
|
|
break;
|
|
case GL_FLOAT_VEC4:
|
|
glUniform4fv(uniforms[i].location, 1, uniforms[i].value);
|
|
break;
|
|
default:
|
|
if (strncmp(uniforms[i].name, "gl_", 3) == 0) {
|
|
/* built-in uniform: ignore */
|
|
}
|
|
else {
|
|
fprintf(stderr,
|
|
"Unexpected uniform data type in SetUniformValues\n");
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/** Get list of uniforms used in the program */
|
|
GLuint
|
|
GetUniforms(GLuint program, struct uniform_info uniforms[])
|
|
{
|
|
GLint n, max, i;
|
|
|
|
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n);
|
|
glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
GLint size, len;
|
|
GLenum type;
|
|
char name[100];
|
|
|
|
glGetActiveUniform(program, i, 100, &len, &size, &type, name);
|
|
|
|
uniforms[i].name = strdup(name);
|
|
uniforms[i].size = size;
|
|
uniforms[i].type = type;
|
|
uniforms[i].location = glGetUniformLocation(program, name);
|
|
}
|
|
|
|
uniforms[i].name = NULL; /* end of list */
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
void
|
|
PrintUniforms(const struct uniform_info uniforms[])
|
|
{
|
|
GLint i;
|
|
|
|
printf("Uniforms:\n");
|
|
|
|
for (i = 0; uniforms[i].name; i++) {
|
|
printf(" %d: %s size=%d type=0x%x loc=%d value=%g, %g, %g, %g\n",
|
|
i,
|
|
uniforms[i].name,
|
|
uniforms[i].size,
|
|
uniforms[i].type,
|
|
uniforms[i].location,
|
|
uniforms[i].value[0],
|
|
uniforms[i].value[1],
|
|
uniforms[i].value[2],
|
|
uniforms[i].value[3]);
|
|
}
|
|
}
|
|
|
|
|
|
/** Get list of attribs used in the program */
|
|
GLuint
|
|
GetAttribs(GLuint program, struct attrib_info attribs[])
|
|
{
|
|
GLint n, max, i;
|
|
|
|
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n);
|
|
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
GLint size, len;
|
|
GLenum type;
|
|
char name[100];
|
|
|
|
glGetActiveAttrib(program, i, 100, &len, &size, &type, name);
|
|
|
|
attribs[i].name = strdup(name);
|
|
attribs[i].size = size;
|
|
attribs[i].type = type;
|
|
attribs[i].location = glGetAttribLocation(program, name);
|
|
}
|
|
|
|
attribs[i].name = NULL; /* end of list */
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
void
|
|
PrintAttribs(const struct attrib_info attribs[])
|
|
{
|
|
GLint i;
|
|
|
|
printf("Attribs:\n");
|
|
|
|
for (i = 0; attribs[i].name; i++) {
|
|
printf(" %d: %s size=%d type=0x%x loc=%d\n",
|
|
i,
|
|
attribs[i].name,
|
|
attribs[i].size,
|
|
attribs[i].type,
|
|
attribs[i].location);
|
|
}
|
|
}
|