progs/glsl: new shtest program, a simple shader test harness app
authorBrian Paul <brianp@vmware.com>
Thu, 13 Aug 2009 18:52:13 +0000 (12:52 -0600)
committerBrian Paul <brianp@vmware.com>
Thu, 13 Aug 2009 18:52:13 +0000 (12:52 -0600)
This commit includes some sample config files (*.shtest)

progs/glsl/Makefile
progs/glsl/brick.shtest [new file with mode: 0644]
progs/glsl/mandelbrot.shtest [new file with mode: 0644]
progs/glsl/shtest.c [new file with mode: 0644]
progs/glsl/toyball.shtest [new file with mode: 0644]

index eedd866c957b15c306ead48e72471479eb642adc..bbe08c46ac08b4992c2665fbaa48b36213c01460 100644 (file)
@@ -33,6 +33,7 @@ DEMO_SOURCES = \
        points.c \
        samplers.c \
        shadow_sampler.c \
+       shtest.c \
        skinning.c \
        texaaline.c \
        texdemo1.c \
@@ -198,9 +199,14 @@ shadow_sampler.o: $(UTIL_HEADERS)
 shadow_sampler: shadow_sampler.o $(UTIL_OBJS)
 
 
-skinning.o: $(UTIL_HEADERS)
+shtest.o: $(UTIL_HEADERS)
 
-skinning: skinning.o $(UTIL_OBJS)
+shtest: shtest.o $(UTIL_OBJS)
+
+
+shtest.o: $(UTIL_HEADERS)
+
+shtest: shtest.o $(UTIL_OBJS)
 
 
 texaaline.o: $(UTIL_HEADERS)
