1/** 2 * Random rendering, to check for crashes, hangs, etc. 3 * 4 * Brian Paul 5 * 21 June 2007 6 */ 7 8 9#include <assert.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <math.h> 14#include <GL/glew.h> 15#include "glut_wrap.h" 16 17static int Win; 18static GLboolean Anim = GL_TRUE; 19static int Width = 200, Height = 200; 20static int DB = 0; 21static int MinVertexCount = 0, MaxVertexCount = 1000; 22static int Count = 0; 23 24struct vertex 25{ 26 int type; 27 float v[4]; 28}; 29 30static int BufferSize = 10000; 31static struct vertex *Vbuffer = NULL; 32static int Vcount, Vprim; 33 34enum { 35 BEGIN, 36 END, 37 VERTEX2, 38 VERTEX3, 39 VERTEX4, 40 COLOR3, 41 COLOR4, 42 TEX2, 43 TEX3, 44 TEX4, 45 SECCOLOR3, 46 NORMAL3 47}; 48 49 50 51/** 52 * This can be called from within gdb after a crash: 53 * (gdb) call ReportState() 54 */ 55static void 56ReportState(void) 57{ 58 static const struct { 59 GLenum token; 60 char *str; 61 GLenum type; 62 } state [] = { 63 { GL_ALPHA_TEST, "GL_ALPHA_TEST", GL_INT }, 64 { GL_BLEND, "GL_BLEND", GL_INT }, 65 { GL_CLIP_PLANE0, "GL_CLIP_PLANE0", GL_INT }, 66 { GL_DEPTH_TEST, "GL_DEPTH_TEST", GL_INT }, 67 { GL_LIGHTING, "GL_LIGHTING", GL_INT }, 68 { GL_LINE_WIDTH, "GL_LINE_WIDTH", GL_FLOAT }, 69 { GL_POINT_SIZE, "GL_POINT_SIZE", GL_FLOAT }, 70 { GL_SHADE_MODEL, "GL_SHADE_MODEL", GL_INT }, 71 { GL_SCISSOR_TEST, "GL_SCISSOR_TEST", GL_INT }, 72 { 0, NULL, 0 } 73 }; 74 75 GLint i; 76 77 for (i = 0; state[i].token; i++) { 78 if (state[i].type == GL_INT) { 79 GLint v; 80 glGetIntegerv(state[i].token, &v); 81 printf("%s = %d\n", state[i].str, v); 82 } 83 else { 84 GLfloat v; 85 glGetFloatv(state[i].token, &v); 86 printf("%s = %f\n", state[i].str, v); 87 } 88 } 89} 90 91static void 92PrintVertex(const char *f, const struct vertex *v, int sz) 93{ 94 int i; 95 printf("%s(", f); 96 for (i = 0; i < sz; i++) { 97 printf("%g%s", v->v[i], (i == sz-1) ? "" : ", "); 98 } 99 printf(");\n"); 100} 101 102/** 103 * This can be called from within gdb after a crash: 104 * (gdb) call ReportState() 105 */ 106static void 107LastPrim(void) 108{ 109 int i; 110 for (i = 0; i < Vcount; i++) { 111 switch (Vbuffer[i].type) { 112 case BEGIN: 113 printf("glBegin(%d);\n", (int) Vbuffer[i].v[0]); 114 break; 115 case END: 116 printf("glEnd();\n"); 117 break; 118 case VERTEX2: 119 PrintVertex("glVertex2f", Vbuffer + i, 2); 120 break; 121 case VERTEX3: 122 PrintVertex("glVertex3f", Vbuffer + i, 3); 123 break; 124 case VERTEX4: 125 PrintVertex("glVertex4f", Vbuffer + i, 4); 126 break; 127 case COLOR3: 128 PrintVertex("glColor3f", Vbuffer + i, 3); 129 break; 130 case COLOR4: 131 PrintVertex("glColor4f", Vbuffer + i, 4); 132 break; 133 case TEX2: 134 PrintVertex("glTexCoord2f", Vbuffer + i, 2); 135 break; 136 case TEX3: 137 PrintVertex("glTexCoord3f", Vbuffer + i, 3); 138 break; 139 case TEX4: 140 PrintVertex("glTexCoord4f", Vbuffer + i, 4); 141 break; 142 case SECCOLOR3: 143 PrintVertex("glSecondaryColor3f", Vbuffer + i, 3); 144 break; 145 case NORMAL3: 146 PrintVertex("glNormal3f", Vbuffer + i, 3); 147 break; 148 default: 149 abort(); 150 } 151 } 152} 153 154 155static int 156RandomInt(int max) 157{ 158 if (max == 0) 159 return 0; 160 return rand() % max; 161} 162 163static float 164RandomFloat(float min, float max) 165{ 166 int k = rand() % 10000; 167 float x = min + (max - min) * k / 10000.0; 168 return x; 169} 170 171/* 172 * Return true if random number in [0,1] is <= percentile. 173 */ 174static GLboolean 175RandomChoice(float percentile) 176{ 177 return RandomFloat(0.0, 1.0) <= percentile; 178} 179 180static void 181RandomStateChange(void) 182{ 183 int k = RandomInt(19); 184 switch (k) { 185 case 0: 186 glEnable(GL_BLEND); 187 break; 188 case 1: 189 glDisable(GL_BLEND); 190 break; 191 case 2: 192 glEnable(GL_ALPHA_TEST); 193 break; 194 case 3: 195 glEnable(GL_ALPHA_TEST); 196 break; 197 case 4: 198 glEnable(GL_DEPTH_TEST); 199 break; 200 case 5: 201 glEnable(GL_DEPTH_TEST); 202 break; 203 case 6: 204 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 205 break; 206 case 7: 207 glPointSize(10.0); 208 break; 209 case 8: 210 glPointSize(1.0); 211 break; 212 case 9: 213 glLineWidth(10.0); 214 break; 215 case 10: 216 glLineWidth(1.0); 217 break; 218 case 11: 219 glEnable(GL_LIGHTING); 220 break; 221 case 12: 222 glDisable(GL_LIGHTING); 223 break; 224 case 13: 225 glEnable(GL_SCISSOR_TEST); 226 break; 227 case 14: 228 glDisable(GL_SCISSOR_TEST); 229 break; 230 case 15: 231 glEnable(GL_CLIP_PLANE0); 232 break; 233 case 16: 234 glDisable(GL_CLIP_PLANE0); 235 break; 236 case 17: 237 glShadeModel(GL_FLAT); 238 break; 239 case 18: 240 glShadeModel(GL_SMOOTH); 241 break; 242 } 243} 244 245 246static void 247RandomPrimitive(void) 248{ 249 int i; 250 int len = MinVertexCount + RandomInt(MaxVertexCount - MinVertexCount); 251 252 Vprim = RandomInt(10); 253 254 glBegin(Vprim); 255 Vbuffer[Vcount].type = BEGIN; 256 Vbuffer[Vcount].v[0] = Vprim; 257 Vcount++; 258 259 for (i = 0; i < len; i++) { 260 int k = RandomInt(9); 261 Vbuffer[Vcount].v[0] = RandomFloat(-3, 3); 262 Vbuffer[Vcount].v[1] = RandomFloat(-3, 3); 263 Vbuffer[Vcount].v[2] = RandomFloat(-3, 3); 264 Vbuffer[Vcount].v[3] = RandomFloat(-3, 3); 265 switch (k) { 266 case 0: 267 glVertex2fv(Vbuffer[Vcount].v); 268 Vbuffer[Vcount].type = VERTEX2; 269 break; 270 case 1: 271 glVertex3fv(Vbuffer[Vcount].v); 272 Vbuffer[Vcount].type = VERTEX3; 273 break; 274 case 2: 275 glVertex4fv(Vbuffer[Vcount].v); 276 Vbuffer[Vcount].type = VERTEX4; 277 break; 278 case 3: 279 glColor3fv(Vbuffer[Vcount].v); 280 Vbuffer[Vcount].type = COLOR3; 281 break; 282 case 4: 283 glColor4fv(Vbuffer[Vcount].v); 284 Vbuffer[Vcount].type = COLOR4; 285 break; 286 case 5: 287 glTexCoord2fv(Vbuffer[Vcount].v); 288 Vbuffer[Vcount].type = TEX2; 289 break; 290 case 6: 291 glTexCoord3fv(Vbuffer[Vcount].v); 292 Vbuffer[Vcount].type = TEX3; 293 break; 294 case 7: 295 glTexCoord4fv(Vbuffer[Vcount].v); 296 Vbuffer[Vcount].type = TEX4; 297 break; 298 case 8: 299 glSecondaryColor3fv(Vbuffer[Vcount].v); 300 Vbuffer[Vcount].type = SECCOLOR3; 301 break; 302 case 9: 303 glNormal3fv(Vbuffer[Vcount].v); 304 Vbuffer[Vcount].type = NORMAL3; 305 break; 306 default: 307 abort(); 308 } 309 Vcount++; 310 311 if (Vcount >= BufferSize - 2) { 312 /* reset */ 313 Vcount = 0; 314 } 315 } 316 317 Vbuffer[Vcount++].type = END; 318 319 glEnd(); 320} 321 322 323static void 324RandomDraw(void) 325{ 326 int i; 327 GLboolean dlist = RandomChoice(0.1); 328 if (dlist) 329 glNewList(1, GL_COMPILE); 330 for (i = 0; i < 3; i++) { 331 RandomStateChange(); 332 } 333 RandomPrimitive(); 334 335 if (dlist) { 336 glEndList(); 337 glCallList(1); 338 } 339} 340 341 342static void 343Idle(void) 344{ 345 glutPostRedisplay(); 346} 347 348 349static void 350Draw(void) 351{ 352#if 1 353 RandomDraw(); 354 Count++; 355#else 356 /* cut & paste temp code here */ 357#endif 358 359 assert(glGetError() == 0); 360 361 if (DB) 362 glutSwapBuffers(); 363 else 364 glFinish(); 365} 366 367 368static void 369Reshape(int width, int height) 370{ 371 Width = width; 372 Height = height; 373 glViewport(0, 0, width, height); 374 glScissor(20, 20, Width-40, Height-40); 375 glMatrixMode(GL_PROJECTION); 376 glLoadIdentity(); 377 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0); 378 glMatrixMode(GL_MODELVIEW); 379 glLoadIdentity(); 380 glTranslatef(0.0, 0.0, -15.0); 381} 382 383 384static void 385Key(unsigned char key, int x, int y) 386{ 387 (void) x; 388 (void) y; 389 switch (key) { 390 case 27: 391 glutDestroyWindow(Win); 392 exit(0); 393 break; 394 } 395 glutPostRedisplay(); 396} 397 398 399static void 400Init(void) 401{ 402 static const GLdouble plane[4] = {1, 1, 0, 0}; 403 glDrawBuffer(GL_FRONT); 404 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 405 glEnable(GL_LIGHT0); 406 glClipPlane(GL_CLIP_PLANE0, plane); 407 408 Vbuffer = (struct vertex *) 409 malloc(BufferSize * sizeof(struct vertex)); 410 411 /* silence warnings */ 412 (void) ReportState; 413 (void) LastPrim; 414} 415 416 417static void 418ParseArgs(int argc, char *argv[]) 419{ 420 int i; 421 for (i = 1; i < argc; i++) { 422 if (strcmp(argv[i], "-s") == 0) { 423 int j = atoi(argv[i + 1]); 424 printf("Random seed value: %d\n", j); 425 srand(j); 426 i++; 427 } 428 else if (strcmp(argv[i], "-a") == 0) { 429 i++; 430 MinVertexCount = atoi(argv[i]); 431 } 432 else if (strcmp(argv[i], "-b") == 0) { 433 i++; 434 MaxVertexCount = atoi(argv[i]); 435 } 436 } 437} 438 439 440int 441main(int argc, char *argv[]) 442{ 443 glutInit(&argc, argv); 444 glutInitWindowPosition(0, 0); 445 glutInitWindowSize(Width, Height); 446 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); 447 Win = glutCreateWindow(argv[0]); 448 glewInit(); 449 ParseArgs(argc, argv); 450 glutReshapeFunc(Reshape); 451 glutKeyboardFunc(Key); 452 glutDisplayFunc(Draw); 453 if (Anim) 454 glutIdleFunc(Idle); 455 Init(); 456 glutMainLoop(); 457 return 0; 458} 459