2 * Simple shader test harness.
7 * shtest --vs vertShaderFile --fs fragShaderFile
9 * In this case the given vertex/frag shaders are read and compiled.
10 * Random values are assigned to the uniforms.
15 * In this case a config file is read that specifies the file names
16 * of the shaders plus initial values for uniforms.
18 * Example config file:
23 * uniform v1 1.0 0.5 0.2 0.3
37 #include "shaderutil.h"
49 static char *FragShaderFile
= NULL
;
50 static char *VertShaderFile
= NULL
;
51 static char *ConfigFile
= NULL
;
53 /* program/shader objects */
54 static GLuint fragShader
;
55 static GLuint vertShader
;
56 static GLuint Program
;
59 #define MAX_UNIFORMS 100
60 static struct uniform_info Uniforms
[MAX_UNIFORMS
];
61 static GLuint NumUniforms
= 0;
64 #define MAX_ATTRIBS 100
65 static struct attrib_info Attribs
[MAX_ATTRIBS
];
66 static GLuint NumAttribs
= 0;
86 static GLboolean Anim
= GL_FALSE
;
87 static GLfloat TexRot
= 0.0;
88 static GLfloat xRot
= 0.0f
, yRot
= 0.0f
, zRot
= 0.0f
;
89 static shape Object
= SPHERE
;
93 RandomFloat(float min
, float max
)
95 int k
= rand() % 10000;
96 float x
= min
+ (max
- min
) * k
/ 10000.0;
101 /** Set new random values for uniforms */
103 RandomUniformValues(void)
106 for (i
= 0; i
< NumUniforms
; i
++) {
107 if (Uniforms
[i
].type
== GL_FLOAT
) {
108 Uniforms
[i
].value
[0] = RandomFloat(0.0, 1.0);
111 Uniforms
[i
].value
[0] = RandomFloat(-1.0, 2.0);
112 Uniforms
[i
].value
[1] = RandomFloat(-1.0, 2.0);
113 Uniforms
[i
].value
[2] = RandomFloat(-1.0, 2.0);
114 Uniforms
[i
].value
[3] = RandomFloat(-1.0, 2.0);
132 SquareVertex(GLfloat s
, GLfloat t
, GLfloat size
)
134 GLfloat x
= -size
+ s
* 2.0 * size
;
135 GLfloat y
= -size
+ t
* 2.0 * size
;
138 glMultiTexCoord2f(GL_TEXTURE0
, s
, t
);
139 glMultiTexCoord2f(GL_TEXTURE1
, s
, t
);
140 glMultiTexCoord2f(GL_TEXTURE2
, s
, t
);
141 glMultiTexCoord2f(GL_TEXTURE3
, s
, t
);
143 /* assign (s,t) to the generic attributes */
144 for (i
= 0; i
< NumAttribs
; i
++) {
145 if (Attribs
[i
].location
>= 0) {
146 glVertexAttrib2f(Attribs
[i
].location
, s
, t
);
155 * Draw a square, specifying normal and tangent vectors.
160 GLint tangentAttrib
= 1;
162 glVertexAttrib3f(tangentAttrib
, 1, 0, 0);
165 SquareVertex(0, 0, size
);
166 SquareVertex(1, 0, size
);
167 SquareVertex(1, 1, size
);
168 SquareVertex(0, 1, size
);
170 glTexCoord2f(0, 0); glVertex2f(-size
, -size
);
171 glTexCoord2f(1, 0); glVertex2f( size
, -size
);
172 glTexCoord2f(1, 1); glVertex2f( size
, size
);
173 glTexCoord2f(0, 1); glVertex2f(-size
, size
);
184 glRotatef(90, 0, 1, 0);
185 glTranslatef(0, 0, size
);
191 glRotatef(-90, 0, 1, 0);
192 glTranslatef(0, 0, size
);
198 glRotatef(90, 1, 0, 0);
199 glTranslatef(0, 0, size
);
205 glRotatef(-90, 1, 0, 0);
206 glTranslatef(0, 0, size
);
213 glTranslatef(0, 0, size
);
219 glRotatef(180, 0, 1, 0);
220 glTranslatef(0, 0, size
);
227 Sphere(GLfloat radius
, GLint slices
, GLint stacks
)
229 static GLUquadricObj
*q
= NULL
;
233 gluQuadricDrawStyle(q
, GLU_FILL
);
234 gluQuadricNormals(q
, GLU_SMOOTH
);
235 gluQuadricTexture(q
, GL_TRUE
);
238 gluSphere(q
, radius
, slices
, stacks
);
245 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
248 glRotatef(xRot
, 1.0f
, 0.0f
, 0.0f
);
249 glRotatef(yRot
, 0.0f
, 1.0f
, 0.0f
);
250 glRotatef(zRot
, 0.0f
, 0.0f
, 1.0f
);
252 glMatrixMode(GL_TEXTURE
);
254 glRotatef(TexRot
, 0.0f
, 1.0f
, 0.0f
);
255 glMatrixMode(GL_MODELVIEW
);
257 if (Object
== SPHERE
) {
260 else if (Object
== CUBE
) {
271 Reshape(int width
, int height
)
273 glViewport(0, 0, width
, height
);
274 glMatrixMode(GL_PROJECTION
);
276 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
277 glMatrixMode(GL_MODELVIEW
);
279 glTranslatef(0.0f
, 0.0f
, -15.0f
);
286 glDeleteShader(fragShader
);
287 glDeleteShader(vertShader
);
288 glDeleteProgram(Program
);
289 glutDestroyWindow(win
);
294 Key(unsigned char key
, int x
, int y
)
296 const GLfloat step
= 2.0;
315 Object
= (Object
+ 1) % NUM_SHAPES
;
318 RandomUniformValues();
319 SetUniformValues(Program
, Uniforms
);
320 PrintUniforms(Uniforms
);
332 SpecialKey(int key
, int x
, int y
)
334 const GLfloat step
= 2.0;
358 InitUniforms(const struct config_file
*conf
,
359 struct uniform_info uniforms
[])
363 for (i
= 0; i
< conf
->num_uniforms
; i
++) {
365 for (j
= 0; uniforms
[j
].name
; j
++) {
366 if (strcmp(uniforms
[j
].name
, conf
->uniforms
[i
].name
) == 0) {
367 uniforms
[j
].type
= conf
->uniforms
[i
].type
;
368 uniforms
[j
].value
[0] = conf
->uniforms
[i
].value
[0];
369 uniforms
[j
].value
[1] = conf
->uniforms
[i
].value
[1];
370 uniforms
[j
].value
[2] = conf
->uniforms
[i
].value
[2];
371 uniforms
[j
].value
[3] = conf
->uniforms
[i
].value
[3];
379 LoadTexture(GLint unit
, const char *texFileName
)
381 GLint imgWidth
, imgHeight
;
383 GLubyte
*image
= NULL
;
385 GLenum filter
= GL_LINEAR
;
387 image
= LoadRGBImage(texFileName
, &imgWidth
, &imgHeight
, &imgFormat
);
389 printf("Couldn't read %s\n", texFileName
);
393 printf("Load Texture: unit %d: %s %d x %d\n",
394 unit
, texFileName
, imgWidth
, imgHeight
);
396 glActiveTexture(GL_TEXTURE0
+ unit
);
397 glGenTextures(1, &tex
);
398 glBindTexture(GL_TEXTURE_2D
, tex
);
400 gluBuild2DMipmaps(GL_TEXTURE_2D
, 4, imgWidth
, imgHeight
,
401 imgFormat
, GL_UNSIGNED_BYTE
, image
);
404 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
405 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
406 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, filter
);
407 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, filter
);
412 TypeFromName(const char *n
)
414 static const struct {
418 { "GL_FLOAT", GL_FLOAT
},
419 { "GL_FLOAT_VEC2", GL_FLOAT_VEC2
},
420 { "GL_FLOAT_VEC3", GL_FLOAT_VEC3
},
421 { "GL_FLOAT_VEC4", GL_FLOAT_VEC4
},
422 { "GL_INT", GL_INT
},
423 { "GL_INT_VEC2", GL_INT_VEC2
},
424 { "GL_INT_VEC3", GL_INT_VEC3
},
425 { "GL_INT_VEC4", GL_INT_VEC4
},
426 { "GL_SAMPLER_2D", GL_SAMPLER_2D
},
431 for (i
= 0; types
[i
].name
; i
++) {
432 if (strcmp(types
[i
].name
, n
) == 0)
433 return types
[i
].type
;
442 * Read a config file.
445 ReadConfigFile(const char *filename
, struct config_file
*conf
)
450 f
= fopen(filename
, "r");
452 fprintf(stderr
, "Unable to open config file %s\n", filename
);
456 conf
->num_uniforms
= 0;
458 /* ugly but functional parser */
460 fgets(line
, sizeof(line
), f
);
461 if (!feof(f
) && line
[0]) {
462 if (strncmp(line
, "vs ", 3) == 0) {
463 VertShaderFile
= strdup(line
+ 3);
464 VertShaderFile
[strlen(VertShaderFile
) - 1] = 0;
466 else if (strncmp(line
, "fs ", 3) == 0) {
467 FragShaderFile
= strdup(line
+ 3);
468 FragShaderFile
[strlen(FragShaderFile
) - 1] = 0;
470 else if (strncmp(line
, "texture ", 8) == 0) {
471 char texFileName
[100];
473 k
= sscanf(line
+ 8, "%d %s", &unit
, texFileName
);
475 LoadTexture(unit
, texFileName
);
477 else if (strncmp(line
, "uniform ", 8) == 0) {
478 char name
[1000], typeName
[100];
480 float v1
= 0.0F
, v2
= 0.0F
, v3
= 0.0F
, v4
= 0.0F
;
483 k
= sscanf(line
+ 8, "%s %s %f %f %f %f", name
, typeName
,
486 type
= TypeFromName(typeName
);
488 strcpy(conf
->uniforms
[conf
->num_uniforms
].name
, name
);
489 conf
->uniforms
[conf
->num_uniforms
].value
[0] = v1
;
490 conf
->uniforms
[conf
->num_uniforms
].value
[1] = v2
;
491 conf
->uniforms
[conf
->num_uniforms
].value
[2] = v3
;
492 conf
->uniforms
[conf
->num_uniforms
].value
[3] = v4
;
493 conf
->uniforms
[conf
->num_uniforms
].type
= type
;
494 conf
->num_uniforms
++;
497 if (strlen(line
) > 1) {
498 fprintf(stderr
, "syntax error in: %s\n", line
);
512 struct config_file config
;
513 memset(&config
, 0, sizeof(config
));
516 ReadConfigFile(ConfigFile
, &config
);
518 if (!VertShaderFile
) {
519 fprintf(stderr
, "Error: no vertex shader\n");
523 if (!FragShaderFile
) {
524 fprintf(stderr
, "Error: no fragment shader\n");
528 if (!ShadersSupported())
531 vertShader
= CompileShaderFile(GL_VERTEX_SHADER
, VertShaderFile
);
532 fragShader
= CompileShaderFile(GL_FRAGMENT_SHADER
, FragShaderFile
);
533 Program
= LinkShaders(vertShader
, fragShader
);
535 glUseProgram(Program
);
537 NumUniforms
= GetUniforms(Program
, Uniforms
);
538 if (config
.num_uniforms
) {
539 InitUniforms(&config
, Uniforms
);
542 RandomUniformValues();
544 SetUniformValues(Program
, Uniforms
);
545 PrintUniforms(Uniforms
);
547 NumAttribs
= GetAttribs(Program
, Attribs
);
548 PrintAttribs(Attribs
);
550 //assert(glGetError() == 0);
552 glClearColor(0.4f
, 0.4f
, 0.8f
, 0.0f
);
554 glEnable(GL_DEPTH_TEST
);
563 printf("Keyboard:\n");
564 printf(" a Animation toggle\n");
565 printf(" r Randomize uniform values\n");
566 printf(" o Change object\n");
567 printf(" arrows Rotate object\n");
568 printf(" ESC Exit\n");
576 printf(" shtest config.shtest\n");
577 printf(" Run w/ given config file.\n");
578 printf(" shtest --vs vertShader --fs fragShader\n");
579 printf(" Load/compile given shaders.\n");
584 ParseOptions(int argc
, char *argv
[])
593 for (i
= 1; i
< argc
; i
++) {
594 if (strcmp(argv
[i
], "--fs") == 0) {
595 FragShaderFile
= argv
[i
+1];
598 else if (strcmp(argv
[i
], "--vs") == 0) {
599 VertShaderFile
= argv
[i
+1];
603 /* assume the arg is a config file */
604 ConfigFile
= argv
[i
];
612 main(int argc
, char *argv
[])
614 glutInit(&argc
, argv
);
615 glutInitWindowPosition( 0, 0);
616 glutInitWindowSize(400, 400);
617 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
618 win
= glutCreateWindow(argv
[0]);
620 glutReshapeFunc(Reshape
);
621 glutKeyboardFunc(Key
);
622 glutSpecialFunc(SpecialKey
);
623 glutDisplayFunc(Redisplay
);
624 ParseOptions(argc
, argv
);