1*6eba5912SPhilippe Houdoin /**
2*6eba5912SPhilippe Houdoin * Utilities for OpenGL shading language
3*6eba5912SPhilippe Houdoin *
4*6eba5912SPhilippe Houdoin * Brian Paul
5*6eba5912SPhilippe Houdoin * 9 April 2008
6*6eba5912SPhilippe Houdoin */
7*6eba5912SPhilippe Houdoin
8*6eba5912SPhilippe Houdoin
9*6eba5912SPhilippe Houdoin #include <assert.h>
10*6eba5912SPhilippe Houdoin #include <stdio.h>
11*6eba5912SPhilippe Houdoin #include <stdlib.h>
12*6eba5912SPhilippe Houdoin #include <string.h>
13*6eba5912SPhilippe Houdoin // #include <GL/glew.h>
14*6eba5912SPhilippe Houdoin #include <GL/glut.h>
15*6eba5912SPhilippe Houdoin #include "shaderutil.h"
16*6eba5912SPhilippe Houdoin
17*6eba5912SPhilippe Houdoin /** time to compile previous shader */
18*6eba5912SPhilippe Houdoin static GLdouble CompileTime = 0.0;
19*6eba5912SPhilippe Houdoin
20*6eba5912SPhilippe Houdoin /** time to linke previous program */
21*6eba5912SPhilippe Houdoin static GLdouble LinkTime = 0.0;
22*6eba5912SPhilippe Houdoin
23*6eba5912SPhilippe Houdoin
24*6eba5912SPhilippe Houdoin GLboolean
ShadersSupported(void)25*6eba5912SPhilippe Houdoin ShadersSupported(void)
26*6eba5912SPhilippe Houdoin {
27*6eba5912SPhilippe Houdoin const char *version = (const char *) glGetString(GL_VERSION);
28*6eba5912SPhilippe Houdoin
29*6eba5912SPhilippe Houdoin /* NVIDIA binary drivers will return "3.0.0", and they clearly support
30*6eba5912SPhilippe Houdoin * shaders.
31*6eba5912SPhilippe Houdoin */
32*6eba5912SPhilippe Houdoin if (version[0] >= '2' && version[1] == '.') {
33*6eba5912SPhilippe Houdoin return GL_TRUE;
34*6eba5912SPhilippe Houdoin }
35*6eba5912SPhilippe Houdoin else if (glutExtensionSupported("GL_ARB_vertex_shader")
36*6eba5912SPhilippe Houdoin && glutExtensionSupported("GL_ARB_fragment_shader")
37*6eba5912SPhilippe Houdoin && glutExtensionSupported("GL_ARB_shader_objects")) {
38*6eba5912SPhilippe Houdoin fprintf(stderr, "Warning: Trying ARB GLSL instead of OpenGL 2.x. This may not work.\n");
39*6eba5912SPhilippe Houdoin return GL_TRUE;
40*6eba5912SPhilippe Houdoin }
41*6eba5912SPhilippe Houdoin fprintf(stderr, "Sorry, GLSL not supported with this OpenGL.\n");
42*6eba5912SPhilippe Houdoin return GL_FALSE;
43*6eba5912SPhilippe Houdoin }
44*6eba5912SPhilippe Houdoin
45*6eba5912SPhilippe Houdoin
46*6eba5912SPhilippe Houdoin GLuint
CompileShaderText(GLenum shaderType,const char * text)47*6eba5912SPhilippe Houdoin CompileShaderText(GLenum shaderType, const char *text)
48*6eba5912SPhilippe Houdoin {
49*6eba5912SPhilippe Houdoin GLuint shader;
50*6eba5912SPhilippe Houdoin GLint stat;
51*6eba5912SPhilippe Houdoin GLdouble t0, t1;
52*6eba5912SPhilippe Houdoin
53*6eba5912SPhilippe Houdoin shader = glCreateShader(shaderType);
54*6eba5912SPhilippe Houdoin glShaderSource(shader, 1, (const GLchar **) &text, NULL);
55*6eba5912SPhilippe Houdoin
56*6eba5912SPhilippe Houdoin t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
57*6eba5912SPhilippe Houdoin glCompileShader(shader);
58*6eba5912SPhilippe Houdoin t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
59*6eba5912SPhilippe Houdoin
60*6eba5912SPhilippe Houdoin CompileTime = t1 - t0;
61*6eba5912SPhilippe Houdoin
62*6eba5912SPhilippe Houdoin glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
63*6eba5912SPhilippe Houdoin if (!stat) {
64*6eba5912SPhilippe Houdoin GLchar log[1000];
65*6eba5912SPhilippe Houdoin GLsizei len;
66*6eba5912SPhilippe Houdoin glGetShaderInfoLog(shader, 1000, &len, log);
67*6eba5912SPhilippe Houdoin fprintf(stderr, "Error: problem compiling shader: %s\n", log);
68*6eba5912SPhilippe Houdoin exit(1);
69*6eba5912SPhilippe Houdoin }
70*6eba5912SPhilippe Houdoin else {
71*6eba5912SPhilippe Houdoin /*printf("Shader compiled OK\n");*/
72*6eba5912SPhilippe Houdoin }
73*6eba5912SPhilippe Houdoin return shader;
74*6eba5912SPhilippe Houdoin }
75*6eba5912SPhilippe Houdoin
76*6eba5912SPhilippe Houdoin
77*6eba5912SPhilippe Houdoin /**
78*6eba5912SPhilippe Houdoin * Read a shader from a file.
79*6eba5912SPhilippe Houdoin */
80*6eba5912SPhilippe Houdoin GLuint
CompileShaderFile(GLenum shaderType,const char * filename)81*6eba5912SPhilippe Houdoin CompileShaderFile(GLenum shaderType, const char *filename)
82*6eba5912SPhilippe Houdoin {
83*6eba5912SPhilippe Houdoin const int max = 100*1000;
84*6eba5912SPhilippe Houdoin int n;
85*6eba5912SPhilippe Houdoin char *buffer = (char*) malloc(max);
86*6eba5912SPhilippe Houdoin GLuint shader;
87*6eba5912SPhilippe Houdoin FILE *f;
88*6eba5912SPhilippe Houdoin
89*6eba5912SPhilippe Houdoin f = fopen(filename, "r");
90*6eba5912SPhilippe Houdoin if (!f) {
91*6eba5912SPhilippe Houdoin fprintf(stderr, "Unable to open shader file %s\n", filename);
92*6eba5912SPhilippe Houdoin free(buffer);
93*6eba5912SPhilippe Houdoin return 0;
94*6eba5912SPhilippe Houdoin }
95*6eba5912SPhilippe Houdoin
96*6eba5912SPhilippe Houdoin n = fread(buffer, 1, max, f);
97*6eba5912SPhilippe Houdoin /*printf("read %d bytes from shader file %s\n", n, filename);*/
98*6eba5912SPhilippe Houdoin if (n > 0) {
99*6eba5912SPhilippe Houdoin buffer[n] = 0;
100*6eba5912SPhilippe Houdoin shader = CompileShaderText(shaderType, buffer);
101*6eba5912SPhilippe Houdoin }
102*6eba5912SPhilippe Houdoin else {
103*6eba5912SPhilippe Houdoin fclose(f);
104*6eba5912SPhilippe Houdoin free(buffer);
105*6eba5912SPhilippe Houdoin return 0;
106*6eba5912SPhilippe Houdoin }
107*6eba5912SPhilippe Houdoin
108*6eba5912SPhilippe Houdoin fclose(f);
109*6eba5912SPhilippe Houdoin free(buffer);
110*6eba5912SPhilippe Houdoin
111*6eba5912SPhilippe Houdoin return shader;
112*6eba5912SPhilippe Houdoin }
113*6eba5912SPhilippe Houdoin
114*6eba5912SPhilippe Houdoin
115*6eba5912SPhilippe Houdoin GLuint
LinkShaders(GLuint vertShader,GLuint fragShader)116*6eba5912SPhilippe Houdoin LinkShaders(GLuint vertShader, GLuint fragShader)
117*6eba5912SPhilippe Houdoin {
118*6eba5912SPhilippe Houdoin GLuint program = glCreateProgram();
119*6eba5912SPhilippe Houdoin GLdouble t0, t1;
120*6eba5912SPhilippe Houdoin
121*6eba5912SPhilippe Houdoin assert(vertShader || fragShader);
122*6eba5912SPhilippe Houdoin
123*6eba5912SPhilippe Houdoin if (fragShader)
124*6eba5912SPhilippe Houdoin glAttachShader(program, fragShader);
125*6eba5912SPhilippe Houdoin if (vertShader)
126*6eba5912SPhilippe Houdoin glAttachShader(program, vertShader);
127*6eba5912SPhilippe Houdoin
128*6eba5912SPhilippe Houdoin t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
129*6eba5912SPhilippe Houdoin glLinkProgram(program);
130*6eba5912SPhilippe Houdoin t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
131*6eba5912SPhilippe Houdoin
132*6eba5912SPhilippe Houdoin LinkTime = t1 - t0;
133*6eba5912SPhilippe Houdoin
134*6eba5912SPhilippe Houdoin /* check link */
135*6eba5912SPhilippe Houdoin {
136*6eba5912SPhilippe Houdoin GLint stat;
137*6eba5912SPhilippe Houdoin glGetProgramiv(program, GL_LINK_STATUS, &stat);
138*6eba5912SPhilippe Houdoin if (!stat) {
139*6eba5912SPhilippe Houdoin GLchar log[1000];
140*6eba5912SPhilippe Houdoin GLsizei len;
141*6eba5912SPhilippe Houdoin glGetProgramInfoLog(program, 1000, &len, log);
142*6eba5912SPhilippe Houdoin fprintf(stderr, "Shader link error:\n%s\n", log);
143*6eba5912SPhilippe Houdoin return 0;
144*6eba5912SPhilippe Houdoin }
145*6eba5912SPhilippe Houdoin }
146*6eba5912SPhilippe Houdoin
147*6eba5912SPhilippe Houdoin return program;
148*6eba5912SPhilippe Houdoin }
149*6eba5912SPhilippe Houdoin
150*6eba5912SPhilippe Houdoin
151*6eba5912SPhilippe Houdoin GLboolean
ValidateShaderProgram(GLuint program)152*6eba5912SPhilippe Houdoin ValidateShaderProgram(GLuint program)
153*6eba5912SPhilippe Houdoin {
154*6eba5912SPhilippe Houdoin GLint stat;
155*6eba5912SPhilippe Houdoin glValidateProgramARB(program);
156*6eba5912SPhilippe Houdoin glGetProgramiv(program, GL_VALIDATE_STATUS, &stat);
157*6eba5912SPhilippe Houdoin
158*6eba5912SPhilippe Houdoin if (!stat) {
159*6eba5912SPhilippe Houdoin GLchar log[1000];
160*6eba5912SPhilippe Houdoin GLsizei len;
161*6eba5912SPhilippe Houdoin glGetProgramInfoLog(program, 1000, &len, log);
162*6eba5912SPhilippe Houdoin fprintf(stderr, "Program validation error:\n%s\n", log);
163*6eba5912SPhilippe Houdoin return 0;
164*6eba5912SPhilippe Houdoin }
165*6eba5912SPhilippe Houdoin
166*6eba5912SPhilippe Houdoin return (GLboolean) stat;
167*6eba5912SPhilippe Houdoin }
168*6eba5912SPhilippe Houdoin
169*6eba5912SPhilippe Houdoin
170*6eba5912SPhilippe Houdoin GLdouble
GetShaderCompileTime(void)171*6eba5912SPhilippe Houdoin GetShaderCompileTime(void)
172*6eba5912SPhilippe Houdoin {
173*6eba5912SPhilippe Houdoin return CompileTime;
174*6eba5912SPhilippe Houdoin }
175*6eba5912SPhilippe Houdoin
176*6eba5912SPhilippe Houdoin
177*6eba5912SPhilippe Houdoin GLdouble
GetShaderLinkTime(void)178*6eba5912SPhilippe Houdoin GetShaderLinkTime(void)
179*6eba5912SPhilippe Houdoin {
180*6eba5912SPhilippe Houdoin return LinkTime;
181*6eba5912SPhilippe Houdoin }
182*6eba5912SPhilippe Houdoin
183*6eba5912SPhilippe Houdoin
184*6eba5912SPhilippe Houdoin void
SetUniformValues(GLuint program,struct uniform_info uniforms[])185*6eba5912SPhilippe Houdoin SetUniformValues(GLuint program, struct uniform_info uniforms[])
186*6eba5912SPhilippe Houdoin {
187*6eba5912SPhilippe Houdoin GLuint i;
188*6eba5912SPhilippe Houdoin
189*6eba5912SPhilippe Houdoin for (i = 0; uniforms[i].name; i++) {
190*6eba5912SPhilippe Houdoin uniforms[i].location
191*6eba5912SPhilippe Houdoin = glGetUniformLocation(program, uniforms[i].name);
192*6eba5912SPhilippe Houdoin
193*6eba5912SPhilippe Houdoin switch (uniforms[i].type) {
194*6eba5912SPhilippe Houdoin case GL_INT:
195*6eba5912SPhilippe Houdoin case GL_SAMPLER_1D:
196*6eba5912SPhilippe Houdoin case GL_SAMPLER_2D:
197*6eba5912SPhilippe Houdoin case GL_SAMPLER_3D:
198*6eba5912SPhilippe Houdoin case GL_SAMPLER_CUBE:
199*6eba5912SPhilippe Houdoin case GL_SAMPLER_2D_RECT_ARB:
200*6eba5912SPhilippe Houdoin assert(uniforms[i].value[0] >= 0.0F);
201*6eba5912SPhilippe Houdoin glUniform1i(uniforms[i].location,
202*6eba5912SPhilippe Houdoin (GLint) uniforms[i].value[0]);
203*6eba5912SPhilippe Houdoin break;
204*6eba5912SPhilippe Houdoin case GL_FLOAT:
205*6eba5912SPhilippe Houdoin glUniform1fv(uniforms[i].location, 1, uniforms[i].value);
206*6eba5912SPhilippe Houdoin break;
207*6eba5912SPhilippe Houdoin case GL_FLOAT_VEC2:
208*6eba5912SPhilippe Houdoin glUniform2fv(uniforms[i].location, 1, uniforms[i].value);
209*6eba5912SPhilippe Houdoin break;
210*6eba5912SPhilippe Houdoin case GL_FLOAT_VEC3:
211*6eba5912SPhilippe Houdoin glUniform3fv(uniforms[i].location, 1, uniforms[i].value);
212*6eba5912SPhilippe Houdoin break;
213*6eba5912SPhilippe Houdoin case GL_FLOAT_VEC4:
214*6eba5912SPhilippe Houdoin glUniform4fv(uniforms[i].location, 1, uniforms[i].value);
215*6eba5912SPhilippe Houdoin break;
216*6eba5912SPhilippe Houdoin default:
217*6eba5912SPhilippe Houdoin if (strncmp(uniforms[i].name, "gl_", 3) == 0) {
218*6eba5912SPhilippe Houdoin /* built-in uniform: ignore */
219*6eba5912SPhilippe Houdoin }
220*6eba5912SPhilippe Houdoin else {
221*6eba5912SPhilippe Houdoin fprintf(stderr,
222*6eba5912SPhilippe Houdoin "Unexpected uniform data type in SetUniformValues\n");
223*6eba5912SPhilippe Houdoin abort();
224*6eba5912SPhilippe Houdoin }
225*6eba5912SPhilippe Houdoin }
226*6eba5912SPhilippe Houdoin }
227*6eba5912SPhilippe Houdoin }
228*6eba5912SPhilippe Houdoin
229*6eba5912SPhilippe Houdoin
230*6eba5912SPhilippe Houdoin /** Get list of uniforms used in the program */
231*6eba5912SPhilippe Houdoin GLuint
GetUniforms(GLuint program,struct uniform_info uniforms[])232*6eba5912SPhilippe Houdoin GetUniforms(GLuint program, struct uniform_info uniforms[])
233*6eba5912SPhilippe Houdoin {
234*6eba5912SPhilippe Houdoin GLint n, max, i;
235*6eba5912SPhilippe Houdoin
236*6eba5912SPhilippe Houdoin glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n);
237*6eba5912SPhilippe Houdoin glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max);
238*6eba5912SPhilippe Houdoin
239*6eba5912SPhilippe Houdoin for (i = 0; i < n; i++) {
240*6eba5912SPhilippe Houdoin GLint size, len;
241*6eba5912SPhilippe Houdoin GLenum type;
242*6eba5912SPhilippe Houdoin char name[100];
243*6eba5912SPhilippe Houdoin
244*6eba5912SPhilippe Houdoin glGetActiveUniform(program, i, 100, &len, &size, &type, name);
245*6eba5912SPhilippe Houdoin
246*6eba5912SPhilippe Houdoin uniforms[i].name = strdup(name);
247*6eba5912SPhilippe Houdoin uniforms[i].size = size;
248*6eba5912SPhilippe Houdoin uniforms[i].type = type;
249*6eba5912SPhilippe Houdoin uniforms[i].location = glGetUniformLocation(program, name);
250*6eba5912SPhilippe Houdoin }
251*6eba5912SPhilippe Houdoin
252*6eba5912SPhilippe Houdoin uniforms[i].name = NULL; /* end of list */
253*6eba5912SPhilippe Houdoin
254*6eba5912SPhilippe Houdoin return n;
255*6eba5912SPhilippe Houdoin }
256*6eba5912SPhilippe Houdoin
257*6eba5912SPhilippe Houdoin
258*6eba5912SPhilippe Houdoin void
PrintUniforms(const struct uniform_info uniforms[])259*6eba5912SPhilippe Houdoin PrintUniforms(const struct uniform_info uniforms[])
260*6eba5912SPhilippe Houdoin {
261*6eba5912SPhilippe Houdoin GLint i;
262*6eba5912SPhilippe Houdoin
263*6eba5912SPhilippe Houdoin printf("Uniforms:\n");
264*6eba5912SPhilippe Houdoin
265*6eba5912SPhilippe Houdoin for (i = 0; uniforms[i].name; i++) {
266*6eba5912SPhilippe Houdoin printf(" %d: %s size=%d type=0x%x loc=%d value=%g, %g, %g, %g\n",
267*6eba5912SPhilippe Houdoin i,
268*6eba5912SPhilippe Houdoin uniforms[i].name,
269*6eba5912SPhilippe Houdoin uniforms[i].size,
270*6eba5912SPhilippe Houdoin uniforms[i].type,
271*6eba5912SPhilippe Houdoin uniforms[i].location,
272*6eba5912SPhilippe Houdoin uniforms[i].value[0],
273*6eba5912SPhilippe Houdoin uniforms[i].value[1],
274*6eba5912SPhilippe Houdoin uniforms[i].value[2],
275*6eba5912SPhilippe Houdoin uniforms[i].value[3]);
276*6eba5912SPhilippe Houdoin }
277*6eba5912SPhilippe Houdoin }
278*6eba5912SPhilippe Houdoin
279*6eba5912SPhilippe Houdoin
280*6eba5912SPhilippe Houdoin /** Get list of attribs used in the program */
281*6eba5912SPhilippe Houdoin GLuint
GetAttribs(GLuint program,struct attrib_info attribs[])282*6eba5912SPhilippe Houdoin GetAttribs(GLuint program, struct attrib_info attribs[])
283*6eba5912SPhilippe Houdoin {
284*6eba5912SPhilippe Houdoin GLint n, max, i;
285*6eba5912SPhilippe Houdoin
286*6eba5912SPhilippe Houdoin glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n);
287*6eba5912SPhilippe Houdoin glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max);
288*6eba5912SPhilippe Houdoin
289*6eba5912SPhilippe Houdoin for (i = 0; i < n; i++) {
290*6eba5912SPhilippe Houdoin GLint size, len;
291*6eba5912SPhilippe Houdoin GLenum type;
292*6eba5912SPhilippe Houdoin char name[100];
293*6eba5912SPhilippe Houdoin
294*6eba5912SPhilippe Houdoin glGetActiveAttrib(program, i, 100, &len, &size, &type, name);
295*6eba5912SPhilippe Houdoin
296*6eba5912SPhilippe Houdoin attribs[i].name = strdup(name);
297*6eba5912SPhilippe Houdoin attribs[i].size = size;
298*6eba5912SPhilippe Houdoin attribs[i].type = type;
299*6eba5912SPhilippe Houdoin attribs[i].location = glGetAttribLocation(program, name);
300*6eba5912SPhilippe Houdoin }
301*6eba5912SPhilippe Houdoin
302*6eba5912SPhilippe Houdoin attribs[i].name = NULL; /* end of list */
303*6eba5912SPhilippe Houdoin
304*6eba5912SPhilippe Houdoin return n;
305*6eba5912SPhilippe Houdoin }
306*6eba5912SPhilippe Houdoin
307*6eba5912SPhilippe Houdoin
308*6eba5912SPhilippe Houdoin void
PrintAttribs(const struct attrib_info attribs[])309*6eba5912SPhilippe Houdoin PrintAttribs(const struct attrib_info attribs[])
310*6eba5912SPhilippe Houdoin {
311*6eba5912SPhilippe Houdoin GLint i;
312*6eba5912SPhilippe Houdoin
313*6eba5912SPhilippe Houdoin printf("Attribs:\n");
314*6eba5912SPhilippe Houdoin
315*6eba5912SPhilippe Houdoin for (i = 0; attribs[i].name; i++) {
316*6eba5912SPhilippe Houdoin printf(" %d: %s size=%d type=0x%x loc=%d\n",
317*6eba5912SPhilippe Houdoin i,
318*6eba5912SPhilippe Houdoin attribs[i].name,
319*6eba5912SPhilippe Houdoin attribs[i].size,
320*6eba5912SPhilippe Houdoin attribs[i].type,
321*6eba5912SPhilippe Houdoin attribs[i].location);
322*6eba5912SPhilippe Houdoin }
323*6eba5912SPhilippe Houdoin }
324