ray.c revision 32001f49
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 <string.h>
12#include <math.h>
13
14#ifdef WIN32
15#include <windows.h>
16#endif
17
18#include "glut_wrap.h"
19
20#ifdef XMESA
21#include "GL/xmesa.h"
22static int fullscreen = 1;
23#endif
24
25static int WIDTH = 640;
26static int HEIGHT = 480;
27
28static GLint T0 = 0;
29static GLint Frames = 0;
30
31#define BASESIZE 7.5f
32#define SPHERE_RADIUS 0.75f
33
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)
38
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)
43
44#ifndef M_PI
45#define M_PI 3.1415926535
46#endif
47
48#define EPSILON 0.0001
49
50#define clamp255(a)  ( (a)<(0.0f) ? (0.0f) : ((a)>(255.0f) ? (255.0f) : (a)) )
51
52#ifndef fabs
53#define fabs(x) ((x)<0.0f?-(x):(x))
54#endif
55
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))); \
62  (a)[0] /=m_norm; \
63  (a)[1] /=m_norm; \
64  (a)[2] /=m_norm; }
65
66static GLubyte checkmap[TEX_CHECK_HEIGHT][TEX_CHECK_WIDTH][3];
67static GLuint checkid;
68static int checkmap_currentslot = 0;
69
70static GLubyte reflectmap[TEX_REFLECT_HEIGHT][TEX_REFLECT_WIDTH][3];
71static GLuint reflectid;
72static int reflectmap_currentslot = 0;
73
74static GLuint lightdlist;
75static GLuint objdlist;
76
77static float lightpos[3] = { 2.1, 2.1, 2.8 };
78static float objpos[3] = { 0.0, 0.0, 1.0 };
79
80static float sphere_pos[TEX_CHECK_HEIGHT][TEX_REFLECT_WIDTH][3];
81
82static int win = 0;
83
84static float fogcolor[4] = { 0.05, 0.05, 0.05, 1.0 };
85
86static float obs[3] = { 7.0, 0.0, 2.0 };
87static float dir[3];
88static float v = 0.0;
89static float alpha = -90.0;
90static float beta = 90.0;
91
92static int fog = 1;
93static int bfcull = 1;
94static int poutline = 0;
95static int help = 1;
96static int showcheckmap = 1;
97static int showreflectmap = 1;
98static int joyavailable = 0;
99static int joyactive = 0;
100
101static void
102calcposobs(void)
103{
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);
107
108   if (dir[0] < 1.0e-5 && dir[0] > -1.0e-5)
109      dir[0] = 0;
110   if (dir[1] < 1.0e-5 && dir[1] > -1.0e-5)
111      dir[1] = 0;
112   if (dir[2] < 1.0e-5 && dir[2] > -1.0e-5)
113      dir[2] = 0;
114
115   obs[0] += v * dir[0];
116   obs[1] += v * dir[1];
117   obs[2] += v * dir[2];
118}
119
120static void
121special(int k, int x, int y)
122{
123   switch (k) {
124   case GLUT_KEY_LEFT:
125      alpha -= 2.0;
126      break;
127   case GLUT_KEY_RIGHT:
128      alpha += 2.0;
129      break;
130   case GLUT_KEY_DOWN:
131      beta -= 2.0;
132      break;
133   case GLUT_KEY_UP:
134      beta += 2.0;
135      break;
136   }
137}
138
139static void
140key(unsigned char k, int x, int y)
141{
142   switch (k) {
143   case 27:
144      exit(0);
145      break;
146
147   case 's':
148      lightpos[1] -= 0.1;
149      break;
150   case 'd':
151      lightpos[1] += 0.1;
152      break;
153   case 'e':
154      lightpos[0] -= 0.1;
155      break;
156   case 'x':
157      lightpos[0] += 0.1;
158      break;
159   case 'w':
160      lightpos[2] -= 0.1;
161      break;
162   case 'r':
163      lightpos[2] += 0.1;
164      break;
165
166   case 'j':
167      objpos[1] -= 0.1;
168      break;
169   case 'k':
170      objpos[1] += 0.1;
171      break;
172   case 'i':
173      objpos[0] -= 0.1;
174      break;
175   case 'm':
176      objpos[0] += 0.1;
177      break;
178   case 'u':
179      objpos[2] -= 0.1;
180      break;
181   case 'o':
182      objpos[2] += 0.1;
183      break;
184
185   case 'a':
186      v += 0.005;
187      break;
188   case 'z':
189      v -= 0.005;
190      break;
191
192   case 'g':
193      joyactive = (!joyactive);
194      break;
195   case 'h':
196      help = (!help);
197      break;
198   case 'f':
199      fog = (!fog);
200      break;
201
202   case '1':
203      showcheckmap = (!showcheckmap);
204      break;
205   case '2':
206      showreflectmap = (!showreflectmap);
207      break;
208
209   case 'b':
210      if (bfcull) {
211	 glDisable(GL_CULL_FACE);
212	 bfcull = 0;
213      }
214      else {
215	 glEnable(GL_CULL_FACE);
216	 bfcull = 1;
217      }
218      break;
219   case 'p':
220      if (poutline) {
221	 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
222	 poutline = 0;
223      }
224      else {
225	 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
226	 poutline = 1;
227      }
228      break;
229#ifdef XMESA
230   case ' ':
231      XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
232      fullscreen = (!fullscreen);
233      break;
234#endif
235   }
236}
237
238static void
239reshape(int w, int h)
240{
241   WIDTH = w;
242   HEIGHT = h;
243   glViewport(0, 0, w, h);
244   glMatrixMode(GL_PROJECTION);
245   glLoadIdentity();
246   gluPerspective(45.0, w / (float) h, 0.8, 40.0);
247   glMatrixMode(GL_MODELVIEW);
248   glLoadIdentity();
249}
250
251static void
252printstring(void *font, char *string)
253{
254   int len, i;
255
256   len = (int) strlen(string);
257   for (i = 0; i < len; i++)
258      glutBitmapCharacter(font, string[i]);
259}
260
261static void
262printhelp(void)
263{
264   glEnable(GL_BLEND);
265   glColor4f(0.5, 0.5, 0.5, 0.5);
266   glRecti(40, 40, 600, 440);
267   glDisable(GL_BLEND);
268
269   glColor3f(0.0, 0.0, 1.0);
270   glRasterPos2i(300, 420);
271   printstring(GLUT_BITMAP_HELVETICA_18, "Help");
272
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");
287
288   glRasterPos2i(60, 250);
289   if (joyavailable)
290      printstring(GLUT_BITMAP_HELVETICA_12,
291		  "j - Toggle jostick control (Joystick control available)");
292   else
293      printstring(GLUT_BITMAP_HELVETICA_12,
294		  "(No Joystick control available)");
295
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");
302
303   glRasterPos2i(60, 190);
304   printstring(GLUT_BITMAP_HELVETICA_12,
305	       "1 - Toggle the plane texture map window");
306
307   glRasterPos2i(60, 170);
308   printstring(GLUT_BITMAP_HELVETICA_12,
309	       "2 - Toggle the sphere texture map window");
310}
311
312static GLboolean
313seelight(float p[3], float dir[3])
314{
315   float c[3], b, a, d, t, dist[3];
316
317   vsub(c, p, objpos);
318   b = -dprod(c, dir);
319   a = dprod(c, c) - SPHERE_RADIUS * SPHERE_RADIUS;
320
321   if ((d = b * b - a) < 0.0 || (b < 0.0 && a > 0.0))
322      return GL_FALSE;
323
324   d = sqrt(d);
325
326   t = b - d;
327
328   if (t < EPSILON) {
329      t = b + d;
330      if (t < EPSILON)
331	 return GL_FALSE;
332   }
333
334   vsub(dist, lightpos, p);
335   if (dprod(dist, dist) < t * t)
336      return GL_FALSE;
337
338   return GL_TRUE;
339}
340
341static int
342colorcheckmap(float ppos[3], float c[3])
343{
344   static float norm[3] = { 0.0f, 0.0f, 1.0f };
345   float ldir[3], vdir[3], h[3], dfact, kfact, r, g, b;
346   int x, y;
347
348   x = (int) ((ppos[0] + BASESIZE / 2) * (10.0f / BASESIZE));
349   if ((x < 0) || (x > 10))
350      return GL_FALSE;
351
352   y = (int) ((ppos[1] + BASESIZE / 2) * (10.0f / BASESIZE));
353   if ((y < 0) || (y > 10))
354      return GL_FALSE;
355
356   r = 255.0f;
357   if (y & 1) {
358      if (x & 1)
359	 g = 255.0f;
360      else
361	 g = 0.0f;
362   }
363   else {
364      if (x & 1)
365	 g = 0.0f;
366      else
367	 g = 255.0f;
368   }
369   b = 0.0f;
370
371   vsub(ldir, lightpos, ppos);
372   vnormalize(ldir, ldir);
373
374   if (seelight(ppos, ldir)) {
375      c[0] = r * 0.05f;
376      c[1] = g * 0.05f;
377      c[2] = b * 0.05f;
378
379      return GL_TRUE;
380   }
381
382   dfact = dprod(ldir, norm);
383   if (dfact < 0.0f)
384      dfact = 0.0f;
385
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;
393
394   r = r * dfact + kfact;
395   g = g * dfact + kfact;
396   b = b * dfact + kfact;
397
398   c[0] = clamp255(r);
399   c[1] = clamp255(g);
400   c[2] = clamp255(b);
401
402   return GL_TRUE;
403}
404
405static void
406updatecheckmap(int slot)
407{
408   float c[3], ppos[3];
409   int x, y;
410
411   glBindTexture(GL_TEXTURE_2D, checkid);
412
413   ppos[2] = 0.0f;
414   for (y = slot * TEX_CHECK_SLOT_SIZE; y < (slot + 1) * TEX_CHECK_SLOT_SIZE;
415	y++) {
416      ppos[1] = (y / (float) TEX_CHECK_HEIGHT) * BASESIZE - BASESIZE / 2;
417
418      for (x = 0; x < TEX_CHECK_WIDTH; x++) {
419	 ppos[0] = (x / (float) TEX_CHECK_WIDTH) * BASESIZE - BASESIZE / 2;
420
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];
425      }
426   }
427
428   glTexSubImage2D(GL_TEXTURE_2D, 0, 0, slot * TEX_CHECK_SLOT_SIZE,
429		   TEX_CHECK_WIDTH, TEX_CHECK_SLOT_SIZE, GL_RGB,
430		   GL_UNSIGNED_BYTE,
431		   &checkmap[slot * TEX_CHECK_SLOT_SIZE][0][0]);
432
433}
434
435static void
436updatereflectmap(int slot)
437{
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];
440   int x, y;
441
442   glBindTexture(GL_TEXTURE_2D, reflectid);
443
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];
450
451	 vsub(norm, ppos, objpos);
452	 vnormalize(norm, norm);
453
454	 vsub(ldir, lightpos, ppos);
455	 vnormalize(ldir, ldir);
456	 vsub(vdir, obs, ppos);
457	 vnormalize(vdir, vdir);
458
459	 rf = 2.0f * dprod(norm, vdir);
460	 if (rf > EPSILON) {
461	    rdir[0] = rf * norm[0] - vdir[0];
462	    rdir[1] = rf * norm[1] - vdir[1];
463	    rdir[2] = rf * norm[2] - vdir[2];
464
465	    t = -objpos[2] / rdir[2];
466
467	    if (t > EPSILON) {
468	       planepos[0] = objpos[0] + t * rdir[0];
469	       planepos[1] = objpos[1] + t * rdir[1];
470	       planepos[2] = 0.0f;
471
472	       if (!colorcheckmap(planepos, rcol))
473		  rcol[0] = rcol[1] = rcol[2] = 0.0f;
474	    }
475	    else
476	       rcol[0] = rcol[1] = rcol[2] = 0.0f;
477	 }
478	 else
479	    rcol[0] = rcol[1] = rcol[2] = 0.0f;
480
481	 dfact = 0.1f * dprod(ldir, norm);
482
483	 if (dfact < 0.0f) {
484	    dfact = 0.0f;
485	    kfact = 0.0f;
486	 }
487	 else {
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);
493            if (kfact < 1.0e-10)
494               kfact = 0.0;
495         }
496
497	 r = dfact + kfact;
498	 g = dfact + kfact;
499	 b = dfact + kfact;
500
501	 r *= 255.0f;
502	 g *= 255.0f;
503	 b *= 255.0f;
504
505	 r += rcol[0];
506	 g += rcol[1];
507	 b += rcol[2];
508
509	 r = clamp255(r);
510	 g = clamp255(g);
511	 b = clamp255(b);
512
513	 reflectmap[y][x][0] = (GLubyte) r;
514	 reflectmap[y][x][1] = (GLubyte) g;
515	 reflectmap[y][x][2] = (GLubyte) b;
516      }
517
518   glTexSubImage2D(GL_TEXTURE_2D, 0, 0, slot * TEX_REFLECT_SLOT_SIZE,
519		   TEX_REFLECT_WIDTH, TEX_REFLECT_SLOT_SIZE, GL_RGB,
520		   GL_UNSIGNED_BYTE,
521		   &reflectmap[slot * TEX_REFLECT_SLOT_SIZE][0][0]);
522}
523
524static void
525drawbase(void)
526{
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);
530
531   glBegin(GL_QUADS);
532   glTexCoord2f(0.0f, 0.0f);
533   glVertex3f(-BASESIZE / 2.0f, -BASESIZE / 2.0f, 0.0f);
534
535   glTexCoord2f(1.0f, 0.0f);
536   glVertex3f(BASESIZE / 2.0f, -BASESIZE / 2.0f, 0.0f);
537
538   glTexCoord2f(1.0f, 1.0f);
539   glVertex3f(BASESIZE / 2.0f, BASESIZE / 2.0f, 0.0f);
540
541   glTexCoord2f(0.0f, 1.0f);
542   glVertex3f(-BASESIZE / 2.0f, BASESIZE / 2.0f, 0.0f);
543
544   glEnd();
545}
546
547static void
548drawobj(void)
549{
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);
553
554   glPushMatrix();
555   glTranslatef(objpos[0], objpos[1], objpos[2]);
556   glCallList(objdlist);
557   glPopMatrix();
558}
559
560static void
561dojoy(void)
562{
563#ifdef WIN32
564   static UINT max[2] = { 0, 0 };
565   static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
566   MMRESULT res;
567   JOYINFO joy;
568
569   res = joyGetPos(JOYSTICKID1, &joy);
570
571   if (res == JOYERR_NOERROR) {
572      joyavailable = 1;
573
574      if (max[0] < joy.wXpos)
575	 max[0] = joy.wXpos;
576      if (min[0] > joy.wXpos)
577	 min[0] = joy.wXpos;
578      center[0] = (max[0] + min[0]) / 2;
579
580      if (max[1] < joy.wYpos)
581	 max[1] = joy.wYpos;
582      if (min[1] > joy.wYpos)
583	 min[1] = joy.wYpos;
584      center[1] = (max[1] + min[1]) / 2;
585
586      if (joyactive) {
587	 if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
588	    alpha -=
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]);
592
593	 if (joy.wButtons & JOY_BUTTON1)
594	    v += 0.005;
595	 if (joy.wButtons & JOY_BUTTON2)
596	    v -= 0.005;
597      }
598   }
599   else
600      joyavailable = 0;
601#endif
602}
603
604static void
605updatemaps(void)
606{
607   updatecheckmap(checkmap_currentslot);
608   checkmap_currentslot = (checkmap_currentslot + 1) % TEX_CHECK_NUMSLOT;
609
610   updatereflectmap(reflectmap_currentslot);
611   reflectmap_currentslot =
612      (reflectmap_currentslot + 1) % TEX_REFLECT_NUMSLOT;
613}
614
615static void
616draw(void)
617{
618   static char frbuf[80] = "";
619
620   dojoy();
621
622   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
623
624   glEnable(GL_TEXTURE_2D);
625   glEnable(GL_DEPTH_TEST);
626   if (fog)
627      glEnable(GL_FOG);
628   else
629      glDisable(GL_FOG);
630
631   glPushMatrix();
632   calcposobs();
633
634   gluLookAt(obs[0], obs[1], obs[2],
635	     obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
636	     0.0, 0.0, 1.0);
637
638   drawbase();
639   drawobj();
640
641   glColor3f(1.0, 1.0, 1.0);
642   glDisable(GL_TEXTURE_2D);
643
644   glPushMatrix();
645   glTranslatef(lightpos[0], lightpos[1], lightpos[2]);
646   glCallList(lightdlist);
647   glPopMatrix();
648
649   glPopMatrix();
650
651   glDisable(GL_DEPTH_TEST);
652   glDisable(GL_FOG);
653
654   glMatrixMode(GL_PROJECTION);
655   glPushMatrix();
656   glLoadIdentity();
657   glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
658   glMatrixMode(GL_MODELVIEW);
659
660   glColor3f(0.0f, 0.3f, 1.0f);
661
662   if (showcheckmap) {
663      glEnable(GL_TEXTURE_2D);
664      glBindTexture(GL_TEXTURE_2D, checkid);
665      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
666
667      glBegin(GL_QUADS);
668      glTexCoord2f(1.0f, 0.0f);
669      glVertex2i(10, 30);
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);
676      glEnd();
677
678      glDisable(GL_TEXTURE_2D);
679      glBegin(GL_LINE_LOOP);
680      glVertex2i(10, 30);
681      glVertex2i(10 + 90, 30);
682      glVertex2i(10 + 90, 30 + 90);
683      glVertex2i(10, 30 + 90);
684      glEnd();
685      glRasterPos2i(105, 65);
686      printstring(GLUT_BITMAP_HELVETICA_18, "Plane Texture Map");
687   }
688
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);
693
694      glBegin(GL_QUADS);
695      glTexCoord2f(1.0f, 0.0f);
696      glVertex2i(540, 30);
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);
703      glEnd();
704
705      glDisable(GL_TEXTURE_2D);
706      glBegin(GL_LINE_LOOP);
707      glVertex2i(540, 30);
708      glVertex2i(540 + 90, 30);
709      glVertex2i(540 + 90, 30 + 90);
710      glVertex2i(540, 30 + 90);
711      glEnd();
712      glRasterPos2i(360, 65);
713      printstring(GLUT_BITMAP_HELVETICA_18, "Sphere Texture Map");
714   }
715
716   glDisable(GL_TEXTURE_2D);
717
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)");
723
724   if (help)
725      printhelp();
726
727   glMatrixMode(GL_PROJECTION);
728   glPopMatrix();
729   glMatrixMode(GL_MODELVIEW);
730
731   updatemaps();
732
733   glutSwapBuffers();
734
735   Frames++;
736   {
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);
742         printf("%s\n", frbuf);
743         T0 = t;
744         Frames = 0;
745      }
746   }
747}
748
749static void
750inittextures(void)
751{
752   int y;
753
754   glGenTextures(1, &checkid);
755   glBindTexture(GL_TEXTURE_2D, checkid);
756
757   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
758   glTexImage2D(GL_TEXTURE_2D, 0, 3, TEX_CHECK_WIDTH, TEX_CHECK_HEIGHT,
759		0, GL_RGB, GL_UNSIGNED_BYTE, checkmap);
760
761   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
762   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
763
764   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
765   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
766
767   for (y = 0; y < TEX_CHECK_NUMSLOT; y++)
768      updatecheckmap(y);
769
770
771
772   glGenTextures(1, &reflectid);
773   glBindTexture(GL_TEXTURE_2D, reflectid);
774
775   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
776   glTexImage2D(GL_TEXTURE_2D, 0, 3, TEX_REFLECT_WIDTH, TEX_REFLECT_HEIGHT,
777		0, GL_RGB, GL_UNSIGNED_BYTE, reflectmap);
778
779   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
780   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
781
782   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
783   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
784
785   for (y = 0; y < TEX_REFLECT_NUMSLOT; y++)
786      updatereflectmap(y);
787
788
789}
790
791static void
792initspherepos(void)
793{
794   float alpha, beta, sa, ca, sb, cb;
795   int x, y;
796
797   for (y = 0; y < TEX_REFLECT_HEIGHT; y++) {
798      beta = M_PI - y * (M_PI / TEX_REFLECT_HEIGHT);
799
800      for (x = 0; x < TEX_REFLECT_WIDTH; x++) {
801	 alpha = -x * (2.0f * M_PI / TEX_REFLECT_WIDTH);
802
803	 sa = sin(alpha);
804	 ca = cos(alpha);
805
806	 sb = sin(beta);
807	 cb = cos(beta);
808
809	 sphere_pos[y][x][0] = SPHERE_RADIUS * sa * sb;
810	 sphere_pos[y][x][1] = SPHERE_RADIUS * ca * sb;
811	 sphere_pos[y][x][2] = SPHERE_RADIUS * cb;
812      }
813   }
814}
815
816static void
817initdlists(void)
818{
819   GLUquadricObj *obj;
820
821   obj = gluNewQuadric();
822
823   lightdlist = glGenLists(1);
824   glNewList(lightdlist, GL_COMPILE);
825   gluQuadricDrawStyle(obj, GLU_FILL);
826   gluQuadricNormals(obj, GLU_NONE);
827   gluQuadricTexture(obj, GL_TRUE);
828   gluSphere(obj, 0.25f, 6, 6);
829   glEndList();
830
831   objdlist = glGenLists(1);
832   glNewList(objdlist, GL_COMPILE);
833   gluQuadricDrawStyle(obj, GLU_FILL);
834   gluQuadricNormals(obj, GLU_NONE);
835   gluQuadricTexture(obj, GL_TRUE);
836   gluSphere(obj, SPHERE_RADIUS, 16, 16);
837   glEndList();
838
839   gluDeleteQuadric(obj);
840}
841
842int
843main(int ac, char **av)
844{
845   fprintf(stderr,
846	   "Ray V1.0\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
847
848   /*
849      if(!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS)) {
850      fprintf(stderr,"Error setting the process class.\n");
851      return 0;
852      }
853
854      if(!SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL)) {
855      fprintf(stderr,"Error setting the process priority.\n");
856      return 0;
857      }
858    */
859
860   glutInitWindowSize(WIDTH, HEIGHT);
861   glutInit(&ac, av);
862
863   glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
864
865   if (!(win = glutCreateWindow("Ray"))) {
866      fprintf(stderr, "Error, couldn't open window\n");
867      return -1;
868   }
869
870   reshape(WIDTH, HEIGHT);
871
872   glShadeModel(GL_FLAT);
873   glEnable(GL_DEPTH_TEST);
874   glDepthFunc(GL_LEQUAL);
875   glEnable(GL_CULL_FACE);
876   glEnable(GL_TEXTURE_2D);
877   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
878
879   glEnable(GL_FOG);
880   glFogi(GL_FOG_MODE, GL_EXP2);
881   glFogfv(GL_FOG_COLOR, fogcolor);
882
883   glFogf(GL_FOG_DENSITY, 0.01);
884#ifdef FX
885   glHint(GL_FOG_HINT, GL_NICEST);
886#endif
887
888   calcposobs();
889
890   initspherepos();
891
892   inittextures();
893   initdlists();
894
895   glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
896
897   glutReshapeFunc(reshape);
898   glutDisplayFunc(draw);
899   glutKeyboardFunc(key);
900   glutSpecialFunc(special);
901   glutIdleFunc(draw);
902
903   glutMainLoop();
904
905   return 0;
906}
907