1/*
2 * GL_ARB_vertex_shader test application. Feeds a vertex shader with attributes that
3 * that have magic values and check if the values received by the shader are the same.
4 *
5 * Requires specific support on the GL implementation side. A special function printMESA()
6 * must be supported in the language that prints variable's current value of generic type
7 * to the appropriate shader's info log, and optionally to the screen.
8 *
9 * Perfectly valid behaviour produces output that does not have a line
10 * beginning with three stars (***).
11 *
12 * Author: Michal Krol
13 */
14
15#include "framework.h"
16
17#define EPSILON 0.0001f
18
19static GLhandleARB vert = 0;
20static GLhandleARB prog = 0;
21
22enum SUBMIT_MODE
23{
24   SM_IM,
25   SM_VA,
26   SM_IM_DL,
27   SM_VA_DL,
28   SM_MAX
29};
30
31static enum SUBMIT_MODE submit_method = SM_IM;
32
33#define C 0
34#define S 1
35#define N 2
36#define V 3
37#define T 4
38#define F 5
39#define A 6
40
41struct ATTRIB_DATA
42{
43   const char *name;
44   GLuint dispatch;
45   GLint index;
46   GLint bind;
47   GLuint size;
48   GLfloat data[4];
49};
50
51static struct ATTRIB_DATA attribs[] = {
52   { "gl_Color",          C, -1, -1, 4, { 4.2f, 0.56f, -2.1f, 0.29f } },
53   { "gl_SecondaryColor", S, -1, -1, 4, { 0.38f, 2.0f, 0.99f, 1.0f } },
54   { "gl_Normal",         N, -1, -1, 3, { 54.0f, 77.0f, 1.15f, 0.0f } },
55   { "gl_MultiTexCoord0", T, 0,  -1, 4, { 11.1f, 11.2f, 11.3f, 11.4f } },
56   { "gl_MultiTexCoord1", T, 1,  -1, 4, { 22.1f, 22.2f, 22.3f, 22.4f } },
57   { "gl_MultiTexCoord2", T, 2,  -1, 4, { 33.1f, 33.2f, 33.3f, 33.4f } },
58   { "gl_MultiTexCoord3", T, 3,  -1, 4, { 44.1f, 44.2f, 44.3f, 44.4f } },
59   { "gl_MultiTexCoord4", T, 4,  -1, 4, { 55.1f, 55.2f, 55.3f, 55.4f } },
60   { "gl_MultiTexCoord5", T, 5,  -1, 4, { 66.1f, 66.2f, 66.3f, 66.4f } },
61   { "gl_MultiTexCoord6", T, 6,  -1, 4, { 77.1f, 77.2f, 77.3f, 77.4f } },
62   { "gl_MultiTexCoord7", T, 7,  -1, 4, { 88.1f, 88.2f, 88.3f, 88.4f } },
63   { "gl_FogCoord",       F, -1, -1, 1, { 0.63f, 0.0f, 0.0f, 0.0f } },
64   { "Attribute1",        A, 1,  1,  4, { 1.11f, 1.22f, 1.33f, 1.44f } },
65   { "Attribute2",        A, 2,  2,  4, { 2.11f, 2.22f, 2.33f, 2.44f } },
66   { "Attribute3",        A, 3,  3,  4, { 3.11f, 3.22f, 3.33f, 3.44f } },
67   { "Attribute4",        A, 4,  4,  1, { 4.11f, 0.0f, 0.0f, 0.0f } },
68   { "Attribute5",        A, 5,  5,  2, { 5.11f, 5.22f, 0.0f, 0.0f } },
69   { "Attribute6",        A, 6,  6,  3, { 6.11f, 6.22f, 6.33f, 0.0f } },
70   { "Attribute7",        A, 7,  7,  2, { 7.11f, 7.22f, 0.0f, 0.0f } },
71   { "Attribute7",        A, 8,  -1, 2, { 8.11f, 8.22f, 0.0f, 0.0f } },
72   { "Attribute9",        A, 9,  9,  3, { 9.11f, 9.22f, 9.33f, 0.0f } },
73   { "Attribute9",        A, 10, -1, 3, { 10.11f, 10.22f, 10.33f, 0.0f } },
74   { "Attribute9",        A, 11, -1, 3, { 11.11f, 11.22f, 11.33f, 0.0f } },
75   { "Attribute12",       A, 12, 12, 4, { 12.11f, 12.22f, 12.33f, 12.44f } },
76   { "Attribute12",       A, 13, -1, 4, { 13.11f, 13.22f, 13.33f, 13.44f } },
77   { "Attribute12",       A, 14, -1, 4, { 14.11f, 14.22f, 14.33f, 14.44f } },
78   { "Attribute12",       A, 15, -1, 4, { 15.11f, 15.22f, 15.33f, 15.44f } },
79   { "gl_Vertex",         V, 16, -1, 4, { 0.25f, -0.14f, 0.01f, 1.0f } }
80};
81
82static void im_render (void)
83{
84   GLint i;
85
86   glBegin (GL_POINTS);
87   for (i = 0; i < sizeof (attribs) / sizeof (*attribs); i++) {
88      struct ATTRIB_DATA *att = &attribs[i];
89      switch (att->dispatch)
90      {
91      case C:
92         glColor4fv (att->data);
93         break;
94      case S:
95         glSecondaryColor3fvEXT (att->data);
96         break;
97      case N:
98         glNormal3fv (att->data);
99         break;
100      case V:
101         glVertex4fv (att->data);
102         break;
103      case T:
104         assert (att->index >= 0 && att->index < 8);
105         glMultiTexCoord4fvARB (GL_TEXTURE0_ARB + att->index, att->data);
106         break;
107      case F:
108         glFogCoordfvEXT (att->data);
109         break;
110      case A:
111         assert (att->index > 0 && att->index < 16);
112         glVertexAttrib4fvARB (att->index, att->data);
113         break;
114      default:
115         assert (0);
116      }
117   }
118   glEnd ();
119}
120
121static void va_render (void)
122{
123   GLint i;
124
125   for (i = 0; i < sizeof (attribs) / sizeof (*attribs); i++) {
126      struct ATTRIB_DATA *att = &attribs[i];
127      switch (att->dispatch)
128      {
129      case C:
130         glColorPointer (4, GL_FLOAT, 0, att->data);
131         glEnableClientState (GL_COLOR_ARRAY);
132         break;
133      case S:
134         glSecondaryColorPointerEXT (4, GL_FLOAT, 0, att->data);
135         glEnableClientState (GL_SECONDARY_COLOR_ARRAY_EXT);
136         break;
137      case N:
138         glNormalPointer (GL_FLOAT, 0, att->data);
139         glEnableClientState (GL_NORMAL_ARRAY);
140         break;
141      case V:
142         glVertexPointer (4, GL_FLOAT, 0, att->data);
143         glEnableClientState (GL_VERTEX_ARRAY);
144         break;
145      case T:
146         assert (att->index >= 0 && att->index < 8);
147         glClientActiveTextureARB (GL_TEXTURE0_ARB + att->index);
148         glTexCoordPointer (4, GL_FLOAT, 0, att->data);
149         glEnableClientState (GL_TEXTURE_COORD_ARRAY);
150         break;
151      case F:
152         glFogCoordPointerEXT (GL_FLOAT, 0, att->data);
153         glEnableClientState (GL_FOG_COORDINATE_ARRAY_EXT);
154         break;
155      case A:
156         assert (att->index > 0 && att->index < 16);
157         glVertexAttribPointerARB (att->index, 4, GL_FLOAT, GL_FALSE, 0, att->data);
158         glEnableVertexAttribArrayARB (att->index);
159         break;
160      default:
161         assert (0);
162      }
163   }
164
165   glDrawArrays (GL_POINTS, 0, 1);
166
167   for (i = 0; i < sizeof (attribs) / sizeof (*attribs); i++) {
168      struct ATTRIB_DATA *att = &attribs[i];
169      switch (att->dispatch)
170      {
171      case C:
172         glDisableClientState (GL_COLOR_ARRAY);
173         break;
174      case S:
175         glDisableClientState (GL_SECONDARY_COLOR_ARRAY_EXT);
176         break;
177      case N:
178         glDisableClientState (GL_NORMAL_ARRAY);
179         break;
180      case V:
181         glDisableClientState (GL_VERTEX_ARRAY);
182         break;
183      case T:
184         glClientActiveTextureARB (GL_TEXTURE0_ARB + att->index);
185         glDisableClientState (GL_TEXTURE_COORD_ARRAY);
186         break;
187      case F:
188         glDisableClientState (GL_FOG_COORDINATE_ARRAY_EXT);
189         break;
190      case A:
191         glDisableVertexAttribArrayARB (att->index);
192         break;
193      default:
194         assert (0);
195      }
196   }
197}
198
199static void dl_start (void)
200{
201   glNewList (GL_COMPILE, 1);
202}
203
204static void dl_end (void)
205{
206   glEndList ();
207   glCallList (1);
208}
209
210static void load_test_file (const char *filename)
211{
212   FILE *f;
213   GLint size;
214   char *code;
215   GLint i;
216
217   f = fopen (filename, "r");
218   if (f == NULL)
219      return;
220
221   fseek (f, 0, SEEK_END);
222   size = ftell (f);
223
224   if (size == -1) {
225      fclose (f);
226      return;
227   }
228
229   fseek (f, 0, SEEK_SET);
230
231   code = (char *) (malloc (size));
232   if (code == NULL) {
233      fclose (f);
234      return;
235   }
236   size = fread (code, 1, size, f);
237   fclose (f);
238
239   glShaderSourceARB (vert, 1, (const GLcharARB **) (&code), &size);
240   glCompileShaderARB (vert);
241   if (!CheckObjectStatus (vert))
242      exit (0);
243
244   for (i = 0; i < sizeof (attribs) / sizeof (*attribs); i++)
245      if (attribs[i].dispatch == A && attribs[i].bind != -1)
246         glBindAttribLocationARB (prog, attribs[i].bind, attribs[i].name);
247}
248
249void InitScene (void)
250{
251   prog = glCreateProgramObjectARB ();
252   vert = glCreateShaderObjectARB (GL_VERTEX_SHADER_ARB);
253   glAttachObjectARB (prog, vert);
254   glDeleteObjectARB (vert);
255   load_test_file ("vstest.txt");
256   glLinkProgramARB (prog);
257   if (!CheckObjectStatus (prog))
258      exit (0);
259   glUseProgramObjectARB (prog);
260}
261
262void RenderScene (void)
263{
264   GLint info_length, length;
265   char output[65000], *p;
266   GLint i;
267
268   if (submit_method == SM_MAX)
269      exit (0);
270
271   /*
272    * Get the current size of the info log. Any text output produced by executed
273    * shader will be appended to the end of log.
274    */
275   glGetObjectParameterivARB (vert, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_length);
276
277   switch (submit_method)
278   {
279   case SM_IM:
280      printf ("\n--- TESTING IMMEDIATE MODE\n");
281      im_render ();
282      break;
283   case SM_VA:
284      printf ("\n--- TESTING VERTEX ARRAY MODE\n");
285      va_render ();
286      break;
287   case SM_IM_DL:
288      printf ("\n--- TESTING IMMEDIATE + DISPLAY LIST MODE\n");
289      dl_start ();
290      im_render ();
291      dl_end ();
292      break;
293   case SM_VA_DL:
294      printf ("\n--- TESTING VERTEX ARRAY + DISPLAY LIST MODE\n");
295      dl_start ();
296      va_render ();
297      dl_end ();
298      break;
299   default:
300      assert (0);
301   }
302
303   glFlush ();
304
305   /*
306    * Get the info log and set the pointer to the beginning of the output.
307    */
308   glGetInfoLogARB (vert, sizeof (output), &length, output);
309   p = output + info_length - 1;
310
311   for (i = 0; i < sizeof (attribs) / sizeof (*attribs); i++) {
312      GLuint j;
313      for (j = 0; j < attribs[i].size; j++) {
314         GLfloat value;
315         if (p == NULL) {
316            printf ("*** %s\n", "I/O error");
317            break;
318         }
319         if (strncmp (p, "true", 4) == 0)
320            value = 1.0f;
321         else if (strncmp (p, "false", 5) == 0)
322            value = 0.0f;
323         else if (sscanf (p, "%f", &value) != 1) {
324            printf ("*** %s\n", "I/O error");
325            p = NULL;
326            break;
327         }
328         if (fabs (value - attribs[i].data[j]) > EPSILON)
329            printf ("*** %s, is %f, should be %f\n", "Values are different", value, attribs[i].data[j]);
330         p = strchr (p, '\n');
331         if (p != NULL)
332            p++;
333      }
334      if (p == NULL)
335         break;
336   }
337
338   submit_method++;
339}
340
341int main (int argc, char *argv[])
342{
343   InitFramework (&argc, argv);
344   return 0;
345}
346
347