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;
30 #define SPHERE_RADIUS 0.75f
32 #define TEX_CHECK_WIDTH 256
33 #define TEX_CHECK_HEIGHT 256
34 #define TEX_CHECK_SLOT_SIZE (TEX_CHECK_HEIGHT/16)
35 #define TEX_CHECK_NUMSLOT (TEX_CHECK_HEIGHT/TEX_CHECK_SLOT_SIZE)
37 #define TEX_REFLECT_WIDTH 256
38 #define TEX_REFLECT_HEIGHT 256
39 #define TEX_REFLECT_SLOT_SIZE (TEX_REFLECT_HEIGHT/16)
40 #define TEX_REFLECT_NUMSLOT (TEX_REFLECT_HEIGHT/TEX_REFLECT_SLOT_SIZE)
43 #define M_PI 3.1415926535
46 #define EPSILON 0.0001
48 #define clamp255(a) ( (a)<(0.0f) ? (0.0f) : ((a)>(255.0f) ? (255.0f) : (a)) )
50 #define fabs(x) ((x)<0.0f?-(x):(x))
52 #define vequ(a,b) { (a)[0]=(b)[0]; (a)[1]=(b)[1]; (a)[2]=(b)[2]; }
53 #define vsub(a,b,c) { (a)[0]=(b)[0]-(c)[0]; (a)[1]=(b)[1]-(c)[1]; (a)[2]=(b)[2]-(c)[2]; }
54 #define dprod(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2])
55 #define vnormalize(a,b) { \
56 register float m_norm; \
57 m_norm=sqrt((double)dprod((a),(a))); \
62 static GLubyte checkmap
[TEX_CHECK_HEIGHT
][TEX_CHECK_WIDTH
][3];
63 static GLuint checkid
;
64 static int checkmap_currentslot
= 0;
66 static GLubyte reflectmap
[TEX_REFLECT_HEIGHT
][TEX_REFLECT_WIDTH
][3];
67 static GLuint reflectid
;
68 static int reflectmap_currentslot
= 0;
70 static GLuint lightdlist
;
71 static GLuint objdlist
;
73 static float lightpos
[3] = { 2.1, 2.1, 2.8 };
74 static float objpos
[3] = { 0.0, 0.0, 1.0 };
76 static float sphere_pos
[TEX_CHECK_HEIGHT
][TEX_REFLECT_WIDTH
][3];
80 static float fogcolor
[4] = { 0.05, 0.05, 0.05, 1.0 };
82 static float obs
[3] = { 7.0, 0.0, 2.0 };
85 static float alpha
= -90.0;
86 static float beta
= 90.0;
89 static int bfcull
= 1;
90 static int poutline
= 0;
92 static int showcheckmap
= 1;
93 static int showreflectmap
= 1;
94 static int joyavailable
= 0;
95 static int joyactive
= 0;
100 static float told
= 0.0f
;
103 tnew
= glutGet(GLUT_ELAPSED_TIME
);
115 dir
[0] = sin(alpha
* M_PI
/ 180.0);
116 dir
[1] = cos(alpha
* M_PI
/ 180.0) * sin(beta
* M_PI
/ 180.0);
117 dir
[2] = cos(beta
* M_PI
/ 180.0);
119 obs
[0] += v
* dir
[0];
120 obs
[1] += v
* dir
[1];
121 obs
[2] += v
* dir
[2];
125 special(int k
, int x
, int y
)
144 key(unsigned char k
, int x
, int y
)
197 joyactive
= (!joyactive
);
207 showcheckmap
= (!showcheckmap
);
210 showreflectmap
= (!showreflectmap
);
215 glDisable(GL_CULL_FACE
);
219 glEnable(GL_CULL_FACE
);
225 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
229 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
235 XMesaSetFXmode(fullscreen
? XMESA_FX_FULLSCREEN
: XMESA_FX_WINDOW
);
236 fullscreen
= (!fullscreen
);
243 reshape(int w
, int h
)
247 glViewport(0, 0, w
, h
);
248 glMatrixMode(GL_PROJECTION
);
250 gluPerspective(45.0, w
/ (float) h
, 0.8, 40.0);
251 glMatrixMode(GL_MODELVIEW
);
256 printstring(void *font
, char *string
)
260 len
= (int) strlen(string
);
261 for (i
= 0; i
< len
; i
++)
262 glutBitmapCharacter(font
, string
[i
]);
269 glColor4f(0.5, 0.5, 0.5, 0.5);
270 glRecti(40, 40, 600, 440);
273 glColor3f(0.0, 0.0, 1.0);
274 glRasterPos2i(300, 420);
275 printstring(GLUT_BITMAP_HELVETICA_18
, "Help");
277 glRasterPos2i(60, 390);
278 printstring(GLUT_BITMAP_HELVETICA_12
, "h - Togle Help");
279 glRasterPos2i(60, 370);
280 printstring(GLUT_BITMAP_HELVETICA_12
, "f - Togle Fog");
281 glRasterPos2i(60, 350);
282 printstring(GLUT_BITMAP_HELVETICA_12
, "b - Togle Back face culling");
283 glRasterPos2i(60, 330);
284 printstring(GLUT_BITMAP_HELVETICA_12
, "p - Togle Wire frame");
285 glRasterPos2i(60, 310);
286 printstring(GLUT_BITMAP_HELVETICA_12
, "Arrow Keys - Rotate");
287 glRasterPos2i(60, 290);
288 printstring(GLUT_BITMAP_HELVETICA_12
, "a - Increase velocity");
289 glRasterPos2i(60, 270);
290 printstring(GLUT_BITMAP_HELVETICA_12
, "z - Decrease velocity");
292 glRasterPos2i(60, 250);
294 printstring(GLUT_BITMAP_HELVETICA_12
,
295 "j - Togle jostick control (Joystick control available)");
297 printstring(GLUT_BITMAP_HELVETICA_12
,
298 "(No Joystick control available)");
300 glRasterPos2i(60, 230);
301 printstring(GLUT_BITMAP_HELVETICA_12
,
302 "To move the light source: s - left, d - right, e - far, x - near, w - down r - up");
303 glRasterPos2i(60, 210);
304 printstring(GLUT_BITMAP_HELVETICA_12
,
305 "To move the mirror sphere: j - left, k - right, i - far, m - near, u - down o - up");
307 glRasterPos2i(60, 190);
308 printstring(GLUT_BITMAP_HELVETICA_12
,
309 "1 - Togle the plane texture map window");
311 glRasterPos2i(60, 170);
312 printstring(GLUT_BITMAP_HELVETICA_12
,
313 "2 - Togle the sphere texture map window");
317 seelight(float p
[3], float dir
[3])
319 float c
[3], b
, a
, d
, t
, dist
[3];
323 a
= dprod(c
, c
) - SPHERE_RADIUS
* SPHERE_RADIUS
;
325 if ((d
= b
* b
- a
) < 0.0 || (b
< 0.0 && a
> 0.0))
338 vsub(dist
, lightpos
, p
);
339 if (dprod(dist
, dist
) < t
* t
)
346 colorcheckmap(float ppos
[3], float c
[3])
348 static float norm
[3] = { 0.0f
, 0.0f
, 1.0f
};
349 float ldir
[3], vdir
[3], h
[3], dfact
, kfact
, r
, g
, b
;
352 x
= (int) ((ppos
[0] + BASESIZE
/ 2) * (10.0f
/ BASESIZE
));
353 if ((x
< 0) || (x
> 10))
356 y
= (int) ((ppos
[1] + BASESIZE
/ 2) * (10.0f
/ BASESIZE
));
357 if ((y
< 0) || (y
> 10))
375 vsub(ldir
, lightpos
, ppos
);
376 vnormalize(ldir
, ldir
);
378 if (seelight(ppos
, ldir
)) {
386 dfact
= dprod(ldir
, norm
);
390 vsub(vdir
, obs
, ppos
);
391 vnormalize(vdir
, vdir
);
392 h
[0] = 0.5f
* (vdir
[0] + ldir
[0]);
393 h
[1] = 0.5f
* (vdir
[1] + ldir
[1]);
394 h
[2] = 0.5f
* (vdir
[2] + ldir
[2]);
395 kfact
= dprod(h
, norm
);
397 kfact
* kfact
* kfact
* kfact
* kfact
* kfact
* kfact
* 7.0f
* 255.0f
;
399 r
= r
* dfact
+ kfact
;
400 g
= g
* dfact
+ kfact
;
401 b
= b
* dfact
+ kfact
;
411 updatecheckmap(int slot
)
416 glBindTexture(GL_TEXTURE_2D
, checkid
);
419 for (y
= slot
* TEX_CHECK_SLOT_SIZE
; y
< (slot
+ 1) * TEX_CHECK_SLOT_SIZE
;
421 ppos
[1] = (y
/ (float) TEX_CHECK_HEIGHT
) * BASESIZE
- BASESIZE
/ 2;
423 for (x
= 0; x
< TEX_CHECK_WIDTH
; x
++) {
424 ppos
[0] = (x
/ (float) TEX_CHECK_WIDTH
) * BASESIZE
- BASESIZE
/ 2;
426 colorcheckmap(ppos
, c
);
427 checkmap
[y
][x
][0] = (GLubyte
) c
[0];
428 checkmap
[y
][x
][1] = (GLubyte
) c
[1];
429 checkmap
[y
][x
][2] = (GLubyte
) c
[2];
433 glTexSubImage2D(GL_TEXTURE_2D
, 0, 0, slot
* TEX_CHECK_SLOT_SIZE
,
434 TEX_CHECK_WIDTH
, TEX_CHECK_SLOT_SIZE
, GL_RGB
,
436 &checkmap
[slot
* TEX_CHECK_SLOT_SIZE
][0][0]);
441 updatereflectmap(int slot
)
443 float rf
, r
, g
, b
, t
, dfact
, kfact
, rdir
[3];
444 float rcol
[3], ppos
[3], norm
[3], ldir
[3], h
[3], vdir
[3], planepos
[3];
447 glBindTexture(GL_TEXTURE_2D
, reflectid
);
449 for (y
= slot
* TEX_REFLECT_SLOT_SIZE
;
450 y
< (slot
+ 1) * TEX_REFLECT_SLOT_SIZE
; y
++)
451 for (x
= 0; x
< TEX_REFLECT_WIDTH
; x
++) {
452 ppos
[0] = sphere_pos
[y
][x
][0] + objpos
[0];
453 ppos
[1] = sphere_pos
[y
][x
][1] + objpos
[1];
454 ppos
[2] = sphere_pos
[y
][x
][2] + objpos
[2];
456 vsub(norm
, ppos
, objpos
);
457 vnormalize(norm
, norm
);
459 vsub(ldir
, lightpos
, ppos
);
460 vnormalize(ldir
, ldir
);
461 vsub(vdir
, obs
, ppos
);
462 vnormalize(vdir
, vdir
);
464 rf
= 2.0f
* dprod(norm
, vdir
);
466 rdir
[0] = rf
* norm
[0] - vdir
[0];
467 rdir
[1] = rf
* norm
[1] - vdir
[1];
468 rdir
[2] = rf
* norm
[2] - vdir
[2];
470 t
= -objpos
[2] / rdir
[2];
473 planepos
[0] = objpos
[0] + t
* rdir
[0];
474 planepos
[1] = objpos
[1] + t
* rdir
[1];
477 if (!colorcheckmap(planepos
, rcol
))
478 rcol
[0] = rcol
[1] = rcol
[2] = 0.0f
;
481 rcol
[0] = rcol
[1] = rcol
[2] = 0.0f
;
484 rcol
[0] = rcol
[1] = rcol
[2] = 0.0f
;
486 dfact
= 0.1f
* dprod(ldir
, norm
);
493 h
[0] = 0.5f
* (vdir
[0] + ldir
[0]);
494 h
[1] = 0.5f
* (vdir
[1] + ldir
[1]);
495 h
[2] = 0.5f
* (vdir
[2] + ldir
[2]);
496 kfact
= dprod(h
, norm
);
520 reflectmap
[y
][x
][0] = (GLubyte
) r
;
521 reflectmap
[y
][x
][1] = (GLubyte
) g
;
522 reflectmap
[y
][x
][2] = (GLubyte
) b
;
525 glTexSubImage2D(GL_TEXTURE_2D
, 0, 0, slot
* TEX_REFLECT_SLOT_SIZE
,
526 TEX_REFLECT_WIDTH
, TEX_REFLECT_SLOT_SIZE
, GL_RGB
,
528 &reflectmap
[slot
* TEX_REFLECT_SLOT_SIZE
][0][0]);
534 glColor3f(0.0, 0.0, 0.0);
535 glBindTexture(GL_TEXTURE_2D
, checkid
);
536 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
539 glTexCoord2f(0.0f
, 0.0f
);
540 glVertex3f(-BASESIZE
/ 2.0f
, -BASESIZE
/ 2.0f
, 0.0f
);
542 glTexCoord2f(1.0f
, 0.0f
);
543 glVertex3f(BASESIZE
/ 2.0f
, -BASESIZE
/ 2.0f
, 0.0f
);
545 glTexCoord2f(1.0f
, 1.0f
);
546 glVertex3f(BASESIZE
/ 2.0f
, BASESIZE
/ 2.0f
, 0.0f
);
548 glTexCoord2f(0.0f
, 1.0f
);
549 glVertex3f(-BASESIZE
/ 2.0f
, BASESIZE
/ 2.0f
, 0.0f
);
557 glColor3f(0.0, 0.0, 0.0);
558 glBindTexture(GL_TEXTURE_2D
, reflectid
);
559 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
562 glTranslatef(objpos
[0], objpos
[1], objpos
[2]);
563 glCallList(objdlist
);
571 static UINT max
[2] = { 0, 0 };
572 static UINT min
[2] = { 0xffffffff, 0xffffffff }, center
[2];
576 res
= joyGetPos(JOYSTICKID1
, &joy
);
578 if (res
== JOYERR_NOERROR
) {
581 if (max
[0] < joy
.wXpos
)
583 if (min
[0] > joy
.wXpos
)
585 center
[0] = (max
[0] + min
[0]) / 2;
587 if (max
[1] < joy
.wYpos
)
589 if (min
[1] > joy
.wYpos
)
591 center
[1] = (max
[1] + min
[1]) / 2;
594 if (fabs(center
[0] - (float) joy
.wXpos
) > 0.1 * (max
[0] - min
[0]))
596 2.5 * (center
[0] - (float) joy
.wXpos
) / (max
[0] - min
[0]);
597 if (fabs(center
[1] - (float) joy
.wYpos
) > 0.1 * (max
[1] - min
[1]))
598 beta
+= 2.5 * (center
[1] - (float) joy
.wYpos
) / (max
[1] - min
[1]);
600 if (joy
.wButtons
& JOY_BUTTON1
)
602 if (joy
.wButtons
& JOY_BUTTON2
)
614 updatecheckmap(checkmap_currentslot
);
615 checkmap_currentslot
= (checkmap_currentslot
+ 1) % TEX_CHECK_NUMSLOT
;
617 updatereflectmap(reflectmap_currentslot
);
618 reflectmap_currentslot
=
619 (reflectmap_currentslot
+ 1) % TEX_REFLECT_NUMSLOT
;
625 static int count
= 0;
626 static char frbuf
[80];
631 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
633 glEnable(GL_TEXTURE_2D
);
634 glEnable(GL_DEPTH_TEST
);
643 gluLookAt(obs
[0], obs
[1], obs
[2],
644 obs
[0] + dir
[0], obs
[1] + dir
[1], obs
[2] + dir
[2],
650 glColor3f(1.0, 1.0, 1.0);
651 glDisable(GL_TEXTURE_2D
);
654 glTranslatef(lightpos
[0], lightpos
[1], lightpos
[2]);
655 glCallList(lightdlist
);
660 if ((count
% FRAME
) == 0) {
662 sprintf(frbuf
, "Frame rate: %f", FRAME
/ fr
);
665 glDisable(GL_DEPTH_TEST
);
668 glMatrixMode(GL_PROJECTION
);
671 glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
672 glMatrixMode(GL_MODELVIEW
);
674 glColor3f(0.0f
, 0.3f
, 1.0f
);
677 glEnable(GL_TEXTURE_2D
);
678 glBindTexture(GL_TEXTURE_2D
, checkid
);
679 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
682 glTexCoord2f(1.0f
, 0.0f
);
684 glTexCoord2f(1.0f
, 1.0f
);
685 glVertex2i(10 + 90, 30);
686 glTexCoord2f(0.0f
, 1.0f
);
687 glVertex2i(10 + 90, 30 + 90);
688 glTexCoord2f(0.0f
, 0.0f
);
689 glVertex2i(10, 30 + 90);
692 glDisable(GL_TEXTURE_2D
);
693 glBegin(GL_LINE_LOOP
);
695 glVertex2i(10 + 90, 30);
696 glVertex2i(10 + 90, 30 + 90);
697 glVertex2i(10, 30 + 90);
699 glRasterPos2i(105, 65);
700 printstring(GLUT_BITMAP_HELVETICA_18
, "Plane Texture Map");
703 if (showreflectmap
) {
704 glEnable(GL_TEXTURE_2D
);
705 glBindTexture(GL_TEXTURE_2D
, reflectid
);
706 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
709 glTexCoord2f(1.0f
, 0.0f
);
711 glTexCoord2f(1.0f
, 1.0f
);
712 glVertex2i(540 + 90, 30);
713 glTexCoord2f(0.0f
, 1.0f
);
714 glVertex2i(540 + 90, 30 + 90);
715 glTexCoord2f(0.0f
, 0.0f
);
716 glVertex2i(540, 30 + 90);
719 glDisable(GL_TEXTURE_2D
);
720 glBegin(GL_LINE_LOOP
);
722 glVertex2i(540 + 90, 30);
723 glVertex2i(540 + 90, 30 + 90);
724 glVertex2i(540, 30 + 90);
726 glRasterPos2i(360, 65);
727 printstring(GLUT_BITMAP_HELVETICA_18
, "Sphere Texture Map");
730 glDisable(GL_TEXTURE_2D
);
732 glRasterPos2i(10, 10);
733 printstring(GLUT_BITMAP_HELVETICA_18
, frbuf
);
734 glRasterPos2i(360, 470);
735 printstring(GLUT_BITMAP_HELVETICA_10
,
736 "Ray V1.0 Written by David Bucciarelli (tech.hmw@plus.it)");
741 glMatrixMode(GL_PROJECTION
);
743 glMatrixMode(GL_MODELVIEW
);
757 glGenTextures(1, &checkid
);
758 glBindTexture(GL_TEXTURE_2D
, checkid
);
760 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
761 glTexImage2D(GL_TEXTURE_2D
, 0, 3, TEX_CHECK_WIDTH
, TEX_CHECK_HEIGHT
,
762 0, GL_RGB
, GL_UNSIGNED_BYTE
, checkmap
);
764 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
765 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
767 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
768 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
770 for (y
= 0; y
< TEX_CHECK_NUMSLOT
; y
++)
775 glGenTextures(1, &reflectid
);
776 glBindTexture(GL_TEXTURE_2D
, reflectid
);
778 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
779 glTexImage2D(GL_TEXTURE_2D
, 0, 3, TEX_REFLECT_WIDTH
, TEX_REFLECT_HEIGHT
,
780 0, GL_RGB
, GL_UNSIGNED_BYTE
, reflectmap
);
782 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
783 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
785 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
786 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
788 for (y
= 0; y
< TEX_REFLECT_NUMSLOT
; y
++)
797 float alpha
, beta
, sa
, ca
, sb
, cb
;
800 for (y
= 0; y
< TEX_REFLECT_HEIGHT
; y
++) {
801 beta
= M_PI
- y
* (M_PI
/ TEX_REFLECT_HEIGHT
);
803 for (x
= 0; x
< TEX_REFLECT_WIDTH
; x
++) {
804 alpha
= -x
* (2.0f
* M_PI
/ TEX_REFLECT_WIDTH
);
812 sphere_pos
[y
][x
][0] = SPHERE_RADIUS
* sa
* sb
;
813 sphere_pos
[y
][x
][1] = SPHERE_RADIUS
* ca
* sb
;
814 sphere_pos
[y
][x
][2] = SPHERE_RADIUS
* cb
;
824 obj
= gluNewQuadric();
826 lightdlist
= glGenLists(1);
827 glNewList(lightdlist
, GL_COMPILE
);
828 gluQuadricDrawStyle(obj
, GLU_FILL
);
829 gluQuadricNormals(obj
, GLU_NONE
);
830 gluQuadricTexture(obj
, GL_TRUE
);
831 gluSphere(obj
, 0.25f
, 6, 6);
834 objdlist
= glGenLists(1);
835 glNewList(objdlist
, GL_COMPILE
);
836 gluQuadricDrawStyle(obj
, GLU_FILL
);
837 gluQuadricNormals(obj
, GLU_NONE
);
838 gluQuadricTexture(obj
, GL_TRUE
);
839 gluSphere(obj
, SPHERE_RADIUS
, 16, 16);
844 main(int ac
, char **av
)
847 "Ray V1.0\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
850 if(!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS)) {
851 fprintf(stderr,"Error setting the process class.\n");
855 if(!SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL)) {
856 fprintf(stderr,"Error setting the process priority.\n");
861 glutInitWindowPosition(0, 0);
862 glutInitWindowSize(WIDTH
, HEIGHT
);
865 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
867 if (!(win
= glutCreateWindow("Ray"))) {
868 fprintf(stderr
, "Error, couldn't open window\n");
872 reshape(WIDTH
, HEIGHT
);
874 glShadeModel(GL_FLAT
);
875 glEnable(GL_DEPTH_TEST
);
876 glDepthFunc(GL_LEQUAL
);
877 glEnable(GL_CULL_FACE
);
878 glEnable(GL_TEXTURE_2D
);
879 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
882 glFogi(GL_FOG_MODE
, GL_EXP2
);
883 glFogfv(GL_FOG_COLOR
, fogcolor
);
885 glFogf(GL_FOG_DENSITY
, 0.01);
887 glHint(GL_FOG_HINT
, GL_NICEST
);
897 glClearColor(fogcolor
[0], fogcolor
[1], fogcolor
[2], fogcolor
[3]);
899 glutReshapeFunc(reshape
);
900 glutDisplayFunc(draw
);
901 glutKeyboardFunc(key
);
902 glutSpecialFunc(special
);