1/**
2 * Random rendering, to check for crashes, hangs, etc.
3 *
4 * Brian Paul
5 * 21 June 2007
6 */
7
8
9#include <assert.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <math.h>
14#include <GL/glew.h>
15#include "glut_wrap.h"
16
17static int Win;
18static GLboolean Anim = GL_TRUE;
19static int Width = 200, Height = 200;
20static int DB = 0;
21static int MinVertexCount = 0, MaxVertexCount = 1000;
22static int Count = 0;
23
24struct vertex
25{
26   int type;
27   float v[4];
28};
29
30static int BufferSize = 10000;
31static struct vertex *Vbuffer = NULL;
32static int Vcount, Vprim;
33
34enum {
35   BEGIN,
36   END,
37   VERTEX2,
38   VERTEX3,
39   VERTEX4,
40   COLOR3,
41   COLOR4,
42   TEX2,
43   TEX3,
44   TEX4,
45   SECCOLOR3,
46   NORMAL3
47};
48
49
50
51/**
52 * This can be called from within gdb after a crash:
53 * (gdb) call ReportState()
54 */
55static void
56ReportState(void)
57{
58   static const struct {
59      GLenum token;
60      char *str;
61      GLenum type;
62   } state [] = {
63      { GL_ALPHA_TEST, "GL_ALPHA_TEST", GL_INT },
64      { GL_BLEND, "GL_BLEND", GL_INT },
65      { GL_CLIP_PLANE0, "GL_CLIP_PLANE0", GL_INT },
66      { GL_DEPTH_TEST, "GL_DEPTH_TEST", GL_INT },
67      { GL_LIGHTING, "GL_LIGHTING", GL_INT },
68      { GL_LINE_WIDTH, "GL_LINE_WIDTH", GL_FLOAT },
69      { GL_POINT_SIZE, "GL_POINT_SIZE", GL_FLOAT },
70      { GL_SHADE_MODEL, "GL_SHADE_MODEL", GL_INT },
71      { GL_SCISSOR_TEST, "GL_SCISSOR_TEST", GL_INT },
72      { 0, NULL, 0 }
73   };
74
75   GLint i;
76
77   for (i = 0; state[i].token; i++) {
78      if (state[i].type == GL_INT) {
79         GLint v;
80         glGetIntegerv(state[i].token, &v);
81         printf("%s = %d\n", state[i].str, v);
82      }
83      else {
84         GLfloat v;
85         glGetFloatv(state[i].token, &v);
86         printf("%s = %f\n", state[i].str, v);
87      }
88   }
89}
90
91static void
92PrintVertex(const char *f, const struct vertex *v, int sz)
93{
94   int i;
95   printf("%s(", f);
96   for (i = 0; i < sz; i++) {
97      printf("%g%s", v->v[i], (i == sz-1) ? "" : ", ");
98   }
99   printf(");\n");
100}
101
102/**
103 * This can be called from within gdb after a crash:
104 * (gdb) call ReportState()
105 */
106static void
107LastPrim(void)
108{
109   int i;
110   for (i = 0; i < Vcount; i++) {
111      switch (Vbuffer[i].type) {
112      case BEGIN:
113         printf("glBegin(%d);\n", (int) Vbuffer[i].v[0]);
114         break;
115      case END:
116         printf("glEnd();\n");
117         break;
118      case VERTEX2:
119         PrintVertex("glVertex2f", Vbuffer + i, 2);
120         break;
121      case VERTEX3:
122         PrintVertex("glVertex3f", Vbuffer + i, 3);
123         break;
124      case VERTEX4:
125         PrintVertex("glVertex4f", Vbuffer + i, 4);
126         break;
127      case COLOR3:
128         PrintVertex("glColor3f", Vbuffer + i, 3);
129         break;
130      case COLOR4:
131         PrintVertex("glColor4f", Vbuffer + i, 4);
132         break;
133      case TEX2:
134         PrintVertex("glTexCoord2f", Vbuffer + i, 2);
135         break;
136      case TEX3:
137         PrintVertex("glTexCoord3f", Vbuffer + i, 3);
138         break;
139      case TEX4:
140         PrintVertex("glTexCoord4f", Vbuffer + i, 4);
141         break;
142      case SECCOLOR3:
143         PrintVertex("glSecondaryColor3f", Vbuffer + i, 3);
144         break;
145      case NORMAL3:
146         PrintVertex("glNormal3f", Vbuffer + i, 3);
147         break;
148      default:
149         abort();
150      }
151   }
152}
153
154
155static int
156RandomInt(int max)
157{
158   if (max == 0)
159      return 0;
160   return rand() % max;
161}
162
163static float
164RandomFloat(float min, float max)
165{
166   int k = rand() % 10000;
167   float x = min + (max - min) * k / 10000.0;
168   return x;
169}
170
171/*
172 * Return true if random number in [0,1] is <= percentile.
173 */
174static GLboolean
175RandomChoice(float percentile)
176{
177   return RandomFloat(0.0, 1.0) <= percentile;
178}
179
180static void
181RandomStateChange(void)
182{
183   int k = RandomInt(19);
184   switch (k) {
185   case 0:
186      glEnable(GL_BLEND);
187      break;
188   case 1:
189      glDisable(GL_BLEND);
190      break;
191   case 2:
192      glEnable(GL_ALPHA_TEST);
193      break;
194   case 3:
195      glEnable(GL_ALPHA_TEST);
196      break;
197   case 4:
198      glEnable(GL_DEPTH_TEST);
199      break;
200   case 5:
201      glEnable(GL_DEPTH_TEST);
202      break;
203   case 6:
204      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
205      break;
206   case 7:
207      glPointSize(10.0);
208      break;
209   case 8:
210      glPointSize(1.0);
211      break;
212   case 9:
213      glLineWidth(10.0);
214      break;
215   case 10:
216      glLineWidth(1.0);
217      break;
218   case 11:
219      glEnable(GL_LIGHTING);
220      break;
221   case 12:
222      glDisable(GL_LIGHTING);
223      break;
224   case 13:
225      glEnable(GL_SCISSOR_TEST);
226      break;
227   case 14:
228      glDisable(GL_SCISSOR_TEST);
229      break;
230   case 15:
231      glEnable(GL_CLIP_PLANE0);
232      break;
233   case 16:
234      glDisable(GL_CLIP_PLANE0);
235      break;
236   case 17:
237      glShadeModel(GL_FLAT);
238      break;
239   case 18:
240      glShadeModel(GL_SMOOTH);
241      break;
242   }
243}
244
245
246static void
247RandomPrimitive(void)
248{
249   int i;
250   int len = MinVertexCount + RandomInt(MaxVertexCount - MinVertexCount);
251
252   Vprim = RandomInt(10);
253
254   glBegin(Vprim);
255   Vbuffer[Vcount].type = BEGIN;
256   Vbuffer[Vcount].v[0] = Vprim;
257   Vcount++;
258
259   for (i = 0; i < len; i++) {
260      int k = RandomInt(9);
261      Vbuffer[Vcount].v[0] = RandomFloat(-3, 3);
262      Vbuffer[Vcount].v[1] = RandomFloat(-3, 3);
263      Vbuffer[Vcount].v[2] = RandomFloat(-3, 3);
264      Vbuffer[Vcount].v[3] = RandomFloat(-3, 3);
265      switch (k) {
266      case 0:
267         glVertex2fv(Vbuffer[Vcount].v);
268         Vbuffer[Vcount].type = VERTEX2;
269         break;
270      case 1:
271         glVertex3fv(Vbuffer[Vcount].v);
272         Vbuffer[Vcount].type = VERTEX3;
273         break;
274      case 2:
275         glVertex4fv(Vbuffer[Vcount].v);
276         Vbuffer[Vcount].type = VERTEX4;
277         break;
278      case 3:
279         glColor3fv(Vbuffer[Vcount].v);
280         Vbuffer[Vcount].type = COLOR3;
281         break;
282      case 4:
283         glColor4fv(Vbuffer[Vcount].v);
284         Vbuffer[Vcount].type = COLOR4;
285         break;
286      case 5:
287         glTexCoord2fv(Vbuffer[Vcount].v);
288         Vbuffer[Vcount].type = TEX2;
289         break;
290      case 6:
291         glTexCoord3fv(Vbuffer[Vcount].v);
292         Vbuffer[Vcount].type = TEX3;
293         break;
294      case 7:
295         glTexCoord4fv(Vbuffer[Vcount].v);
296         Vbuffer[Vcount].type = TEX4;
297         break;
298      case 8:
299         glSecondaryColor3fv(Vbuffer[Vcount].v);
300         Vbuffer[Vcount].type = SECCOLOR3;
301         break;
302      case 9:
303         glNormal3fv(Vbuffer[Vcount].v);
304         Vbuffer[Vcount].type = NORMAL3;
305         break;
306      default:
307         abort();
308      }
309      Vcount++;
310
311      if (Vcount >= BufferSize - 2) {
312         /* reset */
313         Vcount = 0;
314      }
315   }
316
317   Vbuffer[Vcount++].type = END;
318
319   glEnd();
320}
321
322
323static void
324RandomDraw(void)
325{
326   int i;
327   GLboolean dlist = RandomChoice(0.1);
328   if (dlist)
329      glNewList(1, GL_COMPILE);
330   for (i = 0; i < 3; i++) {
331      RandomStateChange();
332   }
333   RandomPrimitive();
334
335   if (dlist) {
336      glEndList();
337      glCallList(1);
338   }
339}
340
341
342static void
343Idle(void)
344{
345   glutPostRedisplay();
346}
347
348
349static void
350Draw(void)
351{
352#if 1
353   RandomDraw();
354   Count++;
355#else
356   /* cut & paste temp code here */
357#endif
358
359   assert(glGetError() == 0);
360
361   if (DB)
362      glutSwapBuffers();
363   else
364      glFinish();
365}
366
367
368static void
369Reshape(int width, int height)
370{
371   Width = width;
372   Height = height;
373   glViewport(0, 0, width, height);
374   glScissor(20, 20, Width-40, Height-40);
375   glMatrixMode(GL_PROJECTION);
376   glLoadIdentity();
377   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
378   glMatrixMode(GL_MODELVIEW);
379   glLoadIdentity();
380   glTranslatef(0.0, 0.0, -15.0);
381}
382
383
384static void
385Key(unsigned char key, int x, int y)
386{
387   (void) x;
388   (void) y;
389   switch (key) {
390      case 27:
391         glutDestroyWindow(Win);
392         exit(0);
393         break;
394   }
395   glutPostRedisplay();
396}
397
398
399static void
400Init(void)
401{
402   static const GLdouble plane[4] = {1, 1, 0, 0};
403   glDrawBuffer(GL_FRONT);
404   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
405   glEnable(GL_LIGHT0);
406   glClipPlane(GL_CLIP_PLANE0, plane);
407
408   Vbuffer = (struct vertex *)
409      malloc(BufferSize * sizeof(struct vertex));
410
411   /* silence warnings */
412   (void) ReportState;
413   (void) LastPrim;
414}
415
416
417static void
418ParseArgs(int argc, char *argv[])
419{
420   int i;
421   for (i = 1; i < argc; i++) {
422      if (strcmp(argv[i], "-s") == 0) {
423         int j = atoi(argv[i + 1]);
424         printf("Random seed value: %d\n", j);
425         srand(j);
426         i++;
427      }
428      else if (strcmp(argv[i], "-a") == 0) {
429         i++;
430         MinVertexCount = atoi(argv[i]);
431      }
432      else if (strcmp(argv[i], "-b") == 0) {
433         i++;
434         MaxVertexCount = atoi(argv[i]);
435      }
436   }
437}
438
439
440int
441main(int argc, char *argv[])
442{
443   glutInit(&argc, argv);
444   glutInitWindowPosition(0, 0);
445   glutInitWindowSize(Width, Height);
446   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
447   Win = glutCreateWindow(argv[0]);
448   glewInit();
449   ParseArgs(argc, argv);
450   glutReshapeFunc(Reshape);
451   glutKeyboardFunc(Key);
452   glutDisplayFunc(Draw);
453   if (Anim)
454      glutIdleFunc(Idle);
455   Init();
456   glutMainLoop();
457   return 0;
458}
459