mesa/progs/tests/random.c

458 lines
8.8 KiB
C

/**
* 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;
}