2 * This program is under the GNU GPL.
3 * Use at your own risk.
5 * written by David Bucciarelli (tech.hmw@plus.it)
22 static int fullscreen = 1;
25 static int WIDTH = 640;
26 static int HEIGHT = 480;
29 static GLint Frames = 0;
32 #define SPHERE_RADIUS 0.75f
34 #define TEX_CHECK_WIDTH 256
35 #define TEX_CHECK_HEIGHT 256
36 #define TEX_CHECK_SLOT_SIZE (TEX_CHECK_HEIGHT/16)
37 #define TEX_CHECK_NUMSLOT (TEX_CHECK_HEIGHT/TEX_CHECK_SLOT_SIZE)
39 #define TEX_REFLECT_WIDTH 256
40 #define TEX_REFLECT_HEIGHT 256
41 #define TEX_REFLECT_SLOT_SIZE (TEX_REFLECT_HEIGHT/16)
42 #define TEX_REFLECT_NUMSLOT (TEX_REFLECT_HEIGHT/TEX_REFLECT_SLOT_SIZE)
45 #define M_PI 3.1415926535
48 #define EPSILON 0.0001
50 #define clamp255(a) ( (a)<(0.0f) ? (0.0f) : ((a)>(255.0f) ? (255.0f) : (a)) )
53 #define fabs(x) ((x)<0.0f?-(x):(x))
56 #define vequ(a,b) { (a)[0]=(b)[0]; (a)[1]=(b)[1]; (a)[2]=(b)[2]; }
57 #define vsub(a,b,c) { (a)[0]=(b)[0]-(c)[0]; (a)[1]=(b)[1]-(c)[1]; (a)[2]=(b)[2]-(c)[2]; }
58 #define dprod(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2])
59 #define vnormalize(a,b) { \
60 register float m_norm; \
61 m_norm=sqrt((double)dprod((a),(a))); \
66 static GLubyte checkmap[TEX_CHECK_HEIGHT][TEX_CHECK_WIDTH][3];
67 static GLuint checkid;
68 static int checkmap_currentslot = 0;
70 static GLubyte reflectmap[TEX_REFLECT_HEIGHT][TEX_REFLECT_WIDTH][3];
71 static GLuint reflectid;
72 static int reflectmap_currentslot = 0;
74 static GLuint lightdlist;
75 static GLuint objdlist;
77 static float lightpos[3] = { 2.1, 2.1, 2.8 };
78 static float objpos[3] = { 0.0, 0.0, 1.0 };
80 static float sphere_pos[TEX_CHECK_HEIGHT][TEX_REFLECT_WIDTH][3];
84 static float fogcolor[4] = { 0.05, 0.05, 0.05, 1.0 };
86 static float obs[3] = { 7.0, 0.0, 2.0 };
89 static float alpha = -90.0;
90 static float beta = 90.0;
93 static int bfcull = 1;
94 static int poutline = 0;
96 static int showcheckmap = 1;
97 static int showreflectmap = 1;
98 static int joyavailable = 0;
99 static int joyactive = 0;
104 dir[0] = sin(alpha * M_PI / 180.0);
105 dir[1] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
106 dir[2] = cos(beta * M_PI / 180.0);
108 if (dir[0] < 1.0e-5 && dir[0] > -1.0e-5)
110 if (dir[1] < 1.0e-5 && dir[1] > -1.0e-5)
112 if (dir[2] < 1.0e-5 && dir[2] > -1.0e-5)
115 obs[0] += v * dir[0];
116 obs[1] += v * dir[1];
117 obs[2] += v * dir[2];
121 special(int k, int x, int y)
140 key(unsigned char k, int x, int y)
193 joyactive = (!joyactive);
203 showcheckmap = (!showcheckmap);
206 showreflectmap = (!showreflectmap);
211 glDisable(GL_CULL_FACE);
215 glEnable(GL_CULL_FACE);
221 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
225 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
231 XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
232 fullscreen = (!fullscreen);
239 reshape(int w, int h)
243 glViewport(0, 0, w, h);
244 glMatrixMode(GL_PROJECTION);
246 gluPerspective(45.0, w / (float) h, 0.8, 40.0);
247 glMatrixMode(GL_MODELVIEW);
252 printstring(void *font, char *string)
256 len = (int) strlen(string);
257 for (i = 0; i < len; i++)
258 glutBitmapCharacter(font, string[i]);
265 glColor4f(0.5, 0.5, 0.5, 0.5);
266 glRecti(40, 40, 600, 440);
269 glColor3f(0.0, 0.0, 1.0);
270 glRasterPos2i(300, 420);
271 printstring(GLUT_BITMAP_HELVETICA_18, "Help");
273 glRasterPos2i(60, 390);
274 printstring(GLUT_BITMAP_HELVETICA_12, "h - Toggle Help");
275 glRasterPos2i(60, 370);
276 printstring(GLUT_BITMAP_HELVETICA_12, "f - Toggle Fog");
277 glRasterPos2i(60, 350);
278 printstring(GLUT_BITMAP_HELVETICA_12, "b - Toggle Back face culling");
279 glRasterPos2i(60, 330);
280 printstring(GLUT_BITMAP_HELVETICA_12, "p - Toggle Wire frame");
281 glRasterPos2i(60, 310);
282 printstring(GLUT_BITMAP_HELVETICA_12, "Arrow Keys - Rotate");
283 glRasterPos2i(60, 290);
284 printstring(GLUT_BITMAP_HELVETICA_12, "a - Increase velocity");
285 glRasterPos2i(60, 270);
286 printstring(GLUT_BITMAP_HELVETICA_12, "z - Decrease velocity");
288 glRasterPos2i(60, 250);
290 printstring(GLUT_BITMAP_HELVETICA_12,
291 "j - Toggle jostick control (Joystick control available)");
293 printstring(GLUT_BITMAP_HELVETICA_12,
294 "(No Joystick control available)");
296 glRasterPos2i(60, 230);
297 printstring(GLUT_BITMAP_HELVETICA_12,
298 "To move the light source: s - left, d - right, e - far, x - near, w - down r - up");
299 glRasterPos2i(60, 210);
300 printstring(GLUT_BITMAP_HELVETICA_12,
301 "To move the mirror sphere: j - left, k - right, i - far, m - near, u - down o - up");
303 glRasterPos2i(60, 190);
304 printstring(GLUT_BITMAP_HELVETICA_12,
305 "1 - Toggle the plane texture map window");
307 glRasterPos2i(60, 170);
308 printstring(GLUT_BITMAP_HELVETICA_12,
309 "2 - Toggle the sphere texture map window");
313 seelight(float p[3], float dir[3])
315 float c[3], b, a, d, t, dist[3];
319 a = dprod(c, c) - SPHERE_RADIUS * SPHERE_RADIUS;
321 if ((d = b * b - a) < 0.0 || (b < 0.0 && a > 0.0))
334 vsub(dist, lightpos, p);
335 if (dprod(dist, dist) < t * t)
342 colorcheckmap(float ppos[3], float c[3])
344 static float norm[3] = { 0.0f, 0.0f, 1.0f };
345 float ldir[3], vdir[3], h[3], dfact, kfact, r, g, b;
348 x = (int) ((ppos[0] + BASESIZE / 2) * (10.0f / BASESIZE));
349 if ((x < 0) || (x > 10))
352 y = (int) ((ppos[1] + BASESIZE / 2) * (10.0f / BASESIZE));
353 if ((y < 0) || (y > 10))
371 vsub(ldir, lightpos, ppos);
372 vnormalize(ldir, ldir);
374 if (seelight(ppos, ldir)) {
382 dfact = dprod(ldir, norm);
386 vsub(vdir, obs, ppos);
387 vnormalize(vdir, vdir);
388 h[0] = 0.5f * (vdir[0] + ldir[0]);
389 h[1] = 0.5f * (vdir[1] + ldir[1]);
390 h[2] = 0.5f * (vdir[2] + ldir[2]);
391 kfact = dprod(h, norm);
392 kfact = pow(kfact, 6.0) * 7.0 * 255.0;
394 r = r * dfact + kfact;
395 g = g * dfact + kfact;
396 b = b * dfact + kfact;
406 updatecheckmap(int slot)
411 glBindTexture(GL_TEXTURE_2D, checkid);
414 for (y = slot * TEX_CHECK_SLOT_SIZE; y < (slot + 1) * TEX_CHECK_SLOT_SIZE;
416 ppos[1] = (y / (float) TEX_CHECK_HEIGHT) * BASESIZE - BASESIZE / 2;
418 for (x = 0; x < TEX_CHECK_WIDTH; x++) {
419 ppos[0] = (x / (float) TEX_CHECK_WIDTH) * BASESIZE - BASESIZE / 2;
421 colorcheckmap(ppos, c);
422 checkmap[y][x][0] = (GLubyte) c[0];
423 checkmap[y][x][1] = (GLubyte) c[1];
424 checkmap[y][x][2] = (GLubyte) c[2];
428 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, slot * TEX_CHECK_SLOT_SIZE,
429 TEX_CHECK_WIDTH, TEX_CHECK_SLOT_SIZE, GL_RGB,
431 &checkmap[slot * TEX_CHECK_SLOT_SIZE][0][0]);
436 updatereflectmap(int slot)
438 float rf, r, g, b, t, dfact, kfact, rdir[3];
439 float rcol[3], ppos[3], norm[3], ldir[3], h[3], vdir[3], planepos[3];
442 glBindTexture(GL_TEXTURE_2D, reflectid);
444 for (y = slot * TEX_REFLECT_SLOT_SIZE;
445 y < (slot + 1) * TEX_REFLECT_SLOT_SIZE; y++)
446 for (x = 0; x < TEX_REFLECT_WIDTH; x++) {
447 ppos[0] = sphere_pos[y][x][0] + objpos[0];
448 ppos[1] = sphere_pos[y][x][1] + objpos[1];
449 ppos[2] = sphere_pos[y][x][2] + objpos[2];
451 vsub(norm, ppos, objpos);
452 vnormalize(norm, norm);
454 vsub(ldir, lightpos, ppos);
455 vnormalize(ldir, ldir);
456 vsub(vdir, obs, ppos);
457 vnormalize(vdir, vdir);
459 rf = 2.0f * dprod(norm, vdir);
461 rdir[0] = rf * norm[0] - vdir[0];
462 rdir[1] = rf * norm[1] - vdir[1];
463 rdir[2] = rf * norm[2] - vdir[2];
465 t = -objpos[2] / rdir[2];
468 planepos[0] = objpos[0] + t * rdir[0];
469 planepos[1] = objpos[1] + t * rdir[1];
472 if (!colorcheckmap(planepos, rcol))
473 rcol[0] = rcol[1] = rcol[2] = 0.0f;
476 rcol[0] = rcol[1] = rcol[2] = 0.0f;
479 rcol[0] = rcol[1] = rcol[2] = 0.0f;
481 dfact = 0.1f * dprod(ldir, norm);
488 h[0] = 0.5f * (vdir[0] + ldir[0]);
489 h[1] = 0.5f * (vdir[1] + ldir[1]);
490 h[2] = 0.5f * (vdir[2] + ldir[2]);
491 kfact = dprod(h, norm);
492 kfact = pow(kfact, 4.0);
513 reflectmap[y][x][0] = (GLubyte) r;
514 reflectmap[y][x][1] = (GLubyte) g;
515 reflectmap[y][x][2] = (GLubyte) b;
518 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, slot * TEX_REFLECT_SLOT_SIZE,
519 TEX_REFLECT_WIDTH, TEX_REFLECT_SLOT_SIZE, GL_RGB,
521 &reflectmap[slot * TEX_REFLECT_SLOT_SIZE][0][0]);
527 glColor3f(0.0, 0.0, 0.0);
528 glBindTexture(GL_TEXTURE_2D, checkid);
529 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
532 glTexCoord2f(0.0f, 0.0f);
533 glVertex3f(-BASESIZE / 2.0f, -BASESIZE / 2.0f, 0.0f);
535 glTexCoord2f(1.0f, 0.0f);
536 glVertex3f(BASESIZE / 2.0f, -BASESIZE / 2.0f, 0.0f);
538 glTexCoord2f(1.0f, 1.0f);
539 glVertex3f(BASESIZE / 2.0f, BASESIZE / 2.0f, 0.0f);
541 glTexCoord2f(0.0f, 1.0f);
542 glVertex3f(-BASESIZE / 2.0f, BASESIZE / 2.0f, 0.0f);
550 glColor3f(0.0, 0.0, 0.0);
551 glBindTexture(GL_TEXTURE_2D, reflectid);
552 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
555 glTranslatef(objpos[0], objpos[1], objpos[2]);
556 glCallList(objdlist);
564 static UINT max[2] = { 0, 0 };
565 static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
569 res = joyGetPos(JOYSTICKID1, &joy);
571 if (res == JOYERR_NOERROR) {
574 if (max[0] < joy.wXpos)
576 if (min[0] > joy.wXpos)
578 center[0] = (max[0] + min[0]) / 2;
580 if (max[1] < joy.wYpos)
582 if (min[1] > joy.wYpos)
584 center[1] = (max[1] + min[1]) / 2;
587 if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
589 2.5 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
590 if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
591 beta += 2.5 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
593 if (joy.wButtons & JOY_BUTTON1)
595 if (joy.wButtons & JOY_BUTTON2)
607 updatecheckmap(checkmap_currentslot);
608 checkmap_currentslot = (checkmap_currentslot + 1) % TEX_CHECK_NUMSLOT;
610 updatereflectmap(reflectmap_currentslot);
611 reflectmap_currentslot =
612 (reflectmap_currentslot + 1) % TEX_REFLECT_NUMSLOT;
618 static char frbuf[80] = "";
622 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
624 glEnable(GL_TEXTURE_2D);
625 glEnable(GL_DEPTH_TEST);
634 gluLookAt(obs[0], obs[1], obs[2],
635 obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
641 glColor3f(1.0, 1.0, 1.0);
642 glDisable(GL_TEXTURE_2D);
645 glTranslatef(lightpos[0], lightpos[1], lightpos[2]);
646 glCallList(lightdlist);
651 glDisable(GL_DEPTH_TEST);
654 glMatrixMode(GL_PROJECTION);
657 glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
658 glMatrixMode(GL_MODELVIEW);
660 glColor3f(0.0f, 0.3f, 1.0f);
663 glEnable(GL_TEXTURE_2D);
664 glBindTexture(GL_TEXTURE_2D, checkid);
665 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
668 glTexCoord2f(1.0f, 0.0f);
670 glTexCoord2f(1.0f, 1.0f);
671 glVertex2i(10 + 90, 30);
672 glTexCoord2f(0.0f, 1.0f);
673 glVertex2i(10 + 90, 30 + 90);
674 glTexCoord2f(0.0f, 0.0f);
675 glVertex2i(10, 30 + 90);
678 glDisable(GL_TEXTURE_2D);
679 glBegin(GL_LINE_LOOP);
681 glVertex2i(10 + 90, 30);
682 glVertex2i(10 + 90, 30 + 90);
683 glVertex2i(10, 30 + 90);
685 glRasterPos2i(105, 65);
686 printstring(GLUT_BITMAP_HELVETICA_18, "Plane Texture Map");
689 if (showreflectmap) {
690 glEnable(GL_TEXTURE_2D);
691 glBindTexture(GL_TEXTURE_2D, reflectid);
692 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
695 glTexCoord2f(1.0f, 0.0f);
697 glTexCoord2f(1.0f, 1.0f);
698 glVertex2i(540 + 90, 30);
699 glTexCoord2f(0.0f, 1.0f);
700 glVertex2i(540 + 90, 30 + 90);
701 glTexCoord2f(0.0f, 0.0f);
702 glVertex2i(540, 30 + 90);
705 glDisable(GL_TEXTURE_2D);
706 glBegin(GL_LINE_LOOP);
708 glVertex2i(540 + 90, 30);
709 glVertex2i(540 + 90, 30 + 90);
710 glVertex2i(540, 30 + 90);
712 glRasterPos2i(360, 65);
713 printstring(GLUT_BITMAP_HELVETICA_18, "Sphere Texture Map");
716 glDisable(GL_TEXTURE_2D);
718 glRasterPos2i(10, 10);
719 printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
720 glRasterPos2i(360, 470);
721 printstring(GLUT_BITMAP_HELVETICA_10,
722 "Ray V1.0 Written by David Bucciarelli (tech.hmw@plus.it)");
727 glMatrixMode(GL_PROJECTION);
729 glMatrixMode(GL_MODELVIEW);
737 GLint t = glutGet(GLUT_ELAPSED_TIME);
738 if (t - T0 >= 2000) {
739 GLfloat seconds = (t - T0) / 1000.0;
740 GLfloat fps = Frames / seconds;
741 sprintf(frbuf, "Frame rate: %f", fps);
753 glGenTextures(1, &checkid);
754 glBindTexture(GL_TEXTURE_2D, checkid);
756 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
757 glTexImage2D(GL_TEXTURE_2D, 0, 3, TEX_CHECK_WIDTH, TEX_CHECK_HEIGHT,
758 0, GL_RGB, GL_UNSIGNED_BYTE, checkmap);
760 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
761 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
763 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
764 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
766 for (y = 0; y < TEX_CHECK_NUMSLOT; y++)
771 glGenTextures(1, &reflectid);
772 glBindTexture(GL_TEXTURE_2D, reflectid);
774 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
775 glTexImage2D(GL_TEXTURE_2D, 0, 3, TEX_REFLECT_WIDTH, TEX_REFLECT_HEIGHT,
776 0, GL_RGB, GL_UNSIGNED_BYTE, reflectmap);
778 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
779 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
781 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
782 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
784 for (y = 0; y < TEX_REFLECT_NUMSLOT; y++)
793 float alpha, beta, sa, ca, sb, cb;
796 for (y = 0; y < TEX_REFLECT_HEIGHT; y++) {
797 beta = M_PI - y * (M_PI / TEX_REFLECT_HEIGHT);
799 for (x = 0; x < TEX_REFLECT_WIDTH; x++) {
800 alpha = -x * (2.0f * M_PI / TEX_REFLECT_WIDTH);
808 sphere_pos[y][x][0] = SPHERE_RADIUS * sa * sb;
809 sphere_pos[y][x][1] = SPHERE_RADIUS * ca * sb;
810 sphere_pos[y][x][2] = SPHERE_RADIUS * cb;
820 obj = gluNewQuadric();
822 lightdlist = glGenLists(1);
823 glNewList(lightdlist, GL_COMPILE);
824 gluQuadricDrawStyle(obj, GLU_FILL);
825 gluQuadricNormals(obj, GLU_NONE);
826 gluQuadricTexture(obj, GL_TRUE);
827 gluSphere(obj, 0.25f, 6, 6);
830 objdlist = glGenLists(1);
831 glNewList(objdlist, GL_COMPILE);
832 gluQuadricDrawStyle(obj, GLU_FILL);
833 gluQuadricNormals(obj, GLU_NONE);
834 gluQuadricTexture(obj, GL_TRUE);
835 gluSphere(obj, SPHERE_RADIUS, 16, 16);
840 main(int ac, char **av)
843 "Ray V1.0\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
846 if(!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS)) {
847 fprintf(stderr,"Error setting the process class.\n");
851 if(!SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL)) {
852 fprintf(stderr,"Error setting the process priority.\n");
857 glutInitWindowPosition(0, 0);
858 glutInitWindowSize(WIDTH, HEIGHT);
861 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
863 if (!(win = glutCreateWindow("Ray"))) {
864 fprintf(stderr, "Error, couldn't open window\n");
868 reshape(WIDTH, HEIGHT);
870 glShadeModel(GL_FLAT);
871 glEnable(GL_DEPTH_TEST);
872 glDepthFunc(GL_LEQUAL);
873 glEnable(GL_CULL_FACE);
874 glEnable(GL_TEXTURE_2D);
875 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
878 glFogi(GL_FOG_MODE, GL_EXP2);
879 glFogfv(GL_FOG_COLOR, fogcolor);
881 glFogf(GL_FOG_DENSITY, 0.01);
883 glHint(GL_FOG_HINT, GL_NICEST);
893 glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
895 glutReshapeFunc(reshape);
896 glutDisplayFunc(draw);
897 glutKeyboardFunc(key);
898 glutSpecialFunc(special);