1/* 2 * This program is under the GNU GPL. 3 * Use at your own risk. 4 * 5 * written by David Bucciarelli (tech.hmw@plus.it) 6 * Humanware s.r.l. 7 */ 8 9#include <stdio.h> 10#include <stdlib.h> 11#include <math.h> 12#include <string.h> 13 14#if defined (WIN32)|| defined(_WIN32) 15#include <windows.h> 16#include <mmsystem.h> 17#endif 18 19#include <GL/glew.h> /* for GL_RESCALE_NORMAL_EXT */ 20#include "glut_wrap.h" 21 22#include "readtex.h" 23 24#ifdef XMESA 25#include "GL/xmesa.h" 26static int fullscreen = 1; 27#endif 28 29static int WIDTH = 640; 30static int HEIGHT = 480; 31 32static GLint T0; 33static GLint Frames; 34 35#define MAX_LOD 9 36 37#define TEX_SKY_WIDTH 256 38#define TEX_SKY_HEIGHT TEX_SKY_WIDTH 39 40#ifndef M_PI 41#define M_PI 3.1415926535 42#endif 43 44#define FROM_NONE 0 45#define FROM_DOWN 1 46#define FROM_UP 2 47#define FROM_LEFT 3 48#define FROM_RIGHT 4 49#define FROM_FRONT 5 50#define FROM_BACK 6 51 52static int win = 0; 53 54static float obs[3] = { 3.8, 0.0, 0.0 }; 55static float dir[3]; 56static float v = 0.0; 57static float alpha = -90.0; 58static float beta = 90.0; 59 60static int fog = 1; 61static int bfcull = 1; 62static int usetex = 1; 63static int help = 1; 64static int poutline = 0; 65static int normext = 1; 66static int joyavailable = 0; 67static int joyactive = 0; 68static int LODbias = 3; 69static int maxdepth = MAX_LOD; 70 71static unsigned int totpoly = 0; 72 73static GLuint t1id, t2id; 74static GLuint skydlist, LODdlist[MAX_LOD], LODnumpoly[MAX_LOD]; 75 76static void 77initlight(void) 78{ 79 GLfloat lspec[4] = { 1.0, 1.0, 1.0, 1.0 }; 80 static GLfloat lightpos[4] = { 30, 15.0, 30.0, 1.0 }; 81 82 glLightfv(GL_LIGHT0, GL_POSITION, lightpos); 83 glLightfv(GL_LIGHT0, GL_SPECULAR, lspec); 84 85 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 32.0); 86 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, lspec); 87} 88 89static void 90initdlists(void) 91{ 92 static int slicetable[MAX_LOD][2] = { 93 {21, 10}, 94 {18, 9}, 95 {15, 8}, 96 {12, 7}, 97 {9, 6}, 98 {7, 5}, 99 {5, 4}, 100 {4, 3}, 101 {3, 2} 102 }; 103 GLUquadricObj *obj; 104 int i, xslices, yslices; 105 106 obj = gluNewQuadric(); 107 108 skydlist = glGenLists(1); 109 glNewList(skydlist, GL_COMPILE); 110 glBindTexture(GL_TEXTURE_2D, t2id); 111 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 112 glColor3f(1.0f, 1.0f, 1.0f); 113 114 gluQuadricDrawStyle(obj, GLU_FILL); 115 gluQuadricNormals(obj, GLU_NONE); 116 gluQuadricTexture(obj, GL_TRUE); 117 gluQuadricOrientation(obj, GLU_INSIDE); 118 gluSphere(obj, 40.0f, 18, 9); 119 120 glEndList(); 121 122 for (i = 0; i < MAX_LOD; i++) { 123 LODdlist[i] = glGenLists(1); 124 glNewList(LODdlist[i], GL_COMPILE); 125 126 gluQuadricDrawStyle(obj, GLU_FILL); 127 gluQuadricNormals(obj, GLU_SMOOTH); 128 gluQuadricTexture(obj, GL_TRUE); 129 gluQuadricOrientation(obj, GLU_OUTSIDE); 130 xslices = slicetable[i][0]; 131 yslices = slicetable[i][1]; 132 gluSphere(obj, 1.0f, xslices, yslices); 133 LODnumpoly[i] = xslices * (yslices - 2) + 2 * (xslices - 1); 134 135 glEndList(); 136 } 137 138 gluDeleteQuadric(obj); 139} 140 141static void 142inittextures(void) 143{ 144 GLubyte tsky[TEX_SKY_HEIGHT][TEX_SKY_WIDTH][3]; 145 GLuint x, y; 146 GLfloat fact; 147 GLenum gluerr; 148 149 /* Brick */ 150 151 glGenTextures(1, &t1id); 152 glBindTexture(GL_TEXTURE_2D, t1id); 153 154 if (!LoadRGBMipmaps(DEMOS_DATA_DIR "bw.rgb", 3)) { 155 fprintf(stderr, "Error reading a texture.\n"); 156 exit(-1); 157 } 158 159 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 160 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 161 162 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 163 GL_LINEAR_MIPMAP_LINEAR); 164 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 165 166 /* Sky */ 167 168 glGenTextures(1, &t2id); 169 glBindTexture(GL_TEXTURE_2D, t2id); 170 171 for (y = 0; y < TEX_SKY_HEIGHT; y++) 172 for (x = 0; x < TEX_SKY_WIDTH; x++) 173 if (y < TEX_SKY_HEIGHT / 2) { 174 fact = y / (GLfloat) (TEX_SKY_HEIGHT / 2); 175 tsky[y][x][0] = 176 (GLubyte) (255.0f * (0.1f * fact + 0.3f * (1.0f - fact))); 177 tsky[y][x][1] = 178 (GLubyte) (255.0f * (0.2f * fact + 1.0f * (1.0f - fact))); 179 tsky[y][x][2] = 255; 180 } 181 else { 182 tsky[y][x][0] = tsky[TEX_SKY_HEIGHT - y - 1][x][0]; 183 tsky[y][x][1] = tsky[TEX_SKY_HEIGHT - y - 1][x][1]; 184 tsky[y][x][2] = 255; 185 } 186 187 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 188 if ( 189 (gluerr = 190 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TEX_SKY_WIDTH, TEX_SKY_HEIGHT, 191 GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *) (tsky)))) { 192 fprintf(stderr, "GLULib%s\n", (char *) gluErrorString(gluerr)); 193 exit(-1); 194 } 195 196 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 197 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 198 199 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 200 GL_LINEAR_MIPMAP_LINEAR); 201 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 202} 203 204static void 205calcposobs(void) 206{ 207 dir[0] = sin(alpha * M_PI / 180.0); 208 dir[1] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0); 209 dir[2] = cos(beta * M_PI / 180.0); 210 211 if (dir[0] < 1.0e-5 && dir[0] > -1.0e-5) 212 dir[0] = 0; 213 if (dir[1] < 1.0e-5 && dir[1] > -1.0e-5) 214 dir[1] = 0; 215 if (dir[2] < 1.0e-5 && dir[2] > -1.0e-5) 216 dir[2] = 0; 217 218 obs[0] += v * dir[0]; 219 obs[1] += v * dir[1]; 220 obs[2] += v * dir[2]; 221} 222 223static void 224special(int k, int x, int y) 225{ 226 switch (k) { 227 case GLUT_KEY_LEFT: 228 alpha -= 2.0; 229 break; 230 case GLUT_KEY_RIGHT: 231 alpha += 2.0; 232 break; 233 case GLUT_KEY_DOWN: 234 beta -= 2.0; 235 break; 236 case GLUT_KEY_UP: 237 beta += 2.0; 238 break; 239 } 240} 241 242static void 243cleanup(void) 244{ 245 int i; 246 247 glDeleteTextures(1, &t1id); 248 glDeleteTextures(1, &t2id); 249 250 glDeleteLists(skydlist, 1); 251 for (i = 0; i < MAX_LOD; i++) { 252 glDeleteLists(LODdlist[i], 1); 253 glDeleteLists(LODnumpoly[i], 1); 254 } 255 256 glutDestroyWindow(glutGetWindow()); 257} 258 259 260static void 261key(unsigned char k, int x, int y) 262{ 263 switch (k) { 264 case 27: 265 cleanup(); 266 exit(0); 267 break; 268 269 case 'a': 270 v += 0.01; 271 break; 272 case 'z': 273 v -= 0.01; 274 break; 275 276#ifdef XMESA 277 case ' ': 278 fullscreen = (!fullscreen); 279 XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW); 280 break; 281#endif 282 283 case '+': 284 LODbias--; 285 break; 286 case '-': 287 LODbias++; 288 break; 289 case 'j': 290 joyactive = (!joyactive); 291 break; 292 case 'h': 293 help = (!help); 294 break; 295 case 'f': 296 fog = (!fog); 297 break; 298 case 't': 299 usetex = (!usetex); 300 break; 301 case 'n': 302 normext = (!normext); 303 break; 304 case 'b': 305 if (bfcull) { 306 glDisable(GL_CULL_FACE); 307 bfcull = 0; 308 } 309 else { 310 glEnable(GL_CULL_FACE); 311 bfcull = 1; 312 } 313 break; 314 case 'p': 315 if (poutline) { 316 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 317 poutline = 0; 318 usetex = 1; 319 } 320 else { 321 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 322 poutline = 1; 323 usetex = 0; 324 } 325 break; 326 } 327} 328 329static void 330reshape(int w, int h) 331{ 332 WIDTH = w; 333 HEIGHT = h; 334 glMatrixMode(GL_PROJECTION); 335 glLoadIdentity(); 336 gluPerspective(90.0, w / (float) h, 0.8, 100.0); 337 glMatrixMode(GL_MODELVIEW); 338 glLoadIdentity(); 339 glViewport(0, 0, w, h); 340} 341 342static void 343printstring(void *font, char *string) 344{ 345 int len, i; 346 347 len = (int) strlen(string); 348 for (i = 0; i < len; i++) 349 glutBitmapCharacter(font, string[i]); 350} 351 352static void 353printhelp(void) 354{ 355 glEnable(GL_BLEND); 356 glColor4f(0.5, 0.5, 0.5, 0.5); 357 glRecti(40, 40, 600, 440); 358 glDisable(GL_BLEND); 359 360 glColor3f(1.0, 0.0, 0.0); 361 glRasterPos2i(300, 420); 362 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help"); 363 364 glRasterPos2i(60, 390); 365 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Toggle Help"); 366 glRasterPos2i(60, 360); 367 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Toggle Textures"); 368 glRasterPos2i(60, 330); 369 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Toggle Fog"); 370 glRasterPos2i(60, 300); 371 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "b - Toggle Back face culling"); 372 glRasterPos2i(60, 270); 373 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate"); 374 glRasterPos2i(60, 240); 375 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity"); 376 glRasterPos2i(60, 210); 377 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity"); 378 glRasterPos2i(60, 180); 379 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "p - Toggle Wire frame"); 380 glRasterPos2i(60, 150); 381 printstring(GLUT_BITMAP_TIMES_ROMAN_24, 382 "n - Toggle GL_EXT_rescale_normal extension"); 383 glRasterPos2i(60, 120); 384 printstring(GLUT_BITMAP_TIMES_ROMAN_24, 385 "+/- - Increase/decrease the Object maximum LOD"); 386 387 glRasterPos2i(60, 90); 388 if (joyavailable) 389 printstring(GLUT_BITMAP_TIMES_ROMAN_24, 390 "j - Toggle jostick control (Joystick control available)"); 391 else 392 printstring(GLUT_BITMAP_TIMES_ROMAN_24, 393 "(No Joystick control available)"); 394} 395 396static void 397dojoy(void) 398{ 399#ifdef _WIN32 400 static UINT max[2] = { 0, 0 }; 401 static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2]; 402 MMRESULT res; 403 JOYINFO joy; 404 405 res = joyGetPos(JOYSTICKID1, &joy); 406 407 if (res == JOYERR_NOERROR) { 408 joyavailable = 1; 409 410 if (max[0] < joy.wXpos) 411 max[0] = joy.wXpos; 412 if (min[0] > joy.wXpos) 413 min[0] = joy.wXpos; 414 center[0] = (max[0] + min[0]) / 2; 415 416 if (max[1] < joy.wYpos) 417 max[1] = joy.wYpos; 418 if (min[1] > joy.wYpos) 419 min[1] = joy.wYpos; 420 center[1] = (max[1] + min[1]) / 2; 421 422 if (joyactive) { 423 if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0])) 424 alpha -= 425 2.0 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]); 426 if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1])) 427 beta += 2.0 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]); 428 429 if (joy.wButtons & JOY_BUTTON1) 430 v += 0.01; 431 if (joy.wButtons & JOY_BUTTON2) 432 v -= 0.01; 433 } 434 } 435 else 436 joyavailable = 0; 437#endif 438} 439 440static void 441drawipers(int depth, int from) 442{ 443 int lod; 444 445 if (depth == maxdepth) 446 return; 447 448 lod = depth + LODbias; 449 if (lod < 0) 450 lod = 0; 451 if (lod >= MAX_LOD) 452 return; 453 454 switch (from) { 455 case FROM_NONE: 456 glCallList(LODdlist[lod]); 457 458 depth++; 459 drawipers(depth, FROM_DOWN); 460 drawipers(depth, FROM_UP); 461 drawipers(depth, FROM_FRONT); 462 drawipers(depth, FROM_BACK); 463 drawipers(depth, FROM_LEFT); 464 drawipers(depth, FROM_RIGHT); 465 break; 466 case FROM_FRONT: 467 glPushMatrix(); 468 glTranslatef(0.0f, -1.5f, 0.0f); 469 glScalef(0.5f, 0.5f, 0.5f); 470 471 glCallList(LODdlist[lod]); 472 473 depth++; 474 drawipers(depth, FROM_DOWN); 475 drawipers(depth, FROM_UP); 476 drawipers(depth, FROM_FRONT); 477 drawipers(depth, FROM_LEFT); 478 drawipers(depth, FROM_RIGHT); 479 glPopMatrix(); 480 break; 481 case FROM_BACK: 482 glPushMatrix(); 483 glTranslatef(0.0f, 1.5f, 0.0f); 484 glScalef(0.5f, 0.5f, 0.5f); 485 486 glCallList(LODdlist[lod]); 487 488 depth++; 489 drawipers(depth, FROM_DOWN); 490 drawipers(depth, FROM_UP); 491 drawipers(depth, FROM_BACK); 492 drawipers(depth, FROM_LEFT); 493 drawipers(depth, FROM_RIGHT); 494 glPopMatrix(); 495 break; 496 case FROM_LEFT: 497 glPushMatrix(); 498 glTranslatef(-1.5f, 0.0f, 0.0f); 499 glScalef(0.5f, 0.5f, 0.5f); 500 501 glCallList(LODdlist[lod]); 502 503 depth++; 504 drawipers(depth, FROM_DOWN); 505 drawipers(depth, FROM_UP); 506 drawipers(depth, FROM_FRONT); 507 drawipers(depth, FROM_BACK); 508 drawipers(depth, FROM_LEFT); 509 glPopMatrix(); 510 break; 511 case FROM_RIGHT: 512 glPushMatrix(); 513 glTranslatef(1.5f, 0.0f, 0.0f); 514 glScalef(0.5f, 0.5f, 0.5f); 515 516 glCallList(LODdlist[lod]); 517 518 depth++; 519 drawipers(depth, FROM_DOWN); 520 drawipers(depth, FROM_UP); 521 drawipers(depth, FROM_FRONT); 522 drawipers(depth, FROM_BACK); 523 drawipers(depth, FROM_RIGHT); 524 glPopMatrix(); 525 break; 526 case FROM_DOWN: 527 glPushMatrix(); 528 glTranslatef(0.0f, 0.0f, 1.5f); 529 glScalef(0.5f, 0.5f, 0.5f); 530 531 glCallList(LODdlist[lod]); 532 533 depth++; 534 drawipers(depth, FROM_DOWN); 535 drawipers(depth, FROM_FRONT); 536 drawipers(depth, FROM_BACK); 537 drawipers(depth, FROM_LEFT); 538 drawipers(depth, FROM_RIGHT); 539 glPopMatrix(); 540 break; 541 case FROM_UP: 542 glPushMatrix(); 543 glTranslatef(0.0f, 0.0f, -1.5f); 544 glScalef(0.5f, 0.5f, 0.5f); 545 546 glCallList(LODdlist[lod]); 547 548 depth++; 549 drawipers(depth, FROM_UP); 550 drawipers(depth, FROM_FRONT); 551 drawipers(depth, FROM_BACK); 552 drawipers(depth, FROM_LEFT); 553 drawipers(depth, FROM_RIGHT); 554 glPopMatrix(); 555 break; 556 } 557 558 totpoly += LODnumpoly[lod]; 559} 560 561static void 562draw(void) 563{ 564 static char frbuf[80] = ""; 565 static GLfloat alpha = 0.0f; 566 static GLfloat beta = 0.0f; 567 static float fr = 0.0; 568 static double t0 = -1.; 569 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; 570 if (t0 < 0.0) 571 t0 = t; 572 dt = t - t0; 573 t0 = t; 574 575 dojoy(); 576 577 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 578 579 if (usetex) 580 glEnable(GL_TEXTURE_2D); 581 else 582 glDisable(GL_TEXTURE_2D); 583 584 if (fog) 585 glEnable(GL_FOG); 586 else 587 glDisable(GL_FOG); 588 589 glPushMatrix(); 590 calcposobs(); 591 gluLookAt(obs[0], obs[1], obs[2], 592 obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2], 593 0.0, 0.0, 1.0); 594 595 /* Scene */ 596 glEnable(GL_DEPTH_TEST); 597 598 glShadeModel(GL_SMOOTH); 599 glBindTexture(GL_TEXTURE_2D, t1id); 600 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 601 glColor3f(1.0f, 1.0f, 1.0f); 602 glEnable(GL_LIGHT0); 603 glEnable(GL_LIGHTING); 604 605 if (normext) 606 glEnable(GL_RESCALE_NORMAL_EXT); 607 else 608 glEnable(GL_NORMALIZE); 609 610 glPushMatrix(); 611 glRotatef(alpha, 0.0f, 0.0f, 1.0f); 612 glRotatef(beta, 1.0f, 0.0f, 0.0f); 613 totpoly = 0; 614 drawipers(0, FROM_NONE); 615 glPopMatrix(); 616 617 alpha += 4.f * dt; 618 beta += 2.4f * dt; 619 620 glDisable(GL_LIGHTING); 621 glDisable(GL_LIGHT0); 622 glShadeModel(GL_FLAT); 623 624 if (normext) 625 glDisable(GL_RESCALE_NORMAL_EXT); 626 else 627 glDisable(GL_NORMALIZE); 628 629 glCallList(skydlist); 630 631 glPopMatrix(); 632 633 /* Help Screen */ 634 635 sprintf(frbuf, 636 "Frame rate: %0.2f LOD: %d Tot. poly.: %d Poly/sec: %.1f", 637 fr, LODbias, totpoly, totpoly * fr); 638 639 glDisable(GL_TEXTURE_2D); 640 glDisable(GL_FOG); 641 glShadeModel(GL_FLAT); 642 glDisable(GL_DEPTH_TEST); 643 644 glMatrixMode(GL_PROJECTION); 645 glPushMatrix(); 646 glLoadIdentity(); 647 glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0); 648 649 glMatrixMode(GL_MODELVIEW); 650 glLoadIdentity(); 651 652 glColor3f(1.0, 0.0, 0.0); 653 glRasterPos2i(10, 10); 654 printstring(GLUT_BITMAP_HELVETICA_18, frbuf); 655 glRasterPos2i(350, 470); 656 printstring(GLUT_BITMAP_HELVETICA_10, 657 "IperS V1.0 Written by David Bucciarelli (tech.hmw@plus.it)"); 658 659 if (help) 660 printhelp(); 661 662 glMatrixMode(GL_PROJECTION); 663 glPopMatrix(); 664 glMatrixMode(GL_MODELVIEW); 665 666 glutSwapBuffers(); 667 668 Frames++; 669 { 670 GLint t = glutGet(GLUT_ELAPSED_TIME); 671 if (t - T0 >= 2000) { 672 GLfloat seconds = (t - T0) / 1000.0; 673 fr = Frames / seconds; 674 printf("Frame rate: %f\n", fr); 675 fflush(stdout); 676 T0 = t; 677 Frames = 0; 678 } 679 } 680} 681 682int 683main(int ac, char **av) 684{ 685 float fogcolor[4] = { 0.7, 0.7, 0.7, 1.0 }; 686 687 fprintf(stderr, 688 "IperS V1.0\nWritten by David Bucciarelli (tech.hmw@plus.it)\n"); 689 690 glutInitWindowSize(WIDTH, HEIGHT); 691 glutInit(&ac, av); 692 693 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 694 695 if (!(win = glutCreateWindow("IperS"))) { 696 fprintf(stderr, "Error, couldn't open window\n"); 697 exit(-1); 698 } 699 700 reshape(WIDTH, HEIGHT); 701 702 glShadeModel(GL_SMOOTH); 703 glEnable(GL_DEPTH_TEST); 704 glEnable(GL_CULL_FACE); 705 glEnable(GL_TEXTURE_2D); 706 707 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 708 709 glEnable(GL_FOG); 710 glFogi(GL_FOG_MODE, GL_EXP2); 711 glFogfv(GL_FOG_COLOR, fogcolor); 712 713 glFogf(GL_FOG_DENSITY, 0.006); 714 715 glHint(GL_FOG_HINT, GL_NICEST); 716 717 inittextures(); 718 initdlists(); 719 initlight(); 720 721 glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]); 722 glClear(GL_COLOR_BUFFER_BIT); 723 724 calcposobs(); 725 726 glutReshapeFunc(reshape); 727 glutDisplayFunc(draw); 728 glutKeyboardFunc(key); 729 glutSpecialFunc(special); 730 glutIdleFunc(draw); 731 732 glutMainLoop(); 733 cleanup(); 734 735 return 0; 736} 737