|
|
@@ -0,0 +1,457 @@ |
|
|
|
/** |
|
|
|
* 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; |
|
|
|
} |