1/*
2 * GL_ARB_shading_language_100 test application.
3 *
4 * Tests correctness of emited code. Runs multiple well-formed shaders and checks if
5 * they produce valid results.
6 *
7 * Requires specific support on the GL implementation side. A special function printMESA()
8 * must be supported in the language that prints current values of generic type
9 * to the appropriate shader's info log, and optionally to the screen.
10 *
11 * Author: Michal Krol
12 */
13
14#include "framework.h"
15
16#define EPSILON 0.0001f
17
18static GLhandleARB vert = 0;
19static GLhandleARB prog = 0;
20
21static int get_line (FILE *f, char *line, int size)
22{
23   if (fgets (line, size, f) == NULL)
24      return 0;
25   if (line[strlen (line) - 1] == '\n')
26      line[strlen (line) - 1] = '\0';
27   return 1;
28}
29
30struct ATTRIB
31{
32   char name[32];
33   GLfloat value[64][4];
34   GLuint count;
35};
36
37struct ATTRIBS
38{
39   struct ATTRIB attrib[32];
40   GLuint count;
41};
42
43struct SHADER
44{
45   char code[16000];
46   GLfloat output[1000];
47   GLuint count;
48};
49
50enum SHADER_LOAD_STATE
51{
52   SLS_NONE,
53   SLS_CODE,
54   SLS_OUTPUT
55};
56
57struct PROGRAM
58{
59   struct PROGRAM *next;
60   char name[256];
61   struct ATTRIBS attribs;
62   struct SHADER vertex;
63};
64
65enum PROGRAM_LOAD_STATE
66{
67   PLS_NONE,
68   PLS_ATTRIB,
69   PLS_VERTEX
70};
71
72static struct PROGRAM *program = NULL;
73
74static void load_test_file (const char *filename, struct PROGRAM **program)
75{
76   struct PROGRAM **currprog = program;
77   FILE *f;
78   char line[256];
79   enum PROGRAM_LOAD_STATE pls = PLS_NONE;
80   enum SHADER_LOAD_STATE sls = SLS_NONE;
81
82   f = fopen (filename, "r");
83   if (f == NULL)
84      return;
85
86   while (get_line (f, line, sizeof (line))) {
87      if (line[0] == '$') {
88         if (strncmp (line + 1, "program", 7) == 0) {
89            if (*currprog != NULL)
90               currprog = &(**currprog).next;
91            *currprog = (struct PROGRAM *) (malloc (sizeof (struct PROGRAM)));
92            if (*currprog == NULL)
93               break;
94            (**currprog).next = NULL;
95            strcpy ((**currprog).name, line + 9);
96            (**currprog).attribs.count = 0;
97            (**currprog).vertex.code[0] = '\0';
98            (**currprog).vertex.count = 0;
99            pls = PLS_NONE;
100         }
101         else if (strncmp (line + 1, "attrib", 6) == 0) {
102            if (*currprog == NULL)
103               break;
104            strcpy ((**currprog).attribs.attrib[(**currprog).attribs.count].name, line + 8);
105            (**currprog).attribs.attrib[(**currprog).attribs.count].count = 0;
106            (**currprog).attribs.count++;
107            pls = PLS_ATTRIB;
108         }
109         else if (strcmp (line + 1, "vertex") == 0) {
110            if (*currprog == NULL)
111               break;
112            pls = PLS_VERTEX;
113            sls = SLS_NONE;
114         }
115         else if (strcmp (line + 1, "code") == 0) {
116            if (*currprog == NULL || pls != PLS_VERTEX)
117               break;
118            sls = SLS_CODE;
119         }
120         else if (strcmp (line + 1, "output") == 0) {
121            if (*currprog == NULL || pls != PLS_VERTEX)
122               break;
123            sls = SLS_OUTPUT;
124         }
125      }
126      else {
127         if ((*currprog == NULL || pls == PLS_NONE || sls == SLS_NONE) && line[0] != '\0')
128            break;
129         if (*currprog != NULL && pls == PLS_VERTEX) {
130            if (sls == SLS_CODE) {
131               strcat ((**currprog).vertex.code, line);
132               strcat ((**currprog).vertex.code, "\n");
133            }
134            else if (sls == SLS_OUTPUT && line[0] != '\0') {
135               if (strcmp (line, "true") == 0)
136                  (**currprog).vertex.output[(**currprog).vertex.count] = 1.0f;
137               else if (strcmp (line, "false") == 0)
138                  (**currprog).vertex.output[(**currprog).vertex.count] = 0.0f;
139               else
140                  sscanf (line, "%f", &(**currprog).vertex.output[(**currprog).vertex.count]);
141               (**currprog).vertex.count++;
142            }
143         }
144         else if (*currprog != NULL && pls == PLS_ATTRIB && line[0] != '\0') {
145            struct ATTRIB *att = &(**currprog).attribs.attrib[(**currprog).attribs.count - 1];
146            GLfloat *vec = att->value[att->count];
147            sscanf (line, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
148            att->count++;
149         }
150      }
151   }
152
153   fclose (f);
154}
155
156void InitScene (void)
157{
158   prog = glCreateProgramObjectARB ();
159   vert = glCreateShaderObjectARB (GL_VERTEX_SHADER_ARB);
160   glAttachObjectARB (prog, vert);
161   glDeleteObjectARB (vert);
162   load_test_file ("cltest.txt", &program);
163}
164
165void RenderScene (void)
166{
167   struct PROGRAM *nextprogram;
168   char *code;
169   GLint info_length, length;
170   char output[65000], *p;
171   GLuint i;
172
173   if (program == NULL)
174      exit (0);
175
176   code = program->vertex.code;
177   glShaderSourceARB (vert, 1, (const GLcharARB **) (&code), NULL);
178   glCompileShaderARB (vert);
179   CheckObjectStatus (vert);
180
181   for (i = 0; i < program->attribs.count; i++) {
182      const char *name = program->attribs.attrib[i].name;
183      if (strcmp (name, "gl_Vertex") != 0)
184         glBindAttribLocationARB (prog, i, name);
185   }
186
187   glLinkProgramARB (prog);
188   CheckObjectStatus (prog);
189   glUseProgramObjectARB (prog);
190
191   printf ("\n--- %s\n", program->name);
192
193   glGetObjectParameterivARB (vert, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_length);
194
195   glBegin (GL_POINTS);
196   if (program->attribs.count == 0) {
197      glVertex2f (0.0f, 0.0f);
198   }
199   else {
200      for (i = 0; i < program->attribs.attrib[0].count; i++) {
201         GLuint j;
202         for (j = 0; j < program->attribs.count; j++) {
203            GLuint n = (j + 1) % program->attribs.count;
204            GLfloat *vec = program->attribs.attrib[n].value[i];
205            const char *name = program->attribs.attrib[n].name;
206            if (strcmp (name, "gl_Vertex") == 0)
207               glVertex4fv (vec);
208            else
209               glVertexAttrib4fvARB (n, vec);
210         }
211      }
212   }
213   glEnd ();
214   glFlush ();
215
216   glGetInfoLogARB (vert, sizeof (output), &length, output);
217   p = output + info_length - 1;
218   for (i = 0; i < program->vertex.count; i++) {
219      GLfloat value;
220      if (p == NULL) {
221         printf ("*** %s\n", "I/O error");
222         break;
223      }
224      if (strncmp (p, "true", 4) == 0)
225         value = 1.0f;
226      else if (strncmp (p, "false", 5) == 0)
227         value = 0.0f;
228      else if (sscanf (p, "%f", &value) != 1) {
229         printf ("*** %s\n", "I/O error");
230         break;
231      }
232      if (fabs (value - program->vertex.output[i]) > EPSILON) {
233         printf ("*** Values are different, is %f, should be %f\n", value,
234                 program->vertex.output[i]);
235      }
236      p = strchr (p, '\n');
237      if (p != NULL)
238         p++;
239   }
240   if (p && *p != '\0')
241      printf ("*** %s\n", "I/O error");
242
243   nextprogram = program->next;
244   free (program);
245   program = nextprogram;
246}
247
248int main (int argc, char *argv[])
249{
250   InitFramework (&argc, argv);
251   return 0;
252}
253
254