132001f49Smrg/*
232001f49Smrg * Simple shader test harness.
332001f49Smrg * Brian Paul
432001f49Smrg * 13 Aug 2009
532001f49Smrg *
632001f49Smrg * Usage:
732001f49Smrg *   shtest --vs vertShaderFile --fs fragShaderFile
832001f49Smrg *
932001f49Smrg *   In this case the given vertex/frag shaders are read and compiled.
1032001f49Smrg *   Random values are assigned to the uniforms.
1132001f49Smrg *
1232001f49Smrg * or:
1332001f49Smrg *   shtest configFile
1432001f49Smrg *
1532001f49Smrg *   In this case a config file is read that specifies the file names
1632001f49Smrg *   of the shaders plus initial values for uniforms.
1732001f49Smrg *
1832001f49Smrg * Example config file:
1932001f49Smrg *
2032001f49Smrg * vs shader.vert
2132001f49Smrg * fs shader.frag
2232001f49Smrg * uniform GL_FLOAT pi 3.14159
2332001f49Smrg * uniform GL_FLOAT_VEC4 v1 1.0 0.5 0.2 0.3
2432001f49Smrg * texture 0 2D texture0.rgb
2532001f49Smrg * texture 1 CUBE texture1.rgb
2632001f49Smrg * texture 2 RECT texture2.rgb
2732001f49Smrg *
2832001f49Smrg */
2932001f49Smrg
3032001f49Smrg
3132001f49Smrg#include <assert.h>
3232001f49Smrg#include <stdio.h>
3332001f49Smrg#include <stdlib.h>
3432001f49Smrg#include <string.h>
3532001f49Smrg#include <math.h>
3632001f49Smrg#include <GL/glew.h>
3732001f49Smrg#include "glut_wrap.h"
3832001f49Smrg#include "shaderutil.h"
3932001f49Smrg#include "readtex.h"
4032001f49Smrg
4132001f49Smrg
4232001f49Smrgtypedef enum
4332001f49Smrg{
4432001f49Smrg   SPHERE,
4532001f49Smrg   CUBE,
4632001f49Smrg   NUM_SHAPES
4732001f49Smrg} shape;
4832001f49Smrg
4932001f49Smrg
5032001f49Smrgstatic char *FragShaderFile = NULL;
5132001f49Smrgstatic char *VertShaderFile = NULL;
5232001f49Smrgstatic char *ConfigFile = NULL;
5332001f49Smrg
5432001f49Smrg/* program/shader objects */
5532001f49Smrgstatic GLuint fragShader;
5632001f49Smrgstatic GLuint vertShader;
5732001f49Smrgstatic GLuint Program;
5832001f49Smrg
5932001f49Smrg
6032001f49Smrg#define MAX_UNIFORMS 100
6132001f49Smrgstatic struct uniform_info Uniforms[MAX_UNIFORMS];
6232001f49Smrgstatic GLuint NumUniforms = 0;
6332001f49Smrg
6432001f49Smrg
6532001f49Smrg#define MAX_ATTRIBS 100
6632001f49Smrgstatic struct attrib_info Attribs[MAX_ATTRIBS];
6732001f49Smrgstatic GLuint NumAttribs = 0;
6832001f49Smrg
6932001f49Smrg
7032001f49Smrg/**
7132001f49Smrg * Config file info.
7232001f49Smrg */
7332001f49Smrgstruct config_file
7432001f49Smrg{
7532001f49Smrg   struct name_value
7632001f49Smrg   {
7732001f49Smrg      char name[100];
7832001f49Smrg      float value[4];
7932001f49Smrg      int type;
8032001f49Smrg   } uniforms[100];
8132001f49Smrg
8232001f49Smrg   int num_uniforms;
8332001f49Smrg};
8432001f49Smrg
8532001f49Smrg
8632001f49Smrgstatic GLint win = 0;
8732001f49Smrgstatic GLboolean Anim = GL_FALSE;
8832001f49Smrgstatic GLfloat TexRot = 0.0;
8932001f49Smrgstatic GLfloat xRot = 0.0f, yRot = 0.0f, zRot = 0.0f;
9032001f49Smrgstatic shape Object = SPHERE;
9132001f49Smrg
9232001f49Smrg
9332001f49Smrgstatic float
9432001f49SmrgRandomFloat(float min, float max)
9532001f49Smrg{
9632001f49Smrg   int k = rand() % 10000;
9732001f49Smrg   float x = min + (max - min) * k / 10000.0;
9832001f49Smrg   return x;
9932001f49Smrg}
10032001f49Smrg
10132001f49Smrg
10232001f49Smrg/** Set new random values for uniforms */
10332001f49Smrgstatic void
10432001f49SmrgRandomUniformValues(void)
10532001f49Smrg{
10632001f49Smrg   GLuint i;
10732001f49Smrg   for (i = 0; i < NumUniforms; i++) {
10832001f49Smrg      switch (Uniforms[i].type) {
10932001f49Smrg      case GL_FLOAT:
11032001f49Smrg         Uniforms[i].value[0] = RandomFloat(0.0, 1.0);
11132001f49Smrg         break;
11232001f49Smrg      case GL_SAMPLER_1D:
11332001f49Smrg      case GL_SAMPLER_2D:
11432001f49Smrg      case GL_SAMPLER_3D:
11532001f49Smrg      case GL_SAMPLER_CUBE:
11632001f49Smrg      case GL_SAMPLER_2D_RECT_ARB:
11732001f49Smrg         /* don't change sampler values - random values are bad */
11832001f49Smrg         break;
11932001f49Smrg      default:
12032001f49Smrg         Uniforms[i].value[0] = RandomFloat(-1.0, 2.0);
12132001f49Smrg         Uniforms[i].value[1] = RandomFloat(-1.0, 2.0);
12232001f49Smrg         Uniforms[i].value[2] = RandomFloat(-1.0, 2.0);
12332001f49Smrg         Uniforms[i].value[3] = RandomFloat(-1.0, 2.0);
12432001f49Smrg      }
12532001f49Smrg   }
12632001f49Smrg}
12732001f49Smrg
12832001f49Smrg
12932001f49Smrgstatic void
13032001f49SmrgIdle(void)
13132001f49Smrg{
13232001f49Smrg   yRot += 2.0;
13332001f49Smrg   if (yRot > 360.0)
13432001f49Smrg      yRot -= 360.0;
13532001f49Smrg   glutPostRedisplay();
13632001f49Smrg}
13732001f49Smrg
13832001f49Smrg
13932001f49Smrg
14032001f49Smrgstatic void
14132001f49SmrgSquareVertex(GLfloat s, GLfloat t, GLfloat size)
14232001f49Smrg{
14332001f49Smrg   GLfloat x = -size + s * 2.0 * size;
14432001f49Smrg   GLfloat y = -size + t * 2.0 * size;
14532001f49Smrg   GLuint i;
14632001f49Smrg
14732001f49Smrg   glMultiTexCoord2f(GL_TEXTURE0, s, t);
14832001f49Smrg   glMultiTexCoord2f(GL_TEXTURE1, s, t);
14932001f49Smrg   glMultiTexCoord2f(GL_TEXTURE2, s, t);
15032001f49Smrg   glMultiTexCoord2f(GL_TEXTURE3, s, t);
15132001f49Smrg
15232001f49Smrg   /* assign (s,t) to the generic attributes */
15332001f49Smrg   for (i = 0; i < NumAttribs; i++) {
15432001f49Smrg      if (Attribs[i].location >= 0) {
15532001f49Smrg         glVertexAttrib2f(Attribs[i].location, s, t);
15632001f49Smrg      }
15732001f49Smrg   }
15832001f49Smrg
15932001f49Smrg   glVertex2f(x, y);
16032001f49Smrg}
16132001f49Smrg
16232001f49Smrg
16332001f49Smrg/*
16432001f49Smrg * Draw a square, specifying normal and tangent vectors.
16532001f49Smrg */
16632001f49Smrgstatic void
16732001f49SmrgSquare(GLfloat size)
16832001f49Smrg{
16932001f49Smrg   GLint tangentAttrib = 1;
17032001f49Smrg   glNormal3f(0, 0, 1);
17132001f49Smrg   glVertexAttrib3f(tangentAttrib, 1, 0, 0);
17232001f49Smrg   glBegin(GL_POLYGON);
17332001f49Smrg#if 1
17432001f49Smrg   SquareVertex(0, 0, size);
17532001f49Smrg   SquareVertex(1, 0, size);
17632001f49Smrg   SquareVertex(1, 1, size);
17732001f49Smrg   SquareVertex(0, 1, size);
17832001f49Smrg#else
17932001f49Smrg   glTexCoord2f(0, 0);  glVertex2f(-size, -size);
18032001f49Smrg   glTexCoord2f(1, 0);  glVertex2f( size, -size);
18132001f49Smrg   glTexCoord2f(1, 1);  glVertex2f( size,  size);
18232001f49Smrg   glTexCoord2f(0, 1);  glVertex2f(-size,  size);
18332001f49Smrg#endif
18432001f49Smrg   glEnd();
18532001f49Smrg}
18632001f49Smrg
18732001f49Smrg
18832001f49Smrgstatic void
18932001f49SmrgCube(GLfloat size)
19032001f49Smrg{
19132001f49Smrg   /* +X */
19232001f49Smrg   glPushMatrix();
19332001f49Smrg   glRotatef(90, 0, 1, 0);
19432001f49Smrg   glTranslatef(0, 0, size);
19532001f49Smrg   Square(size);
19632001f49Smrg   glPopMatrix();
19732001f49Smrg
19832001f49Smrg   /* -X */
19932001f49Smrg   glPushMatrix();
20032001f49Smrg   glRotatef(-90, 0, 1, 0);
20132001f49Smrg   glTranslatef(0, 0, size);
20232001f49Smrg   Square(size);
20332001f49Smrg   glPopMatrix();
20432001f49Smrg
20532001f49Smrg   /* +Y */
20632001f49Smrg   glPushMatrix();
20732001f49Smrg   glRotatef(90, 1, 0, 0);
20832001f49Smrg   glTranslatef(0, 0, size);
20932001f49Smrg   Square(size);
21032001f49Smrg   glPopMatrix();
21132001f49Smrg
21232001f49Smrg   /* -Y */
21332001f49Smrg   glPushMatrix();
21432001f49Smrg   glRotatef(-90, 1, 0, 0);
21532001f49Smrg   glTranslatef(0, 0, size);
21632001f49Smrg   Square(size);
21732001f49Smrg   glPopMatrix();
21832001f49Smrg
21932001f49Smrg
22032001f49Smrg   /* +Z */
22132001f49Smrg   glPushMatrix();
22232001f49Smrg   glTranslatef(0, 0, size);
22332001f49Smrg   Square(size);
22432001f49Smrg   glPopMatrix();
22532001f49Smrg
22632001f49Smrg   /* -Z */
22732001f49Smrg   glPushMatrix();
22832001f49Smrg   glRotatef(180, 0, 1, 0);
22932001f49Smrg   glTranslatef(0, 0, size);
23032001f49Smrg   Square(size);
23132001f49Smrg   glPopMatrix();
23232001f49Smrg}
23332001f49Smrg
23432001f49Smrg
23532001f49Smrgstatic void
23632001f49SmrgSphere(GLfloat radius, GLint slices, GLint stacks)
23732001f49Smrg{
23832001f49Smrg   static GLUquadricObj *q = NULL;
23932001f49Smrg
24032001f49Smrg   if (!q) {
24132001f49Smrg      q = gluNewQuadric();
24232001f49Smrg      gluQuadricDrawStyle(q, GLU_FILL);
24332001f49Smrg      gluQuadricNormals(q, GLU_SMOOTH);
24432001f49Smrg      gluQuadricTexture(q, GL_TRUE);
24532001f49Smrg   }
24632001f49Smrg
24732001f49Smrg   gluSphere(q, radius, slices, stacks);
24832001f49Smrg}
24932001f49Smrg
25032001f49Smrg
25132001f49Smrgstatic void
25232001f49SmrgRedisplay(void)
25332001f49Smrg{
25432001f49Smrg   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
25532001f49Smrg
25632001f49Smrg   glPushMatrix();
25732001f49Smrg   glRotatef(xRot, 1.0f, 0.0f, 0.0f);
25832001f49Smrg   glRotatef(yRot, 0.0f, 1.0f, 0.0f);
25932001f49Smrg   glRotatef(zRot, 0.0f, 0.0f, 1.0f);
26032001f49Smrg
26132001f49Smrg   glMatrixMode(GL_TEXTURE);
26232001f49Smrg   glLoadIdentity();
26332001f49Smrg   glRotatef(TexRot, 0.0f, 1.0f, 0.0f);
26432001f49Smrg   glMatrixMode(GL_MODELVIEW);
26532001f49Smrg
26632001f49Smrg   if (Object == SPHERE) {
26732001f49Smrg      Sphere(2.5, 20, 10);
26832001f49Smrg   }
26932001f49Smrg   else if (Object == CUBE) {
27032001f49Smrg      Cube(2.0);
27132001f49Smrg   }
27232001f49Smrg
27332001f49Smrg   glPopMatrix();
27432001f49Smrg
27532001f49Smrg   glutSwapBuffers();
27632001f49Smrg}
27732001f49Smrg
27832001f49Smrg
27932001f49Smrgstatic void
28032001f49SmrgReshape(int width, int height)
28132001f49Smrg{
28232001f49Smrg   glViewport(0, 0, width, height);
28332001f49Smrg   glMatrixMode(GL_PROJECTION);
28432001f49Smrg   glLoadIdentity();
28532001f49Smrg   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
28632001f49Smrg   glMatrixMode(GL_MODELVIEW);
28732001f49Smrg   glLoadIdentity();
28832001f49Smrg   glTranslatef(0.0f, 0.0f, -15.0f);
28932001f49Smrg}
29032001f49Smrg
29132001f49Smrg
29232001f49Smrgstatic void
29332001f49SmrgCleanUp(void)
29432001f49Smrg{
29532001f49Smrg   glDeleteShader(fragShader);
29632001f49Smrg   glDeleteShader(vertShader);
29732001f49Smrg   glDeleteProgram(Program);
29832001f49Smrg   glutDestroyWindow(win);
29932001f49Smrg}
30032001f49Smrg
30132001f49Smrg
30232001f49Smrgstatic void
30332001f49SmrgKey(unsigned char key, int x, int y)
30432001f49Smrg{
30532001f49Smrg   const GLfloat step = 2.0;
30632001f49Smrg  (void) x;
30732001f49Smrg  (void) y;
30832001f49Smrg
30932001f49Smrg   switch(key) {
31032001f49Smrg   case 'a':
31132001f49Smrg      Anim = !Anim;
31232001f49Smrg      if (Anim)
31332001f49Smrg         glutIdleFunc(Idle);
31432001f49Smrg      else
31532001f49Smrg         glutIdleFunc(NULL);
31632001f49Smrg      break;
31732001f49Smrg   case 'z':
31832001f49Smrg      zRot += step;
31932001f49Smrg      break;
32032001f49Smrg   case 'Z':
32132001f49Smrg      zRot -= step;
32232001f49Smrg      break;
32332001f49Smrg   case 'o':
32432001f49Smrg      Object = (Object + 1) % NUM_SHAPES;
32532001f49Smrg      break;
32632001f49Smrg   case 'r':
32732001f49Smrg      RandomUniformValues();
32832001f49Smrg      SetUniformValues(Program, Uniforms);
32932001f49Smrg      PrintUniforms(Uniforms);
33032001f49Smrg      break;
33132001f49Smrg   case 27:
33232001f49Smrg      CleanUp();
33332001f49Smrg      exit(0);
33432001f49Smrg      break;
33532001f49Smrg   }
33632001f49Smrg   glutPostRedisplay();
33732001f49Smrg}
33832001f49Smrg
33932001f49Smrg
34032001f49Smrgstatic void
34132001f49SmrgSpecialKey(int key, int x, int y)
34232001f49Smrg{
34332001f49Smrg   const GLfloat step = 2.0;
34432001f49Smrg
34532001f49Smrg  (void) x;
34632001f49Smrg  (void) y;
34732001f49Smrg
34832001f49Smrg   switch(key) {
34932001f49Smrg   case GLUT_KEY_UP:
35032001f49Smrg      xRot += step;
35132001f49Smrg      break;
35232001f49Smrg   case GLUT_KEY_DOWN:
35332001f49Smrg      xRot -= step;
35432001f49Smrg      break;
35532001f49Smrg   case GLUT_KEY_LEFT:
35632001f49Smrg      yRot -= step;
35732001f49Smrg      break;
35832001f49Smrg   case GLUT_KEY_RIGHT:
35932001f49Smrg      yRot += step;
36032001f49Smrg      break;
36132001f49Smrg   }
36232001f49Smrg   glutPostRedisplay();
36332001f49Smrg}
36432001f49Smrg
36532001f49Smrg
36632001f49Smrgstatic void
36732001f49SmrgInitUniforms(const struct config_file *conf,
36832001f49Smrg             struct uniform_info uniforms[])
36932001f49Smrg{
37032001f49Smrg   int i;
37132001f49Smrg
37232001f49Smrg   for (i = 0; i < conf->num_uniforms; i++) {
37332001f49Smrg      int j;
37432001f49Smrg      for (j = 0; uniforms[j].name; j++) {
37532001f49Smrg         if (strcmp(uniforms[j].name, conf->uniforms[i].name) == 0) {
37632001f49Smrg            uniforms[j].type = conf->uniforms[i].type;
37732001f49Smrg            uniforms[j].value[0] = conf->uniforms[i].value[0];
37832001f49Smrg            uniforms[j].value[1] = conf->uniforms[i].value[1];
37932001f49Smrg            uniforms[j].value[2] = conf->uniforms[i].value[2];
38032001f49Smrg            uniforms[j].value[3] = conf->uniforms[i].value[3];
38132001f49Smrg         }
38232001f49Smrg      }
38332001f49Smrg   }
38432001f49Smrg}
38532001f49Smrg
38632001f49Smrg
38732001f49Smrgstatic void
38832001f49SmrgLoadTexture(GLint unit, GLenum target, const char *texFileName)
38932001f49Smrg{
39032001f49Smrg   GLint imgWidth, imgHeight;
39132001f49Smrg   GLenum imgFormat;
39232001f49Smrg   GLubyte *image = NULL;
39332001f49Smrg   GLuint tex;
39432001f49Smrg   GLenum filter = GL_LINEAR;
39532001f49Smrg   GLenum objTarget;
39632001f49Smrg
39732001f49Smrg   image = LoadRGBImage(texFileName, &imgWidth, &imgHeight, &imgFormat);
39832001f49Smrg   if (!image) {
39932001f49Smrg      printf("Couldn't read %s\n", texFileName);
40032001f49Smrg      exit(1);
40132001f49Smrg   }
40232001f49Smrg
40332001f49Smrg   printf("Load Texture: unit %d, target 0x%x: %s %d x %d\n",
40432001f49Smrg          unit, target, texFileName, imgWidth, imgHeight);
40532001f49Smrg
40632001f49Smrg   if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
40732001f49Smrg       target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
40832001f49Smrg      objTarget = GL_TEXTURE_CUBE_MAP;
40932001f49Smrg   }
41032001f49Smrg   else {
41132001f49Smrg      objTarget = target;
41232001f49Smrg   }
41332001f49Smrg
41432001f49Smrg   glActiveTexture(GL_TEXTURE0 + unit);
41532001f49Smrg   glGenTextures(1, &tex);
41632001f49Smrg   glBindTexture(objTarget, tex);
41732001f49Smrg
41832001f49Smrg   if (target == GL_TEXTURE_3D) {
41932001f49Smrg#ifdef GLU_VERSION_1_3
42032001f49Smrg      /* depth=1 */
42132001f49Smrg      gluBuild3DMipmaps(target, 4, imgWidth, imgHeight, 1,
42232001f49Smrg                        imgFormat, GL_UNSIGNED_BYTE, image);
42332001f49Smrg#else
42432001f49Smrg      fprintf(stderr, "Error: GLU 1.3 not available\n");
42532001f49Smrg      exit(1);
42632001f49Smrg#endif
42732001f49Smrg   }
42832001f49Smrg   else if (target == GL_TEXTURE_1D) {
42932001f49Smrg      gluBuild1DMipmaps(target, 4, imgWidth,
43032001f49Smrg                        imgFormat, GL_UNSIGNED_BYTE, image);
43132001f49Smrg   }
43232001f49Smrg   else {
43332001f49Smrg      gluBuild2DMipmaps(target, 4, imgWidth, imgHeight,
43432001f49Smrg                        imgFormat, GL_UNSIGNED_BYTE, image);
43532001f49Smrg   }
43632001f49Smrg
43732001f49Smrg   free(image);
43832001f49Smrg
43932001f49Smrg   glTexParameteri(objTarget, GL_TEXTURE_WRAP_S, GL_REPEAT);
44032001f49Smrg   glTexParameteri(objTarget, GL_TEXTURE_WRAP_T, GL_REPEAT);
44132001f49Smrg   glTexParameteri(objTarget, GL_TEXTURE_MIN_FILTER, filter);
44232001f49Smrg   glTexParameteri(objTarget, GL_TEXTURE_MAG_FILTER, filter);
44332001f49Smrg}
44432001f49Smrg
44532001f49Smrg
44632001f49Smrgstatic GLenum
44732001f49SmrgTypeFromName(const char *n)
44832001f49Smrg{
44932001f49Smrg   static const struct {
45032001f49Smrg      const char *name;
45132001f49Smrg      GLenum type;
45232001f49Smrg   } types[] = {
45332001f49Smrg      { "GL_FLOAT", GL_FLOAT },
45432001f49Smrg      { "GL_FLOAT_VEC2", GL_FLOAT_VEC2 },
45532001f49Smrg      { "GL_FLOAT_VEC3", GL_FLOAT_VEC3 },
45632001f49Smrg      { "GL_FLOAT_VEC4", GL_FLOAT_VEC4 },
45732001f49Smrg      { "GL_INT", GL_INT },
45832001f49Smrg      { "GL_INT_VEC2", GL_INT_VEC2 },
45932001f49Smrg      { "GL_INT_VEC3", GL_INT_VEC3 },
46032001f49Smrg      { "GL_INT_VEC4", GL_INT_VEC4 },
46132001f49Smrg      { "GL_SAMPLER_1D", GL_SAMPLER_1D },
46232001f49Smrg      { "GL_SAMPLER_2D", GL_SAMPLER_2D },
46332001f49Smrg      { "GL_SAMPLER_3D", GL_SAMPLER_3D },
46432001f49Smrg      { "GL_SAMPLER_CUBE", GL_SAMPLER_CUBE },
46532001f49Smrg      { "GL_SAMPLER_2D_RECT", GL_SAMPLER_2D_RECT_ARB },
46632001f49Smrg      { NULL, 0 }
46732001f49Smrg   };
46832001f49Smrg   GLuint i;
46932001f49Smrg
47032001f49Smrg   for (i = 0; types[i].name; i++) {
47132001f49Smrg      if (strcmp(types[i].name, n) == 0)
47232001f49Smrg         return types[i].type;
47332001f49Smrg   }
47432001f49Smrg   abort();
47532001f49Smrg   return GL_NONE;
47632001f49Smrg}
47732001f49Smrg
47832001f49Smrg
47932001f49Smrg
48032001f49Smrg/**
48132001f49Smrg * Read a config file.
48232001f49Smrg */
48332001f49Smrgstatic void
48432001f49SmrgReadConfigFile(const char *filename, struct config_file *conf)
48532001f49Smrg{
48632001f49Smrg   char line[1000];
48732001f49Smrg   FILE *f;
48832001f49Smrg
48932001f49Smrg   f = fopen(filename, "r");
49032001f49Smrg   if (!f) {
49132001f49Smrg      fprintf(stderr, "Unable to open config file %s\n", filename);
49232001f49Smrg      exit(1);
49332001f49Smrg   }
49432001f49Smrg
49532001f49Smrg   conf->num_uniforms = 0;
49632001f49Smrg
49732001f49Smrg   /* ugly but functional parser */
49832001f49Smrg   while (fgets(line, sizeof(line), f) != NULL) {
49932001f49Smrg      if (line[0]) {
50032001f49Smrg         if (strncmp(line, "vs ", 3) == 0) {
50132001f49Smrg            VertShaderFile = strdup(line + 3);
50232001f49Smrg            VertShaderFile[strlen(VertShaderFile) - 1] = 0;
50332001f49Smrg         }
50432001f49Smrg         else if (strncmp(line, "fs ", 3) == 0) {
50532001f49Smrg            FragShaderFile = strdup(line + 3);
50632001f49Smrg            FragShaderFile[strlen(FragShaderFile) - 1] = 0;
50732001f49Smrg         }
50832001f49Smrg         else if (strncmp(line, "texture ", 8) == 0) {
50932001f49Smrg            char target[100], texFileName[100];
51032001f49Smrg            int unit, k;
51132001f49Smrg            k = sscanf(line + 8, "%d %s %s", &unit, target, texFileName);
51232001f49Smrg            assert(k == 3 || k == 8);
51332001f49Smrg            if (strcmp(target, "CUBE") == 0) {
51432001f49Smrg               char texFileNames[6][100];
51532001f49Smrg               k = sscanf(line + 8, "%d %s  %s %s %s %s %s %s",
51632001f49Smrg                          &unit, target,
51732001f49Smrg                          texFileNames[0],
51832001f49Smrg                          texFileNames[1],
51932001f49Smrg                          texFileNames[2],
52032001f49Smrg                          texFileNames[3],
52132001f49Smrg                          texFileNames[4],
52232001f49Smrg                          texFileNames[5]);
52332001f49Smrg               LoadTexture(unit, GL_TEXTURE_CUBE_MAP_POSITIVE_X, texFileNames[0]);
52432001f49Smrg               LoadTexture(unit, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, texFileNames[1]);
52532001f49Smrg               LoadTexture(unit, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, texFileNames[2]);
52632001f49Smrg               LoadTexture(unit, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, texFileNames[3]);
52732001f49Smrg               LoadTexture(unit, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, texFileNames[4]);
52832001f49Smrg               LoadTexture(unit, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, texFileNames[5]);
52932001f49Smrg            }
53032001f49Smrg            else if (!strcmp(target, "2D")) {
53132001f49Smrg               LoadTexture(unit, GL_TEXTURE_2D, texFileName);
53232001f49Smrg            }
53332001f49Smrg            else if (!strcmp(target, "3D")) {
53432001f49Smrg               LoadTexture(unit, GL_TEXTURE_3D, texFileName);
53532001f49Smrg            }
53632001f49Smrg            else if (!strcmp(target, "RECT")) {
53732001f49Smrg               LoadTexture(unit, GL_TEXTURE_RECTANGLE_ARB, texFileName);
53832001f49Smrg            }
53932001f49Smrg            else {
54032001f49Smrg               printf("Bad texture target: %s\n", target);
54132001f49Smrg               exit(1);
54232001f49Smrg            }
54332001f49Smrg         }
54432001f49Smrg         else if (strncmp(line, "uniform ", 8) == 0) {
54532001f49Smrg            char name[1000], typeName[100];
54632001f49Smrg            int k;
54732001f49Smrg            float v1 = 0.0F, v2 = 0.0F, v3 = 0.0F, v4 = 0.0F;
54832001f49Smrg            GLenum type;
54932001f49Smrg
55032001f49Smrg            k = sscanf(line + 8, "%s %s %f %f %f %f", typeName, name,
55132001f49Smrg                       &v1, &v2, &v3, &v4);
55232001f49Smrg
55332001f49Smrg            type = TypeFromName(typeName);
55432001f49Smrg
55532001f49Smrg            if (strlen(name) + 1 > sizeof(conf->uniforms[conf->num_uniforms].name)) {
55632001f49Smrg               fprintf(stderr, "string overflow\n");
55732001f49Smrg               exit(1);
55832001f49Smrg            }
55932001f49Smrg            strcpy(conf->uniforms[conf->num_uniforms].name, name);
56032001f49Smrg            conf->uniforms[conf->num_uniforms].value[0] = v1;
56132001f49Smrg            conf->uniforms[conf->num_uniforms].value[1] = v2;
56232001f49Smrg            conf->uniforms[conf->num_uniforms].value[2] = v3;
56332001f49Smrg            conf->uniforms[conf->num_uniforms].value[3] = v4;
56432001f49Smrg            conf->uniforms[conf->num_uniforms].type = type;
56532001f49Smrg            conf->num_uniforms++;
56632001f49Smrg         }
56732001f49Smrg         else {
56832001f49Smrg            if (strlen(line) > 1) {
56932001f49Smrg               fprintf(stderr, "syntax error in: %s\n", line);
57032001f49Smrg               break;
57132001f49Smrg            }
57232001f49Smrg         }
57332001f49Smrg      }
57432001f49Smrg   }
57532001f49Smrg
57632001f49Smrg   fclose(f);
57732001f49Smrg}
57832001f49Smrg
57932001f49Smrg
58032001f49Smrgstatic void
58132001f49SmrgInit(void)
58232001f49Smrg{
58332001f49Smrg   GLdouble vertTime = 0.0, fragTime = 0.0, linkTime = 0.0;
58432001f49Smrg   struct config_file config;
58532001f49Smrg
58632001f49Smrg   memset(&config, 0, sizeof(config));
58732001f49Smrg
58832001f49Smrg   if (ConfigFile)
58932001f49Smrg      ReadConfigFile(ConfigFile, &config);
59032001f49Smrg
59132001f49Smrg   if (!ShadersSupported())
59232001f49Smrg      exit(1);
59332001f49Smrg
59432001f49Smrg   if (VertShaderFile) {
59532001f49Smrg      printf("Read vert shader %s\n", VertShaderFile);
59632001f49Smrg      vertShader = CompileShaderFile(GL_VERTEX_SHADER, VertShaderFile);
59732001f49Smrg      vertTime = GetShaderCompileTime();
59832001f49Smrg   }
59932001f49Smrg
60032001f49Smrg   if (FragShaderFile) {
60132001f49Smrg      printf("Read frag shader %s\n", FragShaderFile);
60232001f49Smrg      fragShader = CompileShaderFile(GL_FRAGMENT_SHADER, FragShaderFile);
60332001f49Smrg      fragTime = GetShaderCompileTime();
60432001f49Smrg   }
60532001f49Smrg
60632001f49Smrg   Program = LinkShaders(vertShader, fragShader);
60732001f49Smrg   linkTime = GetShaderLinkTime();
60832001f49Smrg
60932001f49Smrg   printf("Time to compile vertex shader: %fs\n", vertTime);
61032001f49Smrg   printf("Time to compile fragment shader: %fs\n", fragTime);
61132001f49Smrg   printf("Time to link shaders: %fs\n", linkTime);
61232001f49Smrg
61332001f49Smrg   assert(ValidateShaderProgram(Program));
61432001f49Smrg
61532001f49Smrg   glUseProgram(Program);
61632001f49Smrg
61732001f49Smrg   NumUniforms = GetUniforms(Program, Uniforms);
61832001f49Smrg   if (config.num_uniforms) {
61932001f49Smrg      InitUniforms(&config, Uniforms);
62032001f49Smrg   }
62132001f49Smrg   else {
62232001f49Smrg      RandomUniformValues();
62332001f49Smrg   }
62432001f49Smrg   SetUniformValues(Program, Uniforms);
62532001f49Smrg   PrintUniforms(Uniforms);
62632001f49Smrg
62732001f49Smrg   NumAttribs = GetAttribs(Program, Attribs);
62832001f49Smrg   PrintAttribs(Attribs);
62932001f49Smrg
63032001f49Smrg   /* assert(glGetError() == 0); */
63132001f49Smrg
63232001f49Smrg   glClearColor(0.4f, 0.4f, 0.8f, 0.0f);
63332001f49Smrg
63432001f49Smrg   glEnable(GL_DEPTH_TEST);
63532001f49Smrg
63632001f49Smrg   glColor3f(1, 0, 0);
63732001f49Smrg}
63832001f49Smrg
63932001f49Smrg
64032001f49Smrgstatic void
64132001f49SmrgKeys(void)
64232001f49Smrg{
64332001f49Smrg   printf("Keyboard:\n");
64432001f49Smrg   printf("       a  Animation toggle\n");
64532001f49Smrg   printf("       r  Randomize uniform values\n");
64632001f49Smrg   printf("       o  Change object\n");
64732001f49Smrg   printf("  arrows  Rotate object\n");
64832001f49Smrg   printf("     ESC  Exit\n");
64932001f49Smrg}
65032001f49Smrg
65132001f49Smrg
65232001f49Smrgstatic void
65332001f49SmrgUsage(void)
65432001f49Smrg{
65532001f49Smrg   printf("Usage:\n");
65632001f49Smrg   printf("   shtest config.shtest\n");
65732001f49Smrg   printf("       Run w/ given config file.\n");
65832001f49Smrg   printf("   shtest --vs vertShader --fs fragShader\n");
65932001f49Smrg   printf("       Load/compile given shaders.\n");
66032001f49Smrg}
66132001f49Smrg
66232001f49Smrg
66332001f49Smrgstatic void
66432001f49SmrgParseOptions(int argc, char *argv[])
66532001f49Smrg{
66632001f49Smrg   int i;
66732001f49Smrg
66832001f49Smrg   if (argc == 1) {
66932001f49Smrg      Usage();
67032001f49Smrg      exit(1);
67132001f49Smrg   }
67232001f49Smrg
67332001f49Smrg   for (i = 1; i < argc; i++) {
67432001f49Smrg      if (strcmp(argv[i], "--fs") == 0) {
67532001f49Smrg         FragShaderFile = argv[i+1];
67632001f49Smrg         i++;
67732001f49Smrg      }
67832001f49Smrg      else if (strcmp(argv[i], "--vs") == 0) {
67932001f49Smrg         VertShaderFile = argv[i+1];
68032001f49Smrg         i++;
68132001f49Smrg      }
68232001f49Smrg      else {
68332001f49Smrg         /* assume the arg is a config file */
68432001f49Smrg         ConfigFile = argv[i];
68532001f49Smrg         break;
68632001f49Smrg      }
68732001f49Smrg   }
68832001f49Smrg}
68932001f49Smrg
69032001f49Smrg
69132001f49Smrgint
69232001f49Smrgmain(int argc, char *argv[])
69332001f49Smrg{
69432001f49Smrg   glutInitWindowSize(400, 400);
69532001f49Smrg   glutInit(&argc, argv);
69632001f49Smrg   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
69732001f49Smrg   win = glutCreateWindow(argv[0]);
69832001f49Smrg   glewInit();
69932001f49Smrg   glutReshapeFunc(Reshape);
70032001f49Smrg   glutKeyboardFunc(Key);
70132001f49Smrg   glutSpecialFunc(SpecialKey);
70232001f49Smrg   glutDisplayFunc(Redisplay);
70332001f49Smrg   ParseOptions(argc, argv);
70432001f49Smrg   Init();
70532001f49Smrg   Keys();
70632001f49Smrg   glutMainLoop();
70732001f49Smrg   return 0;
70832001f49Smrg}
70932001f49Smrg
710