132001f49Smrg/*
232001f49Smrg * GL_ARB_shading_language_100 test application.
332001f49Smrg *
432001f49Smrg * Tests correctness of emited code. Runs multiple well-formed shaders and checks if
532001f49Smrg * they produce valid results.
632001f49Smrg *
732001f49Smrg * Requires specific support on the GL implementation side. A special function printMESA()
832001f49Smrg * must be supported in the language that prints current values of generic type
932001f49Smrg * to the appropriate shader's info log, and optionally to the screen.
1032001f49Smrg *
1132001f49Smrg * Author: Michal Krol
1232001f49Smrg */
1332001f49Smrg
1432001f49Smrg#include "framework.h"
1532001f49Smrg
1632001f49Smrg#define EPSILON 0.0001f
1732001f49Smrg
1832001f49Smrgstatic GLhandleARB vert = 0;
1932001f49Smrgstatic GLhandleARB prog = 0;
2032001f49Smrg
2132001f49Smrgstatic int get_line (FILE *f, char *line, int size)
2232001f49Smrg{
2332001f49Smrg   if (fgets (line, size, f) == NULL)
2432001f49Smrg      return 0;
2532001f49Smrg   if (line[strlen (line) - 1] == '\n')
2632001f49Smrg      line[strlen (line) - 1] = '\0';
2732001f49Smrg   return 1;
2832001f49Smrg}
2932001f49Smrg
3032001f49Smrgstruct ATTRIB
3132001f49Smrg{
3232001f49Smrg   char name[32];
3332001f49Smrg   GLfloat value[64][4];
3432001f49Smrg   GLuint count;
3532001f49Smrg};
3632001f49Smrg
3732001f49Smrgstruct ATTRIBS
3832001f49Smrg{
3932001f49Smrg   struct ATTRIB attrib[32];
4032001f49Smrg   GLuint count;
4132001f49Smrg};
4232001f49Smrg
4332001f49Smrgstruct SHADER
4432001f49Smrg{
4532001f49Smrg   char code[16000];
4632001f49Smrg   GLfloat output[1000];
4732001f49Smrg   GLuint count;
4832001f49Smrg};
4932001f49Smrg
5032001f49Smrgenum SHADER_LOAD_STATE
5132001f49Smrg{
5232001f49Smrg   SLS_NONE,
5332001f49Smrg   SLS_CODE,
5432001f49Smrg   SLS_OUTPUT
5532001f49Smrg};
5632001f49Smrg
5732001f49Smrgstruct PROGRAM
5832001f49Smrg{
5932001f49Smrg   struct PROGRAM *next;
6032001f49Smrg   char name[256];
6132001f49Smrg   struct ATTRIBS attribs;
6232001f49Smrg   struct SHADER vertex;
6332001f49Smrg};
6432001f49Smrg
6532001f49Smrgenum PROGRAM_LOAD_STATE
6632001f49Smrg{
6732001f49Smrg   PLS_NONE,
6832001f49Smrg   PLS_ATTRIB,
6932001f49Smrg   PLS_VERTEX
7032001f49Smrg};
7132001f49Smrg
7232001f49Smrgstatic struct PROGRAM *program = NULL;
7332001f49Smrg
7432001f49Smrgstatic void load_test_file (const char *filename, struct PROGRAM **program)
7532001f49Smrg{
7632001f49Smrg   struct PROGRAM **currprog = program;
7732001f49Smrg   FILE *f;
7832001f49Smrg   char line[256];
7932001f49Smrg   enum PROGRAM_LOAD_STATE pls = PLS_NONE;
8032001f49Smrg   enum SHADER_LOAD_STATE sls = SLS_NONE;
8132001f49Smrg
8232001f49Smrg   f = fopen (filename, "r");
8332001f49Smrg   if (f == NULL)
8432001f49Smrg      return;
8532001f49Smrg
8632001f49Smrg   while (get_line (f, line, sizeof (line))) {
8732001f49Smrg      if (line[0] == '$') {
8832001f49Smrg         if (strncmp (line + 1, "program", 7) == 0) {
8932001f49Smrg            if (*currprog != NULL)
9032001f49Smrg               currprog = &(**currprog).next;
9132001f49Smrg            *currprog = (struct PROGRAM *) (malloc (sizeof (struct PROGRAM)));
9232001f49Smrg            if (*currprog == NULL)
9332001f49Smrg               break;
9432001f49Smrg            (**currprog).next = NULL;
9532001f49Smrg            strcpy ((**currprog).name, line + 9);
9632001f49Smrg            (**currprog).attribs.count = 0;
9732001f49Smrg            (**currprog).vertex.code[0] = '\0';
9832001f49Smrg            (**currprog).vertex.count = 0;
9932001f49Smrg            pls = PLS_NONE;
10032001f49Smrg         }
10132001f49Smrg         else if (strncmp (line + 1, "attrib", 6) == 0) {
10232001f49Smrg            if (*currprog == NULL)
10332001f49Smrg               break;
10432001f49Smrg            strcpy ((**currprog).attribs.attrib[(**currprog).attribs.count].name, line + 8);
10532001f49Smrg            (**currprog).attribs.attrib[(**currprog).attribs.count].count = 0;
10632001f49Smrg            (**currprog).attribs.count++;
10732001f49Smrg            pls = PLS_ATTRIB;
10832001f49Smrg         }
10932001f49Smrg         else if (strcmp (line + 1, "vertex") == 0) {
11032001f49Smrg            if (*currprog == NULL)
11132001f49Smrg               break;
11232001f49Smrg            pls = PLS_VERTEX;
11332001f49Smrg            sls = SLS_NONE;
11432001f49Smrg         }
11532001f49Smrg         else if (strcmp (line + 1, "code") == 0) {
11632001f49Smrg            if (*currprog == NULL || pls != PLS_VERTEX)
11732001f49Smrg               break;
11832001f49Smrg            sls = SLS_CODE;
11932001f49Smrg         }
12032001f49Smrg         else if (strcmp (line + 1, "output") == 0) {
12132001f49Smrg            if (*currprog == NULL || pls != PLS_VERTEX)
12232001f49Smrg               break;
12332001f49Smrg            sls = SLS_OUTPUT;
12432001f49Smrg         }
12532001f49Smrg      }
12632001f49Smrg      else {
12732001f49Smrg         if ((*currprog == NULL || pls == PLS_NONE || sls == SLS_NONE) && line[0] != '\0')
12832001f49Smrg            break;
12932001f49Smrg         if (*currprog != NULL && pls == PLS_VERTEX) {
13032001f49Smrg            if (sls == SLS_CODE) {
13132001f49Smrg               strcat ((**currprog).vertex.code, line);
13232001f49Smrg               strcat ((**currprog).vertex.code, "\n");
13332001f49Smrg            }
13432001f49Smrg            else if (sls == SLS_OUTPUT && line[0] != '\0') {
13532001f49Smrg               if (strcmp (line, "true") == 0)
13632001f49Smrg                  (**currprog).vertex.output[(**currprog).vertex.count] = 1.0f;
13732001f49Smrg               else if (strcmp (line, "false") == 0)
13832001f49Smrg                  (**currprog).vertex.output[(**currprog).vertex.count] = 0.0f;
13932001f49Smrg               else
14032001f49Smrg                  sscanf (line, "%f", &(**currprog).vertex.output[(**currprog).vertex.count]);
14132001f49Smrg               (**currprog).vertex.count++;
14232001f49Smrg            }
14332001f49Smrg         }
14432001f49Smrg         else if (*currprog != NULL && pls == PLS_ATTRIB && line[0] != '\0') {
14532001f49Smrg            struct ATTRIB *att = &(**currprog).attribs.attrib[(**currprog).attribs.count - 1];
14632001f49Smrg            GLfloat *vec = att->value[att->count];
14732001f49Smrg            sscanf (line, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
14832001f49Smrg            att->count++;
14932001f49Smrg         }
15032001f49Smrg      }
15132001f49Smrg   }
15232001f49Smrg
15332001f49Smrg   fclose (f);
15432001f49Smrg}
15532001f49Smrg
15632001f49Smrgvoid InitScene (void)
15732001f49Smrg{
15832001f49Smrg   prog = glCreateProgramObjectARB ();
15932001f49Smrg   vert = glCreateShaderObjectARB (GL_VERTEX_SHADER_ARB);
16032001f49Smrg   glAttachObjectARB (prog, vert);
16132001f49Smrg   glDeleteObjectARB (vert);
16232001f49Smrg   load_test_file ("cltest.txt", &program);
16332001f49Smrg}
16432001f49Smrg
16532001f49Smrgvoid RenderScene (void)
16632001f49Smrg{
16732001f49Smrg   struct PROGRAM *nextprogram;
16832001f49Smrg   char *code;
16932001f49Smrg   GLint info_length, length;
17032001f49Smrg   char output[65000], *p;
17132001f49Smrg   GLuint i;
17232001f49Smrg
17332001f49Smrg   if (program == NULL)
17432001f49Smrg      exit (0);
17532001f49Smrg
17632001f49Smrg   code = program->vertex.code;
17732001f49Smrg   glShaderSourceARB (vert, 1, (const GLcharARB **) (&code), NULL);
17832001f49Smrg   glCompileShaderARB (vert);
17932001f49Smrg   CheckObjectStatus (vert);
18032001f49Smrg
18132001f49Smrg   for (i = 0; i < program->attribs.count; i++) {
18232001f49Smrg      const char *name = program->attribs.attrib[i].name;
18332001f49Smrg      if (strcmp (name, "gl_Vertex") != 0)
18432001f49Smrg         glBindAttribLocationARB (prog, i, name);
18532001f49Smrg   }
18632001f49Smrg
18732001f49Smrg   glLinkProgramARB (prog);
18832001f49Smrg   CheckObjectStatus (prog);
18932001f49Smrg   glUseProgramObjectARB (prog);
19032001f49Smrg
19132001f49Smrg   printf ("\n--- %s\n", program->name);
19232001f49Smrg
19332001f49Smrg   glGetObjectParameterivARB (vert, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_length);
19432001f49Smrg
19532001f49Smrg   glBegin (GL_POINTS);
19632001f49Smrg   if (program->attribs.count == 0) {
19732001f49Smrg      glVertex2f (0.0f, 0.0f);
19832001f49Smrg   }
19932001f49Smrg   else {
20032001f49Smrg      for (i = 0; i < program->attribs.attrib[0].count; i++) {
20132001f49Smrg         GLuint j;
20232001f49Smrg         for (j = 0; j < program->attribs.count; j++) {
20332001f49Smrg            GLuint n = (j + 1) % program->attribs.count;
20432001f49Smrg            GLfloat *vec = program->attribs.attrib[n].value[i];
20532001f49Smrg            const char *name = program->attribs.attrib[n].name;
20632001f49Smrg            if (strcmp (name, "gl_Vertex") == 0)
20732001f49Smrg               glVertex4fv (vec);
20832001f49Smrg            else
20932001f49Smrg               glVertexAttrib4fvARB (n, vec);
21032001f49Smrg         }
21132001f49Smrg      }
21232001f49Smrg   }
21332001f49Smrg   glEnd ();
21432001f49Smrg   glFlush ();
21532001f49Smrg
21632001f49Smrg   glGetInfoLogARB (vert, sizeof (output), &length, output);
21732001f49Smrg   p = output + info_length - 1;
21832001f49Smrg   for (i = 0; i < program->vertex.count; i++) {
21932001f49Smrg      GLfloat value;
22032001f49Smrg      if (p == NULL) {
22132001f49Smrg         printf ("*** %s\n", "I/O error");
22232001f49Smrg         break;
22332001f49Smrg      }
22432001f49Smrg      if (strncmp (p, "true", 4) == 0)
22532001f49Smrg         value = 1.0f;
22632001f49Smrg      else if (strncmp (p, "false", 5) == 0)
22732001f49Smrg         value = 0.0f;
22832001f49Smrg      else if (sscanf (p, "%f", &value) != 1) {
22932001f49Smrg         printf ("*** %s\n", "I/O error");
23032001f49Smrg         break;
23132001f49Smrg      }
23232001f49Smrg      if (fabs (value - program->vertex.output[i]) > EPSILON) {
23332001f49Smrg         printf ("*** Values are different, is %f, should be %f\n", value,
23432001f49Smrg                 program->vertex.output[i]);
23532001f49Smrg      }
23632001f49Smrg      p = strchr (p, '\n');
23732001f49Smrg      if (p != NULL)
23832001f49Smrg         p++;
23932001f49Smrg   }
24032001f49Smrg   if (p && *p != '\0')
24132001f49Smrg      printf ("*** %s\n", "I/O error");
24232001f49Smrg
24332001f49Smrg   nextprogram = program->next;
24432001f49Smrg   free (program);
24532001f49Smrg   program = nextprogram;
24632001f49Smrg}
24732001f49Smrg
24832001f49Smrgint main (int argc, char *argv[])
24932001f49Smrg{
25032001f49Smrg   InitFramework (&argc, argv);
25132001f49Smrg   return 0;
25232001f49Smrg}
25332001f49Smrg
254