2 * This program is under the GNU GPL.
3 * Use at your own risk.
5 * written by David Bucciarelli (tech.hmw@plus.it)
21 static int fullscreen
= 1;
24 static int WIDTH
= 640;
25 static int HEIGHT
= 480;
28 static GLint Frames
= 0;
31 #define SPHERE_RADIUS 0.75f
33 #define TEX_CHECK_WIDTH 256
34 #define TEX_CHECK_HEIGHT 256
35 #define TEX_CHECK_SLOT_SIZE (TEX_CHECK_HEIGHT/16)
36 #define TEX_CHECK_NUMSLOT (TEX_CHECK_HEIGHT/TEX_CHECK_SLOT_SIZE)
38 #define TEX_REFLECT_WIDTH 256
39 #define TEX_REFLECT_HEIGHT 256
40 #define TEX_REFLECT_SLOT_SIZE (TEX_REFLECT_HEIGHT/16)
41 #define TEX_REFLECT_NUMSLOT (TEX_REFLECT_HEIGHT/TEX_REFLECT_SLOT_SIZE)
44 #define M_PI 3.1415926535
47 #define EPSILON 0.0001
49 #define clamp255(a) ( (a)<(0.0f) ? (0.0f) : ((a)>(255.0f) ? (255.0f) : (a)) )
51 #define fabs(x) ((x)<0.0f?-(x):(x))
53 #define vequ(a,b) { (a)[0]=(b)[0]; (a)[1]=(b)[1]; (a)[2]=(b)[2]; }
54 #define vsub(a,b,c) { (a)[0]=(b)[0]-(c)[0]; (a)[1]=(b)[1]-(c)[1]; (a)[2]=(b)[2]-(c)[2]; }
55 #define dprod(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2])
56 #define vnormalize(a,b) { \
57 register float m_norm; \
58 m_norm=sqrt((double)dprod((a),(a))); \
63 static GLubyte checkmap
[TEX_CHECK_HEIGHT
][TEX_CHECK_WIDTH
][3];
64 static GLuint checkid
;
65 static int checkmap_currentslot
= 0;
67 static GLubyte reflectmap
[TEX_REFLECT_HEIGHT
][TEX_REFLECT_WIDTH
][3];
68 static GLuint reflectid
;
69 static int reflectmap_currentslot
= 0;
71 static GLuint lightdlist
;
72 static GLuint objdlist
;
74 static float lightpos
[3] = { 2.1, 2.1, 2.8 };
75 static float objpos
[3] = { 0.0, 0.0, 1.0 };
77 static float sphere_pos
[TEX_CHECK_HEIGHT
][TEX_REFLECT_WIDTH
][3];
81 static float fogcolor
[4] = { 0.05, 0.05, 0.05, 1.0 };
83 static float obs
[3] = { 7.0, 0.0, 2.0 };
86 static float alpha
= -90.0;
87 static float beta
= 90.0;
90 static int bfcull
= 1;
91 static int poutline
= 0;
93 static int showcheckmap
= 1;
94 static int showreflectmap
= 1;
95 static int joyavailable
= 0;
96 static int joyactive
= 0;
101 dir
[0] = sin(alpha
* M_PI
/ 180.0);
102 dir
[1] = cos(alpha
* M_PI
/ 180.0) * sin(beta
* M_PI
/ 180.0);
103 dir
[2] = cos(beta
* M_PI
/ 180.0);
105 obs
[0] += v
* dir
[0];
106 obs
[1] += v
* dir
[1];
107 obs
[2] += v
* dir
[2];
111 special(int k
, int x
, int y
)
130 key(unsigned char k
, int x
, int y
)
183 joyactive
= (!joyactive
);
193 showcheckmap
= (!showcheckmap
);
196 showreflectmap
= (!showreflectmap
);
201 glDisable(GL_CULL_FACE
);
205 glEnable(GL_CULL_FACE
);
211 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
215 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
221 XMesaSetFXmode(fullscreen
? XMESA_FX_FULLSCREEN
: XMESA_FX_WINDOW
);
222 fullscreen
= (!fullscreen
);
229 reshape(int w
, int h
)
233 glViewport(0, 0, w
, h
);
234 glMatrixMode(GL_PROJECTION
);
236 gluPerspective(45.0, w
/ (float) h
, 0.8, 40.0);
237 glMatrixMode(GL_MODELVIEW
);
242 printstring(void *font
, char *string
)
246 len
= (int) strlen(string
);
247 for (i
= 0; i
< len
; i
++)
248 glutBitmapCharacter(font
, string
[i
]);
255 glColor4f(0.5, 0.5, 0.5, 0.5);
256 glRecti(40, 40, 600, 440);
259 glColor3f(0.0, 0.0, 1.0);
260 glRasterPos2i(300, 420);
261 printstring(GLUT_BITMAP_HELVETICA_18
, "Help");
263 glRasterPos2i(60, 390);
264 printstring(GLUT_BITMAP_HELVETICA_12
, "h - Togle Help");
265 glRasterPos2i(60, 370);
266 printstring(GLUT_BITMAP_HELVETICA_12
, "f - Togle Fog");
267 glRasterPos2i(60, 350);
268 printstring(GLUT_BITMAP_HELVETICA_12
, "b - Togle Back face culling");
269 glRasterPos2i(60, 330);
270 printstring(GLUT_BITMAP_HELVETICA_12
, "p - Togle Wire frame");
271 glRasterPos2i(60, 310);
272 printstring(GLUT_BITMAP_HELVETICA_12
, "Arrow Keys - Rotate");
273 glRasterPos2i(60, 290);
274 printstring(GLUT_BITMAP_HELVETICA_12
, "a - Increase velocity");
275 glRasterPos2i(60, 270);
276 printstring(GLUT_BITMAP_HELVETICA_12
, "z - Decrease velocity");
278 glRasterPos2i(60, 250);
280 printstring(GLUT_BITMAP_HELVETICA_12
,
281 "j - Togle jostick control (Joystick control available)");
283 printstring(GLUT_BITMAP_HELVETICA_12
,
284 "(No Joystick control available)");
286 glRasterPos2i(60, 230);
287 printstring(GLUT_BITMAP_HELVETICA_12
,
288 "To move the light source: s - left, d - right, e - far, x - near, w - down r - up");
289 glRasterPos2i(60, 210);
290 printstring(GLUT_BITMAP_HELVETICA_12
,
291 "To move the mirror sphere: j - left, k - right, i - far, m - near, u - down o - up");
293 glRasterPos2i(60, 190);
294 printstring(GLUT_BITMAP_HELVETICA_12
,
295 "1 - Togle the plane texture map window");
297 glRasterPos2i(60, 170);
298 printstring(GLUT_BITMAP_HELVETICA_12
,
299 "2 - Togle the sphere texture map window");
303 seelight(float p
[3], float dir
[3])
305 float c
[3], b
, a
, d
, t
, dist
[3];
309 a
= dprod(c
, c
) - SPHERE_RADIUS
* SPHERE_RADIUS
;
311 if ((d
= b
* b
- a
) < 0.0 || (b
< 0.0 && a
> 0.0))
324 vsub(dist
, lightpos
, p
);
325 if (dprod(dist
, dist
) < t
* t
)
332 colorcheckmap(float ppos
[3], float c
[3])
334 static float norm
[3] = { 0.0f
, 0.0f
, 1.0f
};
335 float ldir
[3], vdir
[3], h
[3], dfact
, kfact
, r
, g
, b
;
338 x
= (int) ((ppos
[0] + BASESIZE
/ 2) * (10.0f
/ BASESIZE
));
339 if ((x
< 0) || (x
> 10))
342 y
= (int) ((ppos
[1] + BASESIZE
/ 2) * (10.0f
/ BASESIZE
));
343 if ((y
< 0) || (y
> 10))
361 vsub(ldir
, lightpos
, ppos
);
362 vnormalize(ldir
, ldir
);
364 if (seelight(ppos
, ldir
)) {
372 dfact
= dprod(ldir
, norm
);
376 vsub(vdir
, obs
, ppos
);
377 vnormalize(vdir
, vdir
);
378 h
[0] = 0.5f
* (vdir
[0] + ldir
[0]);
379 h
[1] = 0.5f
* (vdir
[1] + ldir
[1]);
380 h
[2] = 0.5f
* (vdir
[2] + ldir
[2]);
381 kfact
= dprod(h
, norm
);
383 kfact
* kfact
* kfact
* kfact
* kfact
* kfact
* kfact
* 7.0f
* 255.0f
;
385 r
= r
* dfact
+ kfact
;
386 g
= g
* dfact
+ kfact
;
387 b
= b
* dfact
+ kfact
;
397 updatecheckmap(int slot
)
402 glBindTexture(GL_TEXTURE_2D
, checkid
);
405 for (y
= slot
* TEX_CHECK_SLOT_SIZE
; y
< (slot
+ 1) * TEX_CHECK_SLOT_SIZE
;
407 ppos
[1] = (y
/ (float) TEX_CHECK_HEIGHT
) * BASESIZE
- BASESIZE
/ 2;
409 for (x
= 0; x
< TEX_CHECK_WIDTH
; x
++) {
410 ppos
[0] = (x
/ (float) TEX_CHECK_WIDTH
) * BASESIZE
- BASESIZE
/ 2;
412 colorcheckmap(ppos
, c
);
413 checkmap
[y
][x
][0] = (GLubyte
) c
[0];
414 checkmap
[y
][x
][1] = (GLubyte
) c
[1];
415 checkmap
[y
][x
][2] = (GLubyte
) c
[2];
419 glTexSubImage2D(GL_TEXTURE_2D
, 0, 0, slot
* TEX_CHECK_SLOT_SIZE
,
420 TEX_CHECK_WIDTH
, TEX_CHECK_SLOT_SIZE
, GL_RGB
,
422 &checkmap
[slot
* TEX_CHECK_SLOT_SIZE
][0][0]);
427 updatereflectmap(int slot
)
429 float rf
, r
, g
, b
, t
, dfact
, kfact
, rdir
[3];
430 float rcol
[3], ppos
[3], norm
[3], ldir
[3], h
[3], vdir
[3], planepos
[3];
433 glBindTexture(GL_TEXTURE_2D
, reflectid
);
435 for (y
= slot
* TEX_REFLECT_SLOT_SIZE
;
436 y
< (slot
+ 1) * TEX_REFLECT_SLOT_SIZE
; y
++)
437 for (x
= 0; x
< TEX_REFLECT_WIDTH
; x
++) {
438 ppos
[0] = sphere_pos
[y
][x
][0] + objpos
[0];
439 ppos
[1] = sphere_pos
[y
][x
][1] + objpos
[1];
440 ppos
[2] = sphere_pos
[y
][x
][2] + objpos
[2];
442 vsub(norm
, ppos
, objpos
);
443 vnormalize(norm
, norm
);
445 vsub(ldir
, lightpos
, ppos
);
446 vnormalize(ldir
, ldir
);
447 vsub(vdir
, obs
, ppos
);
448 vnormalize(vdir
, vdir
);
450 rf
= 2.0f
* dprod(norm
, vdir
);
452 rdir
[0] = rf
* norm
[0] - vdir
[0];
453 rdir
[1] = rf
* norm
[1] - vdir
[1];
454 rdir
[2] = rf
* norm
[2] - vdir
[2];
456 t
= -objpos
[2] / rdir
[2];
459 planepos
[0] = objpos
[0] + t
* rdir
[0];
460 planepos
[1] = objpos
[1] + t
* rdir
[1];
463 if (!colorcheckmap(planepos
, rcol
))
464 rcol
[0] = rcol
[1] = rcol
[2] = 0.0f
;
467 rcol
[0] = rcol
[1] = rcol
[2] = 0.0f
;
470 rcol
[0] = rcol
[1] = rcol
[2] = 0.0f
;
472 dfact
= 0.1f
* dprod(ldir
, norm
);
479 h
[0] = 0.5f
* (vdir
[0] + ldir
[0]);
480 h
[1] = 0.5f
* (vdir
[1] + ldir
[1]);
481 h
[2] = 0.5f
* (vdir
[2] + ldir
[2]);
482 kfact
= dprod(h
, norm
);
506 reflectmap
[y
][x
][0] = (GLubyte
) r
;
507 reflectmap
[y
][x
][1] = (GLubyte
) g
;
508 reflectmap
[y
][x
][2] = (GLubyte
) b
;
511 glTexSubImage2D(GL_TEXTURE_2D
, 0, 0, slot
* TEX_REFLECT_SLOT_SIZE
,
512 TEX_REFLECT_WIDTH
, TEX_REFLECT_SLOT_SIZE
, GL_RGB
,
514 &reflectmap
[slot
* TEX_REFLECT_SLOT_SIZE
][0][0]);
520 glColor3f(0.0, 0.0, 0.0);
521 glBindTexture(GL_TEXTURE_2D
, checkid
);
522 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
525 glTexCoord2f(0.0f
, 0.0f
);
526 glVertex3f(-BASESIZE
/ 2.0f
, -BASESIZE
/ 2.0f
, 0.0f
);
528 glTexCoord2f(1.0f
, 0.0f
);
529 glVertex3f(BASESIZE
/ 2.0f
, -BASESIZE
/ 2.0f
, 0.0f
);
531 glTexCoord2f(1.0f
, 1.0f
);
532 glVertex3f(BASESIZE
/ 2.0f
, BASESIZE
/ 2.0f
, 0.0f
);
534 glTexCoord2f(0.0f
, 1.0f
);
535 glVertex3f(-BASESIZE
/ 2.0f
, BASESIZE
/ 2.0f
, 0.0f
);
543 glColor3f(0.0, 0.0, 0.0);
544 glBindTexture(GL_TEXTURE_2D
, reflectid
);
545 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
548 glTranslatef(objpos
[0], objpos
[1], objpos
[2]);
549 glCallList(objdlist
);
557 static UINT max
[2] = { 0, 0 };
558 static UINT min
[2] = { 0xffffffff, 0xffffffff }, center
[2];
562 res
= joyGetPos(JOYSTICKID1
, &joy
);
564 if (res
== JOYERR_NOERROR
) {
567 if (max
[0] < joy
.wXpos
)
569 if (min
[0] > joy
.wXpos
)
571 center
[0] = (max
[0] + min
[0]) / 2;
573 if (max
[1] < joy
.wYpos
)
575 if (min
[1] > joy
.wYpos
)
577 center
[1] = (max
[1] + min
[1]) / 2;
580 if (fabs(center
[0] - (float) joy
.wXpos
) > 0.1 * (max
[0] - min
[0]))
582 2.5 * (center
[0] - (float) joy
.wXpos
) / (max
[0] - min
[0]);
583 if (fabs(center
[1] - (float) joy
.wYpos
) > 0.1 * (max
[1] - min
[1]))
584 beta
+= 2.5 * (center
[1] - (float) joy
.wYpos
) / (max
[1] - min
[1]);
586 if (joy
.wButtons
& JOY_BUTTON1
)
588 if (joy
.wButtons
& JOY_BUTTON2
)
600 updatecheckmap(checkmap_currentslot
);
601 checkmap_currentslot
= (checkmap_currentslot
+ 1) % TEX_CHECK_NUMSLOT
;
603 updatereflectmap(reflectmap_currentslot
);
604 reflectmap_currentslot
=
605 (reflectmap_currentslot
+ 1) % TEX_REFLECT_NUMSLOT
;
611 static char frbuf
[80] = "";
615 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
617 glEnable(GL_TEXTURE_2D
);
618 glEnable(GL_DEPTH_TEST
);
627 gluLookAt(obs
[0], obs
[1], obs
[2],
628 obs
[0] + dir
[0], obs
[1] + dir
[1], obs
[2] + dir
[2],
634 glColor3f(1.0, 1.0, 1.0);
635 glDisable(GL_TEXTURE_2D
);
638 glTranslatef(lightpos
[0], lightpos
[1], lightpos
[2]);
639 glCallList(lightdlist
);
644 glDisable(GL_DEPTH_TEST
);
647 glMatrixMode(GL_PROJECTION
);
650 glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
651 glMatrixMode(GL_MODELVIEW
);
653 glColor3f(0.0f
, 0.3f
, 1.0f
);
656 glEnable(GL_TEXTURE_2D
);
657 glBindTexture(GL_TEXTURE_2D
, checkid
);
658 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
661 glTexCoord2f(1.0f
, 0.0f
);
663 glTexCoord2f(1.0f
, 1.0f
);
664 glVertex2i(10 + 90, 30);
665 glTexCoord2f(0.0f
, 1.0f
);
666 glVertex2i(10 + 90, 30 + 90);
667 glTexCoord2f(0.0f
, 0.0f
);
668 glVertex2i(10, 30 + 90);
671 glDisable(GL_TEXTURE_2D
);
672 glBegin(GL_LINE_LOOP
);
674 glVertex2i(10 + 90, 30);
675 glVertex2i(10 + 90, 30 + 90);
676 glVertex2i(10, 30 + 90);
678 glRasterPos2i(105, 65);
679 printstring(GLUT_BITMAP_HELVETICA_18
, "Plane Texture Map");
682 if (showreflectmap
) {
683 glEnable(GL_TEXTURE_2D
);
684 glBindTexture(GL_TEXTURE_2D
, reflectid
);
685 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
688 glTexCoord2f(1.0f
, 0.0f
);
690 glTexCoord2f(1.0f
, 1.0f
);
691 glVertex2i(540 + 90, 30);
692 glTexCoord2f(0.0f
, 1.0f
);
693 glVertex2i(540 + 90, 30 + 90);
694 glTexCoord2f(0.0f
, 0.0f
);
695 glVertex2i(540, 30 + 90);
698 glDisable(GL_TEXTURE_2D
);
699 glBegin(GL_LINE_LOOP
);
701 glVertex2i(540 + 90, 30);
702 glVertex2i(540 + 90, 30 + 90);
703 glVertex2i(540, 30 + 90);
705 glRasterPos2i(360, 65);
706 printstring(GLUT_BITMAP_HELVETICA_18
, "Sphere Texture Map");
709 glDisable(GL_TEXTURE_2D
);
711 glRasterPos2i(10, 10);
712 printstring(GLUT_BITMAP_HELVETICA_18
, frbuf
);
713 glRasterPos2i(360, 470);
714 printstring(GLUT_BITMAP_HELVETICA_10
,
715 "Ray V1.0 Written by David Bucciarelli (tech.hmw@plus.it)");
720 glMatrixMode(GL_PROJECTION
);
722 glMatrixMode(GL_MODELVIEW
);
730 GLint t
= glutGet(GLUT_ELAPSED_TIME
);
731 if (t
- T0
>= 2000) {
732 GLfloat seconds
= (t
- T0
) / 1000.0;
733 GLfloat fps
= Frames
/ seconds
;
734 sprintf(frbuf
, "Frame rate: %f", fps
);
746 glGenTextures(1, &checkid
);
747 glBindTexture(GL_TEXTURE_2D
, checkid
);
749 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
750 glTexImage2D(GL_TEXTURE_2D
, 0, 3, TEX_CHECK_WIDTH
, TEX_CHECK_HEIGHT
,
751 0, GL_RGB
, GL_UNSIGNED_BYTE
, checkmap
);
753 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
754 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
756 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
757 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
759 for (y
= 0; y
< TEX_CHECK_NUMSLOT
; y
++)
764 glGenTextures(1, &reflectid
);
765 glBindTexture(GL_TEXTURE_2D
, reflectid
);
767 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
768 glTexImage2D(GL_TEXTURE_2D
, 0, 3, TEX_REFLECT_WIDTH
, TEX_REFLECT_HEIGHT
,
769 0, GL_RGB
, GL_UNSIGNED_BYTE
, reflectmap
);
771 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
772 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
774 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
775 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
777 for (y
= 0; y
< TEX_REFLECT_NUMSLOT
; y
++)
786 float alpha
, beta
, sa
, ca
, sb
, cb
;
789 for (y
= 0; y
< TEX_REFLECT_HEIGHT
; y
++) {
790 beta
= M_PI
- y
* (M_PI
/ TEX_REFLECT_HEIGHT
);
792 for (x
= 0; x
< TEX_REFLECT_WIDTH
; x
++) {
793 alpha
= -x
* (2.0f
* M_PI
/ TEX_REFLECT_WIDTH
);
801 sphere_pos
[y
][x
][0] = SPHERE_RADIUS
* sa
* sb
;
802 sphere_pos
[y
][x
][1] = SPHERE_RADIUS
* ca
* sb
;
803 sphere_pos
[y
][x
][2] = SPHERE_RADIUS
* cb
;
813 obj
= gluNewQuadric();
815 lightdlist
= glGenLists(1);
816 glNewList(lightdlist
, GL_COMPILE
);
817 gluQuadricDrawStyle(obj
, GLU_FILL
);
818 gluQuadricNormals(obj
, GLU_NONE
);
819 gluQuadricTexture(obj
, GL_TRUE
);
820 gluSphere(obj
, 0.25f
, 6, 6);
823 objdlist
= glGenLists(1);
824 glNewList(objdlist
, GL_COMPILE
);
825 gluQuadricDrawStyle(obj
, GLU_FILL
);
826 gluQuadricNormals(obj
, GLU_NONE
);
827 gluQuadricTexture(obj
, GL_TRUE
);
828 gluSphere(obj
, SPHERE_RADIUS
, 16, 16);
833 main(int ac
, char **av
)
836 "Ray V1.0\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
839 if(!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS)) {
840 fprintf(stderr,"Error setting the process class.\n");
844 if(!SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL)) {
845 fprintf(stderr,"Error setting the process priority.\n");
850 glutInitWindowPosition(0, 0);
851 glutInitWindowSize(WIDTH
, HEIGHT
);
854 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
856 if (!(win
= glutCreateWindow("Ray"))) {
857 fprintf(stderr
, "Error, couldn't open window\n");
861 reshape(WIDTH
, HEIGHT
);
863 glShadeModel(GL_FLAT
);
864 glEnable(GL_DEPTH_TEST
);
865 glDepthFunc(GL_LEQUAL
);
866 glEnable(GL_CULL_FACE
);
867 glEnable(GL_TEXTURE_2D
);
868 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
871 glFogi(GL_FOG_MODE
, GL_EXP2
);
872 glFogfv(GL_FOG_COLOR
, fogcolor
);
874 glFogf(GL_FOG_DENSITY
, 0.01);
876 glHint(GL_FOG_HINT
, GL_NICEST
);
886 glClearColor(fogcolor
[0], fogcolor
[1], fogcolor
[2], fogcolor
[3]);
888 glutReshapeFunc(reshape
);
889 glutDisplayFunc(draw
);
890 glutKeyboardFunc(key
);
891 glutSpecialFunc(special
);