459 lines
8.8 KiB
C
459 lines
8.8 KiB
C
/**
|
|
* Random rendering, to check for crashes, hangs, etc.
|
|
*
|
|
* Brian Paul
|
|
* 21 June 2007
|
|
*/
|
|
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <GL/glew.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++) {
|
|
int k = RandomInt(9);
|
|
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);
|
|
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]);
|
|
glewInit();
|
|
ParseArgs(argc, argv);
|
|
glutReshapeFunc(Reshape);
|
|
glutKeyboardFunc(Key);
|
|
glutDisplayFunc(Draw);
|
|
if (Anim)
|
|
glutIdleFunc(Idle);
|
|
Init();
|
|
glutMainLoop();
|
|
return 0;
|
|
}
|