132001f49Smrg/**
232001f49Smrg * Random rendering, to check for crashes, hangs, etc.
332001f49Smrg *
432001f49Smrg * Brian Paul
532001f49Smrg * 21 June 2007
632001f49Smrg */
732001f49Smrg
832001f49Smrg
932001f49Smrg#include <assert.h>
1032001f49Smrg#include <stdio.h>
1132001f49Smrg#include <stdlib.h>
1232001f49Smrg#include <string.h>
1332001f49Smrg#include <math.h>
1432001f49Smrg#include <GL/glew.h>
1532001f49Smrg#include "glut_wrap.h"
1632001f49Smrg
1732001f49Smrgstatic int Win;
1832001f49Smrgstatic GLboolean Anim = GL_TRUE;
1932001f49Smrgstatic int Width = 200, Height = 200;
2032001f49Smrgstatic int DB = 0;
2132001f49Smrgstatic int MinVertexCount = 0, MaxVertexCount = 1000;
2232001f49Smrgstatic int Count = 0;
2332001f49Smrg
2432001f49Smrgstruct vertex
2532001f49Smrg{
2632001f49Smrg   int type;
2732001f49Smrg   float v[4];
2832001f49Smrg};
2932001f49Smrg
3032001f49Smrgstatic int BufferSize = 10000;
3132001f49Smrgstatic struct vertex *Vbuffer = NULL;
3232001f49Smrgstatic int Vcount, Vprim;
3332001f49Smrg
3432001f49Smrgenum {
3532001f49Smrg   BEGIN,
3632001f49Smrg   END,
3732001f49Smrg   VERTEX2,
3832001f49Smrg   VERTEX3,
3932001f49Smrg   VERTEX4,
4032001f49Smrg   COLOR3,
4132001f49Smrg   COLOR4,
4232001f49Smrg   TEX2,
4332001f49Smrg   TEX3,
4432001f49Smrg   TEX4,
4532001f49Smrg   SECCOLOR3,
4632001f49Smrg   NORMAL3
4732001f49Smrg};
4832001f49Smrg
4932001f49Smrg
5032001f49Smrg
5132001f49Smrg/**
5232001f49Smrg * This can be called from within gdb after a crash:
5332001f49Smrg * (gdb) call ReportState()
5432001f49Smrg */
5532001f49Smrgstatic void
5632001f49SmrgReportState(void)
5732001f49Smrg{
5832001f49Smrg   static const struct {
5932001f49Smrg      GLenum token;
6032001f49Smrg      char *str;
6132001f49Smrg      GLenum type;
6232001f49Smrg   } state [] = {
6332001f49Smrg      { GL_ALPHA_TEST, "GL_ALPHA_TEST", GL_INT },
6432001f49Smrg      { GL_BLEND, "GL_BLEND", GL_INT },
6532001f49Smrg      { GL_CLIP_PLANE0, "GL_CLIP_PLANE0", GL_INT },
6632001f49Smrg      { GL_DEPTH_TEST, "GL_DEPTH_TEST", GL_INT },
6732001f49Smrg      { GL_LIGHTING, "GL_LIGHTING", GL_INT },
6832001f49Smrg      { GL_LINE_WIDTH, "GL_LINE_WIDTH", GL_FLOAT },
6932001f49Smrg      { GL_POINT_SIZE, "GL_POINT_SIZE", GL_FLOAT },
7032001f49Smrg      { GL_SHADE_MODEL, "GL_SHADE_MODEL", GL_INT },
7132001f49Smrg      { GL_SCISSOR_TEST, "GL_SCISSOR_TEST", GL_INT },
7232001f49Smrg      { 0, NULL, 0 }
7332001f49Smrg   };
7432001f49Smrg
7532001f49Smrg   GLint i;
7632001f49Smrg
7732001f49Smrg   for (i = 0; state[i].token; i++) {
7832001f49Smrg      if (state[i].type == GL_INT) {
7932001f49Smrg         GLint v;
8032001f49Smrg         glGetIntegerv(state[i].token, &v);
8132001f49Smrg         printf("%s = %d\n", state[i].str, v);
8232001f49Smrg      }
8332001f49Smrg      else {
8432001f49Smrg         GLfloat v;
8532001f49Smrg         glGetFloatv(state[i].token, &v);
8632001f49Smrg         printf("%s = %f\n", state[i].str, v);
8732001f49Smrg      }
8832001f49Smrg   }
8932001f49Smrg}
9032001f49Smrg
9132001f49Smrgstatic void
9232001f49SmrgPrintVertex(const char *f, const struct vertex *v, int sz)
9332001f49Smrg{
9432001f49Smrg   int i;
9532001f49Smrg   printf("%s(", f);
9632001f49Smrg   for (i = 0; i < sz; i++) {
9732001f49Smrg      printf("%g%s", v->v[i], (i == sz-1) ? "" : ", ");
9832001f49Smrg   }
9932001f49Smrg   printf(");\n");
10032001f49Smrg}
10132001f49Smrg
10232001f49Smrg/**
10332001f49Smrg * This can be called from within gdb after a crash:
10432001f49Smrg * (gdb) call ReportState()
10532001f49Smrg */
10632001f49Smrgstatic void
10732001f49SmrgLastPrim(void)
10832001f49Smrg{
10932001f49Smrg   int i;
11032001f49Smrg   for (i = 0; i < Vcount; i++) {
11132001f49Smrg      switch (Vbuffer[i].type) {
11232001f49Smrg      case BEGIN:
11332001f49Smrg         printf("glBegin(%d);\n", (int) Vbuffer[i].v[0]);
11432001f49Smrg         break;
11532001f49Smrg      case END:
11632001f49Smrg         printf("glEnd();\n");
11732001f49Smrg         break;
11832001f49Smrg      case VERTEX2:
11932001f49Smrg         PrintVertex("glVertex2f", Vbuffer + i, 2);
12032001f49Smrg         break;
12132001f49Smrg      case VERTEX3:
12232001f49Smrg         PrintVertex("glVertex3f", Vbuffer + i, 3);
12332001f49Smrg         break;
12432001f49Smrg      case VERTEX4:
12532001f49Smrg         PrintVertex("glVertex4f", Vbuffer + i, 4);
12632001f49Smrg         break;
12732001f49Smrg      case COLOR3:
12832001f49Smrg         PrintVertex("glColor3f", Vbuffer + i, 3);
12932001f49Smrg         break;
13032001f49Smrg      case COLOR4:
13132001f49Smrg         PrintVertex("glColor4f", Vbuffer + i, 4);
13232001f49Smrg         break;
13332001f49Smrg      case TEX2:
13432001f49Smrg         PrintVertex("glTexCoord2f", Vbuffer + i, 2);
13532001f49Smrg         break;
13632001f49Smrg      case TEX3:
13732001f49Smrg         PrintVertex("glTexCoord3f", Vbuffer + i, 3);
13832001f49Smrg         break;
13932001f49Smrg      case TEX4:
14032001f49Smrg         PrintVertex("glTexCoord4f", Vbuffer + i, 4);
14132001f49Smrg         break;
14232001f49Smrg      case SECCOLOR3:
14332001f49Smrg         PrintVertex("glSecondaryColor3f", Vbuffer + i, 3);
14432001f49Smrg         break;
14532001f49Smrg      case NORMAL3:
14632001f49Smrg         PrintVertex("glNormal3f", Vbuffer + i, 3);
14732001f49Smrg         break;
14832001f49Smrg      default:
14932001f49Smrg         abort();
15032001f49Smrg      }
15132001f49Smrg   }
15232001f49Smrg}
15332001f49Smrg
15432001f49Smrg
15532001f49Smrgstatic int
15632001f49SmrgRandomInt(int max)
15732001f49Smrg{
15832001f49Smrg   if (max == 0)
15932001f49Smrg      return 0;
16032001f49Smrg   return rand() % max;
16132001f49Smrg}
16232001f49Smrg
16332001f49Smrgstatic float
16432001f49SmrgRandomFloat(float min, float max)
16532001f49Smrg{
16632001f49Smrg   int k = rand() % 10000;
16732001f49Smrg   float x = min + (max - min) * k / 10000.0;
16832001f49Smrg   return x;
16932001f49Smrg}
17032001f49Smrg
17132001f49Smrg/*
17232001f49Smrg * Return true if random number in [0,1] is <= percentile.
17332001f49Smrg */
17432001f49Smrgstatic GLboolean
17532001f49SmrgRandomChoice(float percentile)
17632001f49Smrg{
17732001f49Smrg   return RandomFloat(0.0, 1.0) <= percentile;
17832001f49Smrg}
17932001f49Smrg
18032001f49Smrgstatic void
18132001f49SmrgRandomStateChange(void)
18232001f49Smrg{
18332001f49Smrg   int k = RandomInt(19);
18432001f49Smrg   switch (k) {
18532001f49Smrg   case 0:
18632001f49Smrg      glEnable(GL_BLEND);
18732001f49Smrg      break;
18832001f49Smrg   case 1:
18932001f49Smrg      glDisable(GL_BLEND);
19032001f49Smrg      break;
19132001f49Smrg   case 2:
19232001f49Smrg      glEnable(GL_ALPHA_TEST);
19332001f49Smrg      break;
19432001f49Smrg   case 3:
19532001f49Smrg      glEnable(GL_ALPHA_TEST);
19632001f49Smrg      break;
19732001f49Smrg   case 4:
19832001f49Smrg      glEnable(GL_DEPTH_TEST);
19932001f49Smrg      break;
20032001f49Smrg   case 5:
20132001f49Smrg      glEnable(GL_DEPTH_TEST);
20232001f49Smrg      break;
20332001f49Smrg   case 6:
20432001f49Smrg      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
20532001f49Smrg      break;
20632001f49Smrg   case 7:
20732001f49Smrg      glPointSize(10.0);
20832001f49Smrg      break;
20932001f49Smrg   case 8:
21032001f49Smrg      glPointSize(1.0);
21132001f49Smrg      break;
21232001f49Smrg   case 9:
21332001f49Smrg      glLineWidth(10.0);
21432001f49Smrg      break;
21532001f49Smrg   case 10:
21632001f49Smrg      glLineWidth(1.0);
21732001f49Smrg      break;
21832001f49Smrg   case 11:
21932001f49Smrg      glEnable(GL_LIGHTING);
22032001f49Smrg      break;
22132001f49Smrg   case 12:
22232001f49Smrg      glDisable(GL_LIGHTING);
22332001f49Smrg      break;
22432001f49Smrg   case 13:
22532001f49Smrg      glEnable(GL_SCISSOR_TEST);
22632001f49Smrg      break;
22732001f49Smrg   case 14:
22832001f49Smrg      glDisable(GL_SCISSOR_TEST);
22932001f49Smrg      break;
23032001f49Smrg   case 15:
23132001f49Smrg      glEnable(GL_CLIP_PLANE0);
23232001f49Smrg      break;
23332001f49Smrg   case 16:
23432001f49Smrg      glDisable(GL_CLIP_PLANE0);
23532001f49Smrg      break;
23632001f49Smrg   case 17:
23732001f49Smrg      glShadeModel(GL_FLAT);
23832001f49Smrg      break;
23932001f49Smrg   case 18:
24032001f49Smrg      glShadeModel(GL_SMOOTH);
24132001f49Smrg      break;
24232001f49Smrg   }
24332001f49Smrg}
24432001f49Smrg
24532001f49Smrg
24632001f49Smrgstatic void
24732001f49SmrgRandomPrimitive(void)
24832001f49Smrg{
24932001f49Smrg   int i;
25032001f49Smrg   int len = MinVertexCount + RandomInt(MaxVertexCount - MinVertexCount);
25132001f49Smrg
25232001f49Smrg   Vprim = RandomInt(10);
25332001f49Smrg
25432001f49Smrg   glBegin(Vprim);
25532001f49Smrg   Vbuffer[Vcount].type = BEGIN;
25632001f49Smrg   Vbuffer[Vcount].v[0] = Vprim;
25732001f49Smrg   Vcount++;
25832001f49Smrg
25932001f49Smrg   for (i = 0; i < len; i++) {
26032001f49Smrg      int k = RandomInt(9);
26132001f49Smrg      Vbuffer[Vcount].v[0] = RandomFloat(-3, 3);
26232001f49Smrg      Vbuffer[Vcount].v[1] = RandomFloat(-3, 3);
26332001f49Smrg      Vbuffer[Vcount].v[2] = RandomFloat(-3, 3);
26432001f49Smrg      Vbuffer[Vcount].v[3] = RandomFloat(-3, 3);
26532001f49Smrg      switch (k) {
26632001f49Smrg      case 0:
26732001f49Smrg         glVertex2fv(Vbuffer[Vcount].v);
26832001f49Smrg         Vbuffer[Vcount].type = VERTEX2;
26932001f49Smrg         break;
27032001f49Smrg      case 1:
27132001f49Smrg         glVertex3fv(Vbuffer[Vcount].v);
27232001f49Smrg         Vbuffer[Vcount].type = VERTEX3;
27332001f49Smrg         break;
27432001f49Smrg      case 2:
27532001f49Smrg         glVertex4fv(Vbuffer[Vcount].v);
27632001f49Smrg         Vbuffer[Vcount].type = VERTEX4;
27732001f49Smrg         break;
27832001f49Smrg      case 3:
27932001f49Smrg         glColor3fv(Vbuffer[Vcount].v);
28032001f49Smrg         Vbuffer[Vcount].type = COLOR3;
28132001f49Smrg         break;
28232001f49Smrg      case 4:
28332001f49Smrg         glColor4fv(Vbuffer[Vcount].v);
28432001f49Smrg         Vbuffer[Vcount].type = COLOR4;
28532001f49Smrg         break;
28632001f49Smrg      case 5:
28732001f49Smrg         glTexCoord2fv(Vbuffer[Vcount].v);
28832001f49Smrg         Vbuffer[Vcount].type = TEX2;
28932001f49Smrg         break;
29032001f49Smrg      case 6:
29132001f49Smrg         glTexCoord3fv(Vbuffer[Vcount].v);
29232001f49Smrg         Vbuffer[Vcount].type = TEX3;
29332001f49Smrg         break;
29432001f49Smrg      case 7:
29532001f49Smrg         glTexCoord4fv(Vbuffer[Vcount].v);
29632001f49Smrg         Vbuffer[Vcount].type = TEX4;
29732001f49Smrg         break;
29832001f49Smrg      case 8:
29932001f49Smrg         glSecondaryColor3fv(Vbuffer[Vcount].v);
30032001f49Smrg         Vbuffer[Vcount].type = SECCOLOR3;
30132001f49Smrg         break;
30232001f49Smrg      case 9:
30332001f49Smrg         glNormal3fv(Vbuffer[Vcount].v);
30432001f49Smrg         Vbuffer[Vcount].type = NORMAL3;
30532001f49Smrg         break;
30632001f49Smrg      default:
30732001f49Smrg         abort();
30832001f49Smrg      }
30932001f49Smrg      Vcount++;
31032001f49Smrg
31132001f49Smrg      if (Vcount >= BufferSize - 2) {
31232001f49Smrg         /* reset */
31332001f49Smrg         Vcount = 0;
31432001f49Smrg      }
31532001f49Smrg   }
31632001f49Smrg
31732001f49Smrg   Vbuffer[Vcount++].type = END;
31832001f49Smrg
31932001f49Smrg   glEnd();
32032001f49Smrg}
32132001f49Smrg
32232001f49Smrg
32332001f49Smrgstatic void
32432001f49SmrgRandomDraw(void)
32532001f49Smrg{
32632001f49Smrg   int i;
32732001f49Smrg   GLboolean dlist = RandomChoice(0.1);
32832001f49Smrg   if (dlist)
32932001f49Smrg      glNewList(1, GL_COMPILE);
33032001f49Smrg   for (i = 0; i < 3; i++) {
33132001f49Smrg      RandomStateChange();
33232001f49Smrg   }
33332001f49Smrg   RandomPrimitive();
33432001f49Smrg
33532001f49Smrg   if (dlist) {
33632001f49Smrg      glEndList();
33732001f49Smrg      glCallList(1);
33832001f49Smrg   }
33932001f49Smrg}
34032001f49Smrg
34132001f49Smrg
34232001f49Smrgstatic void
34332001f49SmrgIdle(void)
34432001f49Smrg{
34532001f49Smrg   glutPostRedisplay();
34632001f49Smrg}
34732001f49Smrg
34832001f49Smrg
34932001f49Smrgstatic void
35032001f49SmrgDraw(void)
35132001f49Smrg{
35232001f49Smrg#if 1
35332001f49Smrg   RandomDraw();
35432001f49Smrg   Count++;
35532001f49Smrg#else
35632001f49Smrg   /* cut & paste temp code here */
35732001f49Smrg#endif
35832001f49Smrg
35932001f49Smrg   assert(glGetError() == 0);
36032001f49Smrg
36132001f49Smrg   if (DB)
36232001f49Smrg      glutSwapBuffers();
36332001f49Smrg   else
36432001f49Smrg      glFinish();
36532001f49Smrg}
36632001f49Smrg
36732001f49Smrg
36832001f49Smrgstatic void
36932001f49SmrgReshape(int width, int height)
37032001f49Smrg{
37132001f49Smrg   Width = width;
37232001f49Smrg   Height = height;
37332001f49Smrg   glViewport(0, 0, width, height);
37432001f49Smrg   glScissor(20, 20, Width-40, Height-40);
37532001f49Smrg   glMatrixMode(GL_PROJECTION);
37632001f49Smrg   glLoadIdentity();
37732001f49Smrg   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
37832001f49Smrg   glMatrixMode(GL_MODELVIEW);
37932001f49Smrg   glLoadIdentity();
38032001f49Smrg   glTranslatef(0.0, 0.0, -15.0);
38132001f49Smrg}
38232001f49Smrg
38332001f49Smrg
38432001f49Smrgstatic void
38532001f49SmrgKey(unsigned char key, int x, int y)
38632001f49Smrg{
38732001f49Smrg   (void) x;
38832001f49Smrg   (void) y;
38932001f49Smrg   switch (key) {
39032001f49Smrg      case 27:
39132001f49Smrg         glutDestroyWindow(Win);
39232001f49Smrg         exit(0);
39332001f49Smrg         break;
39432001f49Smrg   }
39532001f49Smrg   glutPostRedisplay();
39632001f49Smrg}
39732001f49Smrg
39832001f49Smrg
39932001f49Smrgstatic void
40032001f49SmrgInit(void)
40132001f49Smrg{
40232001f49Smrg   static const GLdouble plane[4] = {1, 1, 0, 0};
40332001f49Smrg   glDrawBuffer(GL_FRONT);
40432001f49Smrg   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
40532001f49Smrg   glEnable(GL_LIGHT0);
40632001f49Smrg   glClipPlane(GL_CLIP_PLANE0, plane);
40732001f49Smrg
40832001f49Smrg   Vbuffer = (struct vertex *)
40932001f49Smrg      malloc(BufferSize * sizeof(struct vertex));
41032001f49Smrg
41132001f49Smrg   /* silence warnings */
41232001f49Smrg   (void) ReportState;
41332001f49Smrg   (void) LastPrim;
41432001f49Smrg}
41532001f49Smrg
41632001f49Smrg
41732001f49Smrgstatic void
41832001f49SmrgParseArgs(int argc, char *argv[])
41932001f49Smrg{
42032001f49Smrg   int i;
42132001f49Smrg   for (i = 1; i < argc; i++) {
42232001f49Smrg      if (strcmp(argv[i], "-s") == 0) {
42332001f49Smrg         int j = atoi(argv[i + 1]);
42432001f49Smrg         printf("Random seed value: %d\n", j);
42532001f49Smrg         srand(j);
42632001f49Smrg         i++;
42732001f49Smrg      }
42832001f49Smrg      else if (strcmp(argv[i], "-a") == 0) {
42932001f49Smrg         i++;
43032001f49Smrg         MinVertexCount = atoi(argv[i]);
43132001f49Smrg      }
43232001f49Smrg      else if (strcmp(argv[i], "-b") == 0) {
43332001f49Smrg         i++;
43432001f49Smrg         MaxVertexCount = atoi(argv[i]);
43532001f49Smrg      }
43632001f49Smrg   }
43732001f49Smrg}
43832001f49Smrg
43932001f49Smrg
44032001f49Smrgint
44132001f49Smrgmain(int argc, char *argv[])
44232001f49Smrg{
44332001f49Smrg   glutInit(&argc, argv);
44432001f49Smrg   glutInitWindowPosition(0, 0);
44532001f49Smrg   glutInitWindowSize(Width, Height);
44632001f49Smrg   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
44732001f49Smrg   Win = glutCreateWindow(argv[0]);
44832001f49Smrg   glewInit();
44932001f49Smrg   ParseArgs(argc, argv);
45032001f49Smrg   glutReshapeFunc(Reshape);
45132001f49Smrg   glutKeyboardFunc(Key);
45232001f49Smrg   glutDisplayFunc(Draw);
45332001f49Smrg   if (Anim)
45432001f49Smrg      glutIdleFunc(Idle);
45532001f49Smrg   Init();
45632001f49Smrg   glutMainLoop();
45732001f49Smrg   return 0;
45832001f49Smrg}
459