WIP - port to Mali EGL
[mesa-demos/mali.git] / src / glsl / shtest.c
blobb3c02fa96cb71552d5877d1b3a7860a5abfd7192
1 /*
2 * Simple shader test harness.
3 * Brian Paul
4 * 13 Aug 2009
6 * Usage:
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.
12 * or:
13 * shtest configFile
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:
20 * vs shader.vert
21 * fs shader.frag
22 * uniform GL_FLOAT pi 3.14159
23 * uniform GL_FLOAT_VEC4 v1 1.0 0.5 0.2 0.3
24 * texture 0 2D texture0.rgb
25 * texture 1 CUBE texture1.rgb
26 * texture 2 RECT texture2.rgb
31 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include <GL/glew.h>
37 #include "glut_wrap.h"
38 #include "shaderutil.h"
39 #include "readtex.h"
42 typedef enum
44 SPHERE,
45 CUBE,
46 NUM_SHAPES
47 } shape;
50 static char *FragShaderFile = NULL;
51 static char *VertShaderFile = NULL;
52 static char *ConfigFile = NULL;
54 /* program/shader objects */
55 static GLuint fragShader;
56 static GLuint vertShader;
57 static GLuint Program;
60 #define MAX_UNIFORMS 100
61 static struct uniform_info Uniforms[MAX_UNIFORMS];
62 static GLuint NumUniforms = 0;
65 #define MAX_ATTRIBS 100
66 static struct attrib_info Attribs[MAX_ATTRIBS];
67 static GLuint NumAttribs = 0;
70 /**
71 * Config file info.
73 struct config_file
75 struct name_value
77 char name[100];
78 float value[4];
79 int type;
80 } uniforms[100];
82 int num_uniforms;
86 static GLint win = 0;
87 static GLboolean Anim = GL_FALSE;
88 static GLfloat TexRot = 0.0;
89 static GLfloat xRot = 0.0f, yRot = 0.0f, zRot = 0.0f;
90 static shape Object = SPHERE;
93 static float
94 RandomFloat(float min, float max)
96 int k = rand() % 10000;
97 float x = min + (max - min) * k / 10000.0;
98 return x;
102 /** Set new random values for uniforms */
103 static void
104 RandomUniformValues(void)
106 GLuint i;
107 for (i = 0; i < NumUniforms; i++) {
108 switch (Uniforms[i].type) {
109 case GL_FLOAT:
110 Uniforms[i].value[0] = RandomFloat(0.0, 1.0);
111 break;
112 case GL_SAMPLER_1D:
113 case GL_SAMPLER_2D:
114 case GL_SAMPLER_3D:
115 case GL_SAMPLER_CUBE:
116 case GL_SAMPLER_2D_RECT_ARB:
117 /* don't change sampler values - random values are bad */
118 break;
119 default:
120 Uniforms[i].value[0] = RandomFloat(-1.0, 2.0);
121 Uniforms[i].value[1] = RandomFloat(-1.0, 2.0);
122 Uniforms[i].value[2] = RandomFloat(-1.0, 2.0);
123 Uniforms[i].value[3] = RandomFloat(-1.0, 2.0);
129 static void
130 Idle(void)
132 yRot += 2.0;
133 if (yRot > 360.0)
134 yRot -= 360.0;
135 glutPostRedisplay();
140 static void
141 SquareVertex(GLfloat s, GLfloat t, GLfloat size)
143 GLfloat x = -size + s * 2.0 * size;
144 GLfloat y = -size + t * 2.0 * size;
145 GLuint i;
147 glMultiTexCoord2f(GL_TEXTURE0, s, t);
148 glMultiTexCoord2f(GL_TEXTURE1, s, t);
149 glMultiTexCoord2f(GL_TEXTURE2, s, t);
150 glMultiTexCoord2f(GL_TEXTURE3, s, t);
152 /* assign (s,t) to the generic attributes */
153 for (i = 0; i < NumAttribs; i++) {
154 if (Attribs[i].location >= 0) {
155 glVertexAttrib2f(Attribs[i].location, s, t);
159 glVertex2f(x, y);
164 * Draw a square, specifying normal and tangent vectors.
166 static void
167 Square(GLfloat size)
169 GLint tangentAttrib = 1;
170 glNormal3f(0, 0, 1);
171 glVertexAttrib3f(tangentAttrib, 1, 0, 0);
172 glBegin(GL_POLYGON);
173 #if 1
174 SquareVertex(0, 0, size);
175 SquareVertex(1, 0, size);
176 SquareVertex(1, 1, size);
177 SquareVertex(0, 1, size);
178 #else
179 glTexCoord2f(0, 0); glVertex2f(-size, -size);
180 glTexCoord2f(1, 0); glVertex2f( size, -size);
181 glTexCoord2f(1, 1); glVertex2f( size, size);
182 glTexCoord2f(0, 1); glVertex2f(-size, size);
183 #endif
184 glEnd();
188 static void
189 Cube(GLfloat size)
191 /* +X */
192 glPushMatrix();
193 glRotatef(90, 0, 1, 0);
194 glTranslatef(0, 0, size);
195 Square(size);
196 glPopMatrix();
198 /* -X */
199 glPushMatrix();
200 glRotatef(-90, 0, 1, 0);
201 glTranslatef(0, 0, size);
202 Square(size);
203 glPopMatrix();
205 /* +Y */
206 glPushMatrix();
207 glRotatef(90, 1, 0, 0);
208 glTranslatef(0, 0, size);
209 Square(size);
210 glPopMatrix();
212 /* -Y */
213 glPushMatrix();
214 glRotatef(-90, 1, 0, 0);
215 glTranslatef(0, 0, size);
216 Square(size);
217 glPopMatrix();
220 /* +Z */
221 glPushMatrix();
222 glTranslatef(0, 0, size);
223 Square(size);
224 glPopMatrix();
226 /* -Z */
227 glPushMatrix();
228 glRotatef(180, 0, 1, 0);
229 glTranslatef(0, 0, size);
230 Square(size);
231 glPopMatrix();
235 static void
236 Sphere(GLfloat radius, GLint slices, GLint stacks)
238 static GLUquadricObj *q = NULL;
240 if (!q) {
241 q = gluNewQuadric();
242 gluQuadricDrawStyle(q, GLU_FILL);
243 gluQuadricNormals(q, GLU_SMOOTH);
244 gluQuadricTexture(q, GL_TRUE);
247 gluSphere(q, radius, slices, stacks);
251 static void
252 Redisplay(void)
254 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
256 glPushMatrix();
257 glRotatef(xRot, 1.0f, 0.0f, 0.0f);
258 glRotatef(yRot, 0.0f, 1.0f, 0.0f);
259 glRotatef(zRot, 0.0f, 0.0f, 1.0f);
261 glMatrixMode(GL_TEXTURE);
262 glLoadIdentity();
263 glRotatef(TexRot, 0.0f, 1.0f, 0.0f);
264 glMatrixMode(GL_MODELVIEW);
266 if (Object == SPHERE) {
267 Sphere(2.5, 20, 10);
269 else if (Object == CUBE) {
270 Cube(2.0);
273 glPopMatrix();
275 glutSwapBuffers();
279 static void
280 Reshape(int width, int height)
282 glViewport(0, 0, width, height);
283 glMatrixMode(GL_PROJECTION);
284 glLoadIdentity();
285 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
286 glMatrixMode(GL_MODELVIEW);
287 glLoadIdentity();
288 glTranslatef(0.0f, 0.0f, -15.0f);
292 static void
293 CleanUp(void)
295 glDeleteShader(fragShader);
296 glDeleteShader(vertShader);
297 glDeleteProgram(Program);
298 glutDestroyWindow(win);
302 static void
303 Key(unsigned char key, int x, int y)
305 const GLfloat step = 2.0;
306 (void) x;
307 (void) y;
309 switch(key) {
310 case 'a':
311 Anim = !Anim;
312 if (Anim)
313 glutIdleFunc(Idle);
314 else
315 glutIdleFunc(NULL);
316 break;
317 case 'z':
318 zRot += step;
319 break;
320 case 'Z':
321 zRot -= step;
322 break;
323 case 'o':
324 Object = (Object + 1) % NUM_SHAPES;
325 break;
326 case 'r':
327 RandomUniformValues();
328 SetUniformValues(Program, Uniforms);
329 PrintUniforms(Uniforms);
330 break;
331 case 27:
332 CleanUp();
333 exit(0);
334 break;
336 glutPostRedisplay();
340 static void
341 SpecialKey(int key, int x, int y)
343 const GLfloat step = 2.0;
345 (void) x;
346 (void) y;
348 switch(key) {
349 case GLUT_KEY_UP:
350 xRot += step;
351 break;
352 case GLUT_KEY_DOWN:
353 xRot -= step;
354 break;
355 case GLUT_KEY_LEFT:
356 yRot -= step;
357 break;
358 case GLUT_KEY_RIGHT:
359 yRot += step;
360 break;
362 glutPostRedisplay();
366 static void
367 InitUniforms(const struct config_file *conf,
368 struct uniform_info uniforms[])
370 int i;
372 for (i = 0; i < conf->num_uniforms; i++) {
373 int j;
374 for (j = 0; uniforms[j].name; j++) {
375 if (strcmp(uniforms[j].name, conf->uniforms[i].name) == 0) {
376 uniforms[j].type = conf->uniforms[i].type;
377 uniforms[j].value[0] = conf->uniforms[i].value[0];
378 uniforms[j].value[1] = conf->uniforms[i].value[1];
379 uniforms[j].value[2] = conf->uniforms[i].value[2];
380 uniforms[j].value[3] = conf->uniforms[i].value[3];
387 static void
388 LoadTexture(GLint unit, GLenum target, const char *texFileName)
390 GLint imgWidth, imgHeight;
391 GLenum imgFormat;
392 GLubyte *image = NULL;
393 GLuint tex;
394 GLenum filter = GL_LINEAR;
395 GLenum objTarget;
397 image = LoadRGBImage(texFileName, &imgWidth, &imgHeight, &imgFormat);
398 if (!image) {
399 printf("Couldn't read %s\n", texFileName);
400 exit(1);
403 printf("Load Texture: unit %d, target 0x%x: %s %d x %d\n",
404 unit, target, texFileName, imgWidth, imgHeight);
406 if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
407 target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
408 objTarget = GL_TEXTURE_CUBE_MAP;
410 else {
411 objTarget = target;
414 glActiveTexture(GL_TEXTURE0 + unit);
415 glGenTextures(1, &tex);
416 glBindTexture(objTarget, tex);
418 if (target == GL_TEXTURE_3D) {
419 #ifdef GLU_VERSION_1_3
420 /* depth=1 */
421 gluBuild3DMipmaps(target, 4, imgWidth, imgHeight, 1,
422 imgFormat, GL_UNSIGNED_BYTE, image);
423 #else
424 fprintf(stderr, "Error: GLU 1.3 not available\n");
425 exit(1);
426 #endif
428 else if (target == GL_TEXTURE_1D) {
429 gluBuild1DMipmaps(target, 4, imgWidth,
430 imgFormat, GL_UNSIGNED_BYTE, image);
432 else {
433 gluBuild2DMipmaps(target, 4, imgWidth, imgHeight,
434 imgFormat, GL_UNSIGNED_BYTE, image);
437 free(image);
439 glTexParameteri(objTarget, GL_TEXTURE_WRAP_S, GL_REPEAT);
440 glTexParameteri(objTarget, GL_TEXTURE_WRAP_T, GL_REPEAT);
441 glTexParameteri(objTarget, GL_TEXTURE_MIN_FILTER, filter);
442 glTexParameteri(objTarget, GL_TEXTURE_MAG_FILTER, filter);
446 static GLenum
447 TypeFromName(const char *n)
449 static const struct {
450 const char *name;
451 GLenum type;
452 } types[] = {
453 { "GL_FLOAT", GL_FLOAT },
454 { "GL_FLOAT_VEC2", GL_FLOAT_VEC2 },
455 { "GL_FLOAT_VEC3", GL_FLOAT_VEC3 },
456 { "GL_FLOAT_VEC4", GL_FLOAT_VEC4 },
457 { "GL_INT", GL_INT },
458 { "GL_INT_VEC2", GL_INT_VEC2 },
459 { "GL_INT_VEC3", GL_INT_VEC3 },
460 { "GL_INT_VEC4", GL_INT_VEC4 },
461 { "GL_SAMPLER_1D", GL_SAMPLER_1D },
462 { "GL_SAMPLER_2D", GL_SAMPLER_2D },
463 { "GL_SAMPLER_3D", GL_SAMPLER_3D },
464 { "GL_SAMPLER_CUBE", GL_SAMPLER_CUBE },
465 { "GL_SAMPLER_2D_RECT", GL_SAMPLER_2D_RECT_ARB },
466 { NULL, 0 }
468 GLuint i;
470 for (i = 0; types[i].name; i++) {
471 if (strcmp(types[i].name, n) == 0)
472 return types[i].type;
474 abort();
475 return GL_NONE;
481 * Read a config file.
483 static void
484 ReadConfigFile(const char *filename, struct config_file *conf)
486 char line[1000];
487 FILE *f;
489 f = fopen(filename, "r");
490 if (!f) {
491 fprintf(stderr, "Unable to open config file %s\n", filename);
492 exit(1);
495 conf->num_uniforms = 0;
497 /* ugly but functional parser */
498 while (fgets(line, sizeof(line), f) != NULL) {
499 if (line[0]) {
500 if (strncmp(line, "vs ", 3) == 0) {
501 VertShaderFile = strdup(line + 3);
502 VertShaderFile[strlen(VertShaderFile) - 1] = 0;
504 else if (strncmp(line, "fs ", 3) == 0) {
505 FragShaderFile = strdup(line + 3);
506 FragShaderFile[strlen(FragShaderFile) - 1] = 0;
508 else if (strncmp(line, "texture ", 8) == 0) {
509 char target[100], texFileName[100];
510 int unit, k;
511 k = sscanf(line + 8, "%d %s %s", &unit, target, texFileName);
512 assert(k == 3 || k == 8);
513 if (strcmp(target, "CUBE") == 0) {
514 char texFileNames[6][100];
515 k = sscanf(line + 8, "%d %s %s %s %s %s %s %s",
516 &unit, target,
517 texFileNames[0],
518 texFileNames[1],
519 texFileNames[2],
520 texFileNames[3],
521 texFileNames[4],
522 texFileNames[5]);
523 LoadTexture(unit, GL_TEXTURE_CUBE_MAP_POSITIVE_X, texFileNames[0]);
524 LoadTexture(unit, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, texFileNames[1]);
525 LoadTexture(unit, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, texFileNames[2]);
526 LoadTexture(unit, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, texFileNames[3]);
527 LoadTexture(unit, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, texFileNames[4]);
528 LoadTexture(unit, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, texFileNames[5]);
530 else if (!strcmp(target, "2D")) {
531 LoadTexture(unit, GL_TEXTURE_2D, texFileName);
533 else if (!strcmp(target, "3D")) {
534 LoadTexture(unit, GL_TEXTURE_3D, texFileName);
536 else if (!strcmp(target, "RECT")) {
537 LoadTexture(unit, GL_TEXTURE_RECTANGLE_ARB, texFileName);
539 else {
540 printf("Bad texture target: %s\n", target);
541 exit(1);
544 else if (strncmp(line, "uniform ", 8) == 0) {
545 char name[1000], typeName[100];
546 int k;
547 float v1 = 0.0F, v2 = 0.0F, v3 = 0.0F, v4 = 0.0F;
548 GLenum type;
550 k = sscanf(line + 8, "%s %s %f %f %f %f", typeName, name,
551 &v1, &v2, &v3, &v4);
553 type = TypeFromName(typeName);
555 if (strlen(name) + 1 > sizeof(conf->uniforms[conf->num_uniforms].name)) {
556 fprintf(stderr, "string overflow\n");
557 exit(1);
559 strcpy(conf->uniforms[conf->num_uniforms].name, name);
560 conf->uniforms[conf->num_uniforms].value[0] = v1;
561 conf->uniforms[conf->num_uniforms].value[1] = v2;
562 conf->uniforms[conf->num_uniforms].value[2] = v3;
563 conf->uniforms[conf->num_uniforms].value[3] = v4;
564 conf->uniforms[conf->num_uniforms].type = type;
565 conf->num_uniforms++;
567 else {
568 if (strlen(line) > 1) {
569 fprintf(stderr, "syntax error in: %s\n", line);
570 break;
576 fclose(f);
580 static void
581 Init(void)
583 GLdouble vertTime = 0.0, fragTime = 0.0, linkTime = 0.0;
584 struct config_file config;
586 memset(&config, 0, sizeof(config));
588 if (ConfigFile)
589 ReadConfigFile(ConfigFile, &config);
591 if (!ShadersSupported())
592 exit(1);
594 if (VertShaderFile) {
595 printf("Read vert shader %s\n", VertShaderFile);
596 vertShader = CompileShaderFile(GL_VERTEX_SHADER, VertShaderFile);
597 vertTime = GetShaderCompileTime();
600 if (FragShaderFile) {
601 printf("Read frag shader %s\n", FragShaderFile);
602 fragShader = CompileShaderFile(GL_FRAGMENT_SHADER, FragShaderFile);
603 fragTime = GetShaderCompileTime();
606 Program = LinkShaders(vertShader, fragShader);
607 linkTime = GetShaderLinkTime();
609 printf("Time to compile vertex shader: %fs\n", vertTime);
610 printf("Time to compile fragment shader: %fs\n", fragTime);
611 printf("Time to link shaders: %fs\n", linkTime);
613 assert(ValidateShaderProgram(Program));
615 glUseProgram(Program);
617 NumUniforms = GetUniforms(Program, Uniforms);
618 if (config.num_uniforms) {
619 InitUniforms(&config, Uniforms);
621 else {
622 RandomUniformValues();
624 SetUniformValues(Program, Uniforms);
625 PrintUniforms(Uniforms);
627 NumAttribs = GetAttribs(Program, Attribs);
628 PrintAttribs(Attribs);
630 /* assert(glGetError() == 0); */
632 glClearColor(0.4f, 0.4f, 0.8f, 0.0f);
634 glEnable(GL_DEPTH_TEST);
636 glColor3f(1, 0, 0);
640 static void
641 Keys(void)
643 printf("Keyboard:\n");
644 printf(" a Animation toggle\n");
645 printf(" r Randomize uniform values\n");
646 printf(" o Change object\n");
647 printf(" arrows Rotate object\n");
648 printf(" ESC Exit\n");
652 static void
653 Usage(void)
655 printf("Usage:\n");
656 printf(" shtest config.shtest\n");
657 printf(" Run w/ given config file.\n");
658 printf(" shtest --vs vertShader --fs fragShader\n");
659 printf(" Load/compile given shaders.\n");
663 static void
664 ParseOptions(int argc, char *argv[])
666 int i;
668 if (argc == 1) {
669 Usage();
670 exit(1);
673 for (i = 1; i < argc; i++) {
674 if (strcmp(argv[i], "--fs") == 0) {
675 FragShaderFile = argv[i+1];
676 i++;
678 else if (strcmp(argv[i], "--vs") == 0) {
679 VertShaderFile = argv[i+1];
680 i++;
682 else {
683 /* assume the arg is a config file */
684 ConfigFile = argv[i];
685 break;
692 main(int argc, char *argv[])
694 glutInitWindowSize(400, 400);
695 glutInit(&argc, argv);
696 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
697 win = glutCreateWindow(argv[0]);
698 glewInit();
699 glutReshapeFunc(Reshape);
700 glutKeyboardFunc(Key);
701 glutSpecialFunc(SpecialKey);
702 glutDisplayFunc(Redisplay);
703 ParseOptions(argc, argv);
704 Init();
705 Keys();
706 glutMainLoop();
707 return 0;