diff --git a/progs/glsl/brick.shtest b/progs/glsl/brick.shtest
new file mode 100644 (file)
index 0000000..c806a0f
--- /dev/null
@@ -0,0 +1,8 @@
+vs CH06-brick.vert
+fs CH06-brick.frag
+uniform LightPosition 0.1 0.1 9.0
+uniform BrickColor 0.8 0.2 0.2
+uniform MortarColor 0.6 0.6 0.6
+uniform BrickSize  1.0 0.3
+uniform BrickPct 0.9 0.8
+
diff --git a/progs/glsl/mandelbrot.shtest b/progs/glsl/mandelbrot.shtest
new file mode 100644 (file)
index 0000000..f5cca22
--- /dev/null
@@ -0,0 +1,14 @@
+vs CH18-mandel.vert
+fs CH18-mandel.frag
+uniform LightPosition        0.1 0.1 9.0
+uniform SpecularContribution 0.5
+uniform DiffuseContribution  0.5
+uniform Shininess            20.0
+uniform Iterations           12
+uniform Zoom                 0.125
+uniform Xcenter              -1.5
+uniform Ycenter              .005
+uniform InnerColor           1 0 0
+uniform OuterColor1          0 1 0
+uniform OuterColor2          0 0 1
+
diff --git a/progs/glsl/shtest.c b/progs/glsl/shtest.c
new file mode 100644 (file)
index 0000000..7eb7202
--- /dev/null
@@ -0,0 +1,562 @@
+/*
+ * Simple shader test harness.
+ * Brian Paul
+ * 13 Aug 2009
+ *
+ * Usage:
+ *   shtest --vs vertShaderFile --fs fragShaderFile
+ *
+ *   In this case the given vertex/frag shaders are read and compiled.
+ *   Random values are assigned to the uniforms.
+ *
+ * or:
+ *   shtest configFile
+ *
+ *   In this case a config file is read that specifies the file names
+ *   of the shaders plus initial values for uniforms.
+ *
+ * Example config file:
+ *
+ * vs shader.vert
+ * fs shader.frag
+ * uniform pi 3.14159
+ * uniform v1 1.0 0.5 0.2 0.3
+ *
+ */
+
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <GL/glew.h>
+#include <GL/glu.h>
+#include <GL/glut.h>
+#include "shaderutil.h"
+
+
+typedef enum
+{
+   SPHERE,
+   CUBE,
+   NUM_SHAPES
+} shape;
+
+
+static char *FragShaderFile = NULL;
+static char *VertShaderFile = NULL;
+static char *ConfigFile = NULL;
+
+/* program/shader objects */
+static GLuint fragShader;
+static GLuint vertShader;
+static GLuint Program;
+
+
+#define MAX_UNIFORMS 100
+static struct uniform_info Uniforms[MAX_UNIFORMS];
+static GLuint NumUniforms = 0;
+
+
+#define MAX_ATTRIBS 100
+static struct attrib_info Attribs[MAX_ATTRIBS];
+static GLuint NumAttribs = 0;
+
+
+/**
+ * Config file info.
+ */
+struct config_file
+{
+   struct name_value
+   {
+      char name[100];
+      float value[4];
+      int type;
+   } uniforms[100];
+
+   int num_uniforms;
+};
+
+
+static GLint win = 0;
+static GLboolean Anim = GL_FALSE;
+static GLfloat TexRot = 0.0;
+static GLfloat xRot = 0.0f, yRot = 0.0f, zRot = 0.0f;
+static shape Object = SPHERE;
+
+
+static float
+RandomFloat(float min, float max)
+{
+   int k = rand() % 10000;
+   float x = min + (max - min) * k / 10000.0;
+   return x;
+}
+
+
+/** Set new random values for uniforms */
+static void
+RandomUniformValues(void)
+{
+   GLuint i;
+   for (i = 0; i < NumUniforms; i++) {
+      if (Uniforms[i].type == GL_FLOAT) {
+         Uniforms[i].value[0] = RandomFloat(0.0, 1.0);
+      }
+      else {
+         Uniforms[i].value[0] = RandomFloat(-1.0, 2.0);
+         Uniforms[i].value[1] = RandomFloat(-1.0, 2.0);
+         Uniforms[i].value[2] = RandomFloat(-1.0, 2.0);
+         Uniforms[i].value[3] = RandomFloat(-1.0, 2.0);
+      }
+   }
+}
+
+
+static void
+Idle(void)
+{
+   yRot += 2.0;
+   if (yRot > 360.0)
+      yRot -= 360.0;
+   glutPostRedisplay();
+}
+
+
+
+static void
+SquareVertex(GLfloat s, GLfloat t, GLfloat size)
+{
+   GLfloat x = -size + s * 2.0 * size;
+   GLfloat y = -size + t * 2.0 * size;
+   glTexCoord2f(s, t);
+   glVertex2f(x, y);
+}
+
+
+/*
+ * Draw a square, specifying normal and tangent vectors.
+ */
+static void
+Square(GLfloat size)
+{
+   GLint tangentAttrib = 1;
+   glNormal3f(0, 0, 1);
+   glVertexAttrib3f(tangentAttrib, 1, 0, 0);
+   glBegin(GL_POLYGON);
+#if 0
+   SquareVertex(0, 0, size);
+   SquareVertex(1, 0, size);
+   SquareVertex(1, 1, size);
+   SquareVertex(0, 1, size);
+#else
+   glTexCoord2f(0, 0);  glVertex2f(-size, -size);
+   glTexCoord2f(1, 0);  glVertex2f( size, -size);
+   glTexCoord2f(1, 1);  glVertex2f( size,  size);
+   glTexCoord2f(0, 1);  glVertex2f(-size,  size);
+#endif
+   glEnd();
+}
+
+
+static void
+Cube(GLfloat size)
+{
+   /* +X */
+   glPushMatrix();
+   glRotatef(90, 0, 1, 0);
+   glTranslatef(0, 0, size);
+   Square(size);
+   glPopMatrix();
+
+   /* -X */
+   glPushMatrix();
+   glRotatef(-90, 0, 1, 0);
+   glTranslatef(0, 0, size);
+   Square(size);
+   glPopMatrix();
+
+   /* +Y */
+   glPushMatrix();
+   glRotatef(90, 1, 0, 0);
+   glTranslatef(0, 0, size);
+   Square(size);
+   glPopMatrix();
+
+   /* -Y */
+   glPushMatrix();
+   glRotatef(-90, 1, 0, 0);
+   glTranslatef(0, 0, size);
+   Square(size);
+   glPopMatrix();
+
+
+   /* +Z */
+   glPushMatrix();
+   glTranslatef(0, 0, size);
+   Square(size);
+   glPopMatrix();
+
+   /* -Z */
+   glPushMatrix();
+   glRotatef(180, 0, 1, 0);
+   glTranslatef(0, 0, size);
+   Square(size);
+   glPopMatrix();
+}
+
+
+static void
+Sphere(GLfloat radius, GLint slices, GLint stacks)
+{
+   static GLUquadricObj *q = NULL;
+
+   if (!q) {
+      q = gluNewQuadric();
+      gluQuadricDrawStyle(q, GLU_FILL);
+      gluQuadricNormals(q, GLU_SMOOTH);
+      gluQuadricTexture(q, GL_TRUE);
+   }
+
+   gluSphere(q, radius, slices, stacks);
+}
+
+
+static void
+Redisplay(void)
+{
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+   
+   glPushMatrix();
+   glRotatef(xRot, 1.0f, 0.0f, 0.0f);
+   glRotatef(yRot, 0.0f, 1.0f, 0.0f);
+   glRotatef(zRot, 0.0f, 0.0f, 1.0f);
+
+   glMatrixMode(GL_TEXTURE);
+   glLoadIdentity();
+   glRotatef(TexRot, 0.0f, 1.0f, 0.0f);
+   glMatrixMode(GL_MODELVIEW);
+
+   if (Object == SPHERE) {
+      Sphere(2.0, 20, 10);
+   }
+   else if (Object == CUBE) {
+      Cube(2.0);
+   }
+
+   glPopMatrix();
+
+   glutSwapBuffers();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+   glViewport(0, 0, width, height);
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glTranslatef(0.0f, 0.0f, -15.0f);
+}
+
+
+static void
+CleanUp(void)
+{
+   glDeleteShader(fragShader);
+   glDeleteShader(vertShader);
+   glDeleteProgram(Program);
+   glutDestroyWindow(win);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+   const GLfloat step = 2.0;
+  (void) x;
+  (void) y;
+
+   switch(key) {
+   case 'a':
+      Anim = !Anim;
+      if (Anim)
+         glutIdleFunc(Idle);
+      else
+         glutIdleFunc(NULL);
+      break;
+   case 'z':
+      zRot += step;
+      break;
+   case 'Z':
+      zRot -= step;
+      break;
+   case 'o':
+      Object = (Object + 1) % NUM_SHAPES;
+      break;
+   case 'r':
+      RandomUniformValues();
+      SetUniformValues(Program, Uniforms);
+      PrintUniforms(Uniforms);
+      break;
+   case 27:
+      CleanUp();
+      exit(0);
+      break;
+   }
+   glutPostRedisplay();
+}
+
+
+static void
+SpecialKey(int key, int x, int y)
+{
+   const GLfloat step = 2.0;
+
+  (void) x;
+  (void) y;
+
+   switch(key) {
+   case GLUT_KEY_UP:
+      xRot += step;
+      break;
+   case GLUT_KEY_DOWN:
+      xRot -= step;
+      break;
+   case GLUT_KEY_LEFT:
+      yRot -= step;
+      break;
+   case GLUT_KEY_RIGHT:
+      yRot += step;
+      break;
+   }
+   glutPostRedisplay();
+}
+
+
+static void
+InitUniforms(const struct config_file *conf,
+             struct uniform_info uniforms[])
+{
+   int i;
+
+   for (i = 0; i < conf->num_uniforms; i++) {
+      int j;
+      for (j = 0; uniforms[j].name; j++) {
+         if (strcmp(uniforms[j].name, conf->uniforms[i].name) == 0) {
+            uniforms[j].type = conf->uniforms[i].type;
+            uniforms[j].value[0] = conf->uniforms[i].value[0];
+            uniforms[j].value[1] = conf->uniforms[i].value[1];
+            uniforms[j].value[2] = conf->uniforms[i].value[2];
+            uniforms[j].value[3] = conf->uniforms[i].value[3];
+         }
+      }
+   }
+}
+
+
+/**
+ * Read a config file.
+ */
+static void
+ReadConfigFile(const char *filename, struct config_file *conf)
+{
+   char line[1000];
+   FILE *f;
+
+   f = fopen(filename, "r");
+   if (!f) {
+      fprintf(stderr, "Unable to open config file %s\n", filename);
+      exit(1);
+   }
+
+   conf->num_uniforms = 0;
+
+   /* ugly but functional parser */
+   while (!feof(f)) {
+      fgets(line, sizeof(line), f);
+      if (line[0]) {
+         if (strncmp(line, "vs ", 3) == 0) {
+            VertShaderFile = strdup(line + 3);
+            VertShaderFile[strlen(VertShaderFile) - 1] = 0;
+         }
+         else if (strncmp(line, "fs ", 3) == 0) {
+            FragShaderFile = strdup(line + 3);
+            FragShaderFile[strlen(FragShaderFile) - 1] = 0;
+         }
+         else if (strncmp(line, "uniform ", 8) == 0) {
+            char name[1000];
+            int k;
+            float v1, v2, v3, v4;
+            GLenum type;
+
+            k = sscanf(line + 8, "%s %f %f %f %f", name, &v1, &v2, &v3, &v4);
+
+            switch (k) {
+            case 1:
+               type = GL_NONE;
+               abort();
+               break;
+            case 2:
+               type = GL_FLOAT;
+               break;
+            case 3:
+               type = GL_FLOAT_VEC2;
+               break;
+            case 4:
+               type = GL_FLOAT_VEC3;
+               break;
+            case 5:
+               type = GL_FLOAT_VEC4;
+               break;
+            }
+
+            strcpy(conf->uniforms[conf->num_uniforms].name, name);
+            conf->uniforms[conf->num_uniforms].value[0] = v1;
+            conf->uniforms[conf->num_uniforms].value[1] = v2;
+            conf->uniforms[conf->num_uniforms].value[2] = v3;
+            conf->uniforms[conf->num_uniforms].value[3] = v4;
+            conf->uniforms[conf->num_uniforms].type = type;
+            conf->num_uniforms++;
+         }
+         else {
+            if (strlen(line) > 1) {
+               fprintf(stderr, "syntax error in: %s\n", line);
+               break;
+            }
+         }
+      }
+   }
+
+   fclose(f);
+}
+
+
+static void
+Init(void)
+{
+   struct config_file config;
+   memset(&config, 0, sizeof(config));
+
+   if (ConfigFile)
+      ReadConfigFile(ConfigFile, &config);
+
+   if (!VertShaderFile) {
+      fprintf(stderr, "Error: no vertex shader\n");
+      exit(1);
+   }
+
+   if (!FragShaderFile) {
+      fprintf(stderr, "Error: no fragment shader\n");
+      exit(1);
+   }
+
+   if (!ShadersSupported())
+      exit(1);
+
+   vertShader = CompileShaderFile(GL_VERTEX_SHADER, VertShaderFile);
+   fragShader = CompileShaderFile(GL_FRAGMENT_SHADER, FragShaderFile);
+   Program = LinkShaders(vertShader, fragShader);
+
+   glUseProgram(Program);
+
+   NumUniforms = GetUniforms(Program, Uniforms);
+   if (config.num_uniforms) {
+      InitUniforms(&config, Uniforms);
+   }
+   else {
+      RandomUniformValues();
+   }
+   SetUniformValues(Program, Uniforms);
+   PrintUniforms(Uniforms);
+
+   NumAttribs = GetAttribs(Program, Attribs);
+   PrintAttribs(Attribs);
+
+   //assert(glGetError() == 0);
+
+   glClearColor(0.4f, 0.4f, 0.8f, 0.0f);
+
+   glEnable(GL_DEPTH_TEST);
+
+   glColor3f(1, 0, 0);
+}
+
+
+static void
+Keys(void)
+{
+   printf("Keyboard:\n");
+   printf("       a  Animation toggle\n");
+   printf("       r  Randomize uniform values\n");
+   printf("       o  Change object\n");
+   printf("  arrows  Rotate object\n");
+   printf("     ESC  Exit\n");
+}
+
+
+static void
+Usage(void)
+{
+   printf("Usage:\n");
+   printf("   shtest config.shtest\n");
+   printf("       Run w/ given config file.\n");
+   printf("   shtest --vs vertShader --fs fragShader\n");
+   printf("       Load/compile given shaders.\n");
+}
+
+
+static void
+ParseOptions(int argc, char *argv[])
+{
+   int i;
+
+   if (argc == 1) {
+      Usage();
+      exit(1);
+   }
+
+   for (i = 1; i < argc; i++) {
+      if (strcmp(argv[i], "--fs") == 0) {
+         FragShaderFile = argv[i+1];
+         i++;
+      }
+      else if (strcmp(argv[i], "--vs") == 0) {
+         VertShaderFile = argv[i+1];
+         i++;
+      }
+      else {
+         /* assume the arg is a config file */
+         ConfigFile = argv[i];
+         break;
+      }
+   }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+   glutInit(&argc, argv);
+   glutInitWindowPosition( 0, 0);
+   glutInitWindowSize(400, 400);
+   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+   win = glutCreateWindow(argv[0]);
+   glewInit();
+   glutReshapeFunc(Reshape);
+   glutKeyboardFunc(Key);
+   glutSpecialFunc(SpecialKey);
+   glutDisplayFunc(Redisplay);
+   ParseOptions(argc, argv);
+   Init();
+   Keys();
+   glutMainLoop();
+   return 0;
+}
+
diff --git a/progs/glsl/toyball.shtest b/progs/glsl/toyball.shtest
new file mode 100644 (file)
index 0000000..2852ab0
--- /dev/null
@@ -0,0 +1,17 @@
+vs CH11-toyball.vert
+fs CH11-toyball.frag
+uniform LightDir  0.57737 0.57735 0.57735 0.0
+uniform HVector 0.32506 0.32506 0.88808 0.0
+uniform BallCenter 0.0 0.0 0.0 1.0
+uniform SpecularColor 0.4 0.4 0.4 60.0
+uniform Red     0.6 0.0 0.0 1.0
+uniform Blue    0.0 0.3 0.6 1.0
+uniform Yellow  0.6 0.5 0.0 1.0
+uniform HalfSpace0 1.0 0.0 0.0 0.2
+uniform HalfSpace1 .309016994 0.951056516 0.0 0.2
+uniform HalfSpace2 -0.809016994 0.587785252 0.0 0.2
+uniform HalfSpace3 -0.809016994 -0.587785252 0.0 0.2
+uniform HalfSpace4 .309116994 -0.951056516 0.0 0.2
+uniform InOrOutInit -3.0
+uniform StripeWidth 0.3
+uniform FWidth  .005