--- /dev/null
+/**
+ * Random rendering, to check for crashes, hangs, etc.
+ *
+ * Brian Paul
+ * 21 June 2007
+ */
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <GL/glut.h>
+
+static int Win;
+static GLboolean Anim = GL_TRUE;
+static int Width = 200, Height = 200;
+static int DB = 0;
+static int MinVertexCount = 0, MaxVertexCount = 1000;
+static int Count = 0;
+
+struct vertex
+{
+ int type;
+ float v[4];
+};
+
+static int BufferSize = 10000;
+static struct vertex *Vbuffer = NULL;
+static int Vcount, Vprim;
+
+enum {
+ BEGIN,
+ END,
+ VERTEX2,
+ VERTEX3,
+ VERTEX4,
+ COLOR3,
+ COLOR4,
+ TEX2,
+ TEX3,
+ TEX4,
+ SECCOLOR3,
+ NORMAL3
+};
+
+
+
+/**
+ * This can be called from within gdb after a crash:
+ * (gdb) call ReportState()
+ */
+static void
+ReportState(void)
+{
+ static const struct {
+ GLenum token;
+ char *str;
+ GLenum type;
+ } state [] = {
+ { GL_ALPHA_TEST, "GL_ALPHA_TEST", GL_INT },
+ { GL_BLEND, "GL_BLEND", GL_INT },
+ { GL_CLIP_PLANE0, "GL_CLIP_PLANE0", GL_INT },
+ { GL_DEPTH_TEST, "GL_DEPTH_TEST", GL_INT },
+ { GL_LIGHTING, "GL_LIGHTING", GL_INT },
+ { GL_LINE_WIDTH, "GL_LINE_WIDTH", GL_FLOAT },
+ { GL_POINT_SIZE, "GL_POINT_SIZE", GL_FLOAT },
+ { GL_SHADE_MODEL, "GL_SHADE_MODEL", GL_INT },
+ { GL_SCISSOR_TEST, "GL_SCISSOR_TEST", GL_INT },
+ { 0, NULL, 0 }
+ };
+
+ GLint i;
+
+ for (i = 0; state[i].token; i++) {
+ if (state[i].type == GL_INT) {
+ GLint v;
+ glGetIntegerv(state[i].token, &v);
+ printf("%s = %d\n", state[i].str, v);
+ }
+ else {
+ GLfloat v;
+ glGetFloatv(state[i].token, &v);
+ printf("%s = %f\n", state[i].str, v);
+ }
+ }
+}
+
+static void
+PrintVertex(const char *f, const struct vertex *v, int sz)
+{
+ int i;
+ printf("%s(", f);
+ for (i = 0; i < sz; i++) {
+ printf("%g%s", v->v[i], (i == sz-1) ? "" : ", ");
+ }
+ printf(");\n");
+}
+
+/**
+ * This can be called from within gdb after a crash:
+ * (gdb) call ReportState()
+ */
+static void
+LastPrim(void)
+{
+ int i;
+ for (i = 0; i < Vcount; i++) {
+ switch (Vbuffer[i].type) {
+ case BEGIN:
+ printf("glBegin(%d);\n", (int) Vbuffer[i].v[0]);
+ break;
+ case END:
+ printf("glEnd();\n");
+ break;
+ case VERTEX2:
+ PrintVertex("glVertex2f", Vbuffer + i, 2);
+ break;
+ case VERTEX3:
+ PrintVertex("glVertex3f", Vbuffer + i, 3);
+ break;
+ case VERTEX4:
+ PrintVertex("glVertex4f", Vbuffer + i, 4);
+ break;
+ case COLOR3:
+ PrintVertex("glColor3f", Vbuffer + i, 3);
+ break;
+ case COLOR4:
+ PrintVertex("glColor4f", Vbuffer + i, 4);
+ break;
+ case TEX2:
+ PrintVertex("glTexCoord2f", Vbuffer + i, 2);
+ break;
+ case TEX3:
+ PrintVertex("glTexCoord3f", Vbuffer + i, 3);
+ break;
+ case TEX4:
+ PrintVertex("glTexCoord4f", Vbuffer + i, 4);
+ break;
+ case SECCOLOR3:
+ PrintVertex("glSecondaryColor3f", Vbuffer + i, 3);
+ break;
+ case NORMAL3:
+ PrintVertex("glNormal3f", Vbuffer + i, 3);
+ break;
+ default:
+ abort();
+ }
+ }
+}
+
+
+static int
+RandomInt(int max)
+{
+ if (max == 0)
+ return 0;
+ return rand() % max;
+}
+
+static float
+RandomFloat(float min, float max)
+{
+ int k = rand() % 10000;
+ float x = min + (max - min) * k / 10000.0;
+ return x;
+}
+
+/*
+ * Return true if random number in [0,1] is <= percentile.
+ */
+static GLboolean
+RandomChoice(float percentile)
+{
+ return RandomFloat(0.0, 1.0) <= percentile;
+}
+
+static void
+RandomStateChange(void)
+{
+ int k = RandomInt(19);
+ switch (k) {
+ case 0:
+ glEnable(GL_BLEND);
+ break;
+ case 1:
+ glDisable(GL_BLEND);
+ break;
+ case 2:
+ glEnable(GL_ALPHA_TEST);
+ break;
+ case 3:
+ glEnable(GL_ALPHA_TEST);
+ break;
+ case 4:
+ glEnable(GL_DEPTH_TEST);
+ break;
+ case 5:
+ glEnable(GL_DEPTH_TEST);
+ break;
+ case 6:
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ break;
+ case 7:
+ glPointSize(10.0);
+ break;
+ case 8:
+ glPointSize(1.0);
+ break;
+ case 9:
+ glLineWidth(10.0);
+ break;
+ case 10:
+ glLineWidth(1.0);
+ break;
+ case 11:
+ glEnable(GL_LIGHTING);
+ break;
+ case 12:
+ glDisable(GL_LIGHTING);
+ break;
+ case 13:
+ glEnable(GL_SCISSOR_TEST);
+ break;
+ case 14:
+ glDisable(GL_SCISSOR_TEST);
+ break;
+ case 15:
+ glEnable(GL_CLIP_PLANE0);
+ break;
+ case 16:
+ glDisable(GL_CLIP_PLANE0);
+ break;
+ case 17:
+ glShadeModel(GL_FLAT);
+ break;
+ case 18:
+ glShadeModel(GL_SMOOTH);
+ break;
+ }
+}
+
+
+static void
+RandomPrimitive(void)
+{
+ int i;
+ int len = MinVertexCount + RandomInt(MaxVertexCount - MinVertexCount);
+
+ Vprim = RandomInt(10);
+
+ glBegin(Vprim);
+ Vbuffer[Vcount].type = BEGIN;
+ Vbuffer[Vcount].v[0] = Vprim;
+ Vcount++;
+
+ for (i = 0; i < len; i++) {
+ Vbuffer[Vcount].v[0] = RandomFloat(-3, 3);
+ Vbuffer[Vcount].v[1] = RandomFloat(-3, 3);
+ Vbuffer[Vcount].v[2] = RandomFloat(-3, 3);
+ Vbuffer[Vcount].v[3] = RandomFloat(-3, 3);
+ int k = RandomInt(9);
+ switch (k) {
+ case 0:
+ glVertex2fv(Vbuffer[Vcount].v);
+ Vbuffer[Vcount].type = VERTEX2;
+ break;
+ case 1:
+ glVertex3fv(Vbuffer[Vcount].v);
+ Vbuffer[Vcount].type = VERTEX3;
+ break;
+ case 2:
+ glVertex4fv(Vbuffer[Vcount].v);
+ Vbuffer[Vcount].type = VERTEX4;
+ break;
+ case 3:
+ glColor3fv(Vbuffer[Vcount].v);
+ Vbuffer[Vcount].type = COLOR3;
+ break;
+ case 4:
+ glColor4fv(Vbuffer[Vcount].v);
+ Vbuffer[Vcount].type = COLOR4;
+ break;
+ case 5:
+ glTexCoord2fv(Vbuffer[Vcount].v);
+ Vbuffer[Vcount].type = TEX2;
+ break;
+ case 6:
+ glTexCoord3fv(Vbuffer[Vcount].v);
+ Vbuffer[Vcount].type = TEX3;
+ break;
+ case 7:
+ glTexCoord4fv(Vbuffer[Vcount].v);
+ Vbuffer[Vcount].type = TEX4;
+ break;
+ case 8:
+ glSecondaryColor3fv(Vbuffer[Vcount].v);
+ Vbuffer[Vcount].type = SECCOLOR3;
+ break;
+ case 9:
+ glNormal3fv(Vbuffer[Vcount].v);
+ Vbuffer[Vcount].type = NORMAL3;
+ break;
+ default:
+ abort();
+ }
+ Vcount++;
+
+ if (Vcount >= BufferSize - 2) {
+ /* reset */
+ Vcount = 0;
+ }
+ }
+
+ Vbuffer[Vcount++].type = END;
+
+ glEnd();
+}
+
+
+static void
+RandomDraw(void)
+{
+ int i;
+ GLboolean dlist = RandomChoice(0.1);
+ if (dlist)
+ glNewList(1, GL_COMPILE);
+ for (i = 0; i < 3; i++) {
+ RandomStateChange();
+ }
+ RandomPrimitive();
+
+ if (dlist) {
+ glEndList();
+ glCallList(1);
+ }
+}
+
+
+static void
+Idle(void)
+{
+ glutPostRedisplay();
+}
+
+
+static void
+Draw(void)
+{
+#if 1
+ RandomDraw();
+ Count++;
+#else
+ /* cut & paste temp code here */
+#endif
+
+ assert(glGetError() == 0);
+
+ if (DB)
+ glutSwapBuffers();
+ else
+ glFinish();
+}
+
+
+static void
+Reshape(int width, int height)
+{
+ Width = width;
+ Height = height;
+ glViewport(0, 0, width, height);
+ glScissor(20, 20, Width-40, Height-40);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -15.0);
+}
+
+
+static void
+Key(unsigned char key, int x, int y)
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ glutDestroyWindow(Win);
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void
+Init(void)
+{
+ static const GLdouble plane[4] = {1, 1, 0, 0};
+ glDrawBuffer(GL_FRONT);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_LIGHT0);
+ glClipPlane(GL_CLIP_PLANE0, plane);
+
+ Vbuffer = (struct vertex *)
+ malloc(BufferSize * sizeof(struct vertex));
+
+ /* silence warnings */
+ (void) ReportState;
+ (void) LastPrim;
+}
+
+
+static void
+ParseArgs(int argc, char *argv[])
+{
+ int i;
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-s") == 0) {
+ int j = atoi(argv[i + 1]);
+ printf("Random seed value: %d\n", j);
+ srand(j);
+ i++;
+ }
+ else if (strcmp(argv[i], "-a") == 0) {
+ i++;
+ MinVertexCount = atoi(argv[i]);
+ }
+ else if (strcmp(argv[i], "-b") == 0) {
+ i++;
+ MaxVertexCount = atoi(argv[i]);
+ }
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowPosition(0, 0);
+ glutInitWindowSize(Width, Height);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ Win = glutCreateWindow(argv[0]);
+ ParseArgs(argc, argv);
+ glutReshapeFunc(Reshape);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Draw);
+ if (Anim)
+ glutIdleFunc(Idle);
+ Init();
+ glutMainLoop();
+ return 0;
+}