tunnel2.c revision 7ec3b29a
1/*
2 * This program is under the GNU GPL.
3 * Use at your own risk.
4 *
5 * You need TWO Voodoo Graphics boards in order to run
6 * this demo !
7 *
8 * written by David Bucciarelli (tech.hmw@plus.it)
9 *            Humanware s.r.l.
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <math.h>
15#include <string.h>
16
17#ifdef WIN32
18#include <windows.h>
19#endif
20
21#include "glut_wrap.h"
22#include "readtex.h"
23#include "tunneldat.h"
24
25#ifdef FX
26#endif
27
28#ifdef XMESA
29#include "GL/xmesa.h"
30static int fullscreen = 1;
31#endif
32
33#ifdef FX
34GLint fxMesaSelectCurrentBoard(int);
35#endif
36
37static int WIDTHC0 = 640;
38static int HEIGHTC0 = 480;
39
40static int WIDTHC1 = 640;
41static int HEIGHTC1 = 480;
42
43static GLint T0 = 0;
44static GLint Frames = 0;
45
46#define NUMBLOC 5
47
48#ifndef M_PI
49#define M_PI 3.1415926535
50#endif
51
52static float obs[3] = { 1000.0, 0.0, 2.0 };
53static float dir[3];
54static float v = 30.;
55static float alpha = 90.0;
56static float beta = 90.0;
57
58static int fog = 1;
59static int bfcull = 1;
60static int usetex = 1;
61static int cstrip = 0;
62static int help = 1;
63static int joyavailable = 0;
64static int joyactive = 0;
65
66static int channel[2];
67
68static GLuint t1id, t2id;
69
70static void
71inittextures(void)
72{
73   glGenTextures(1, &t1id);
74   glBindTexture(GL_TEXTURE_2D, t1id);
75
76   if (!LoadRGBMipmaps(DEMOS_DATA_DIR "tile.rgb", GL_RGB)) {
77      fprintf(stderr, "Error reading a texture.\n");
78      exit(-1);
79   }
80
81   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
82   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
83
84   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
85		   GL_LINEAR_MIPMAP_NEAREST);
86   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
87
88   glGenTextures(1, &t2id);
89   glBindTexture(GL_TEXTURE_2D, t2id);
90
91   if (!LoadRGBMipmaps(DEMOS_DATA_DIR "bw.rgb", GL_RGB)) {
92      fprintf(stderr, "Error reading a texture.\n");
93      exit(-1);
94   }
95
96   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
97   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
98
99   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
100		   GL_LINEAR_MIPMAP_LINEAR);
101   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
102
103   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
104}
105
106static void
107drawobjs(const int *l, const float *f)
108{
109   int mend, j;
110
111   if (cstrip) {
112      float r = 0.33, g = 0.33, b = 0.33;
113
114      for (; (*l) != 0;) {
115	 mend = *l++;
116
117	 r += 0.33;
118	 if (r > 1.0) {
119	    r = 0.33;
120	    g += 0.33;
121	    if (g > 1.0) {
122	       g = 0.33;
123	       b += 0.33;
124	       if (b > 1.0)
125		  b = 0.33;
126	    }
127	 }
128
129	 glColor3f(r, g, b);
130	 glBegin(GL_TRIANGLE_STRIP);
131	 for (j = 0; j < mend; j++) {
132	    f += 4;
133	    glTexCoord2fv(f);
134	    f += 2;
135	    glVertex3fv(f);
136	    f += 3;
137	 }
138	 glEnd();
139      }
140   }
141   else
142      for (; (*l) != 0;) {
143	 mend = *l++;
144
145	 glBegin(GL_TRIANGLE_STRIP);
146	 for (j = 0; j < mend; j++) {
147	    glColor4fv(f);
148	    f += 4;
149	    glTexCoord2fv(f);
150	    f += 2;
151	    glVertex3fv(f);
152	    f += 3;
153	 }
154	 glEnd();
155      }
156}
157
158static void
159calcposobs(void)
160{
161   static double t0 = -1.;
162   double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
163   if (t0 < 0.0)
164      t0 = t;
165   dt = t - t0;
166   t0 = t;
167
168   dir[0] = sin(alpha * M_PI / 180.0);
169   dir[1] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
170   dir[2] = cos(beta * M_PI / 180.0);
171
172   if (dir[0] < 1.0e-5 && dir[0] > -1.0e-5)
173      dir[0] = 0;
174   if (dir[1] < 1.0e-5 && dir[1] > -1.0e-5)
175      dir[1] = 0;
176   if (dir[2] < 1.0e-5 && dir[2] > -1.0e-5)
177      dir[2] = 0;
178
179   obs[0] += v * dir[0] * dt;
180   obs[1] += v * dir[1] * dt;
181   obs[2] += v * dir[2] * dt;
182}
183
184static void
185special(int k, int x, int y)
186{
187   switch (k) {
188   case GLUT_KEY_LEFT:
189      alpha -= 2.0;
190      break;
191   case GLUT_KEY_RIGHT:
192      alpha += 2.0;
193      break;
194   case GLUT_KEY_DOWN:
195      beta -= 2.0;
196      break;
197   case GLUT_KEY_UP:
198      beta += 2.0;
199      break;
200   }
201}
202
203static void
204cleanup(void)
205{
206   glDeleteTextures(1, &t1id);
207   glDeleteTextures(1, &t2id);
208}
209
210static void
211key(unsigned char k, int x, int y)
212{
213   switch (k) {
214   case 27:
215      glutDestroyWindow(channel[0]);
216      glutDestroyWindow(channel[1]);
217      cleanup();
218      exit(0);
219      break;
220
221   case 'a':
222      v += 5.;
223      break;
224   case 'z':
225      v -= 5.;
226      break;
227
228#ifdef XMESA
229   case ' ':
230      fullscreen = (!fullscreen);
231
232      glutSetWindow(channel[0]);
233      XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
234
235      glutSetWindow(channel[1]);
236      XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
237      break;
238#endif
239
240   case 'j':
241      joyactive = (!joyactive);
242      break;
243   case 'h':
244      help = (!help);
245      break;
246   case 'f':
247      fog = (!fog);
248      break;
249   case 't':
250      usetex = (!usetex);
251      break;
252   case 'b':
253      if (bfcull) {
254	 glDisable(GL_CULL_FACE);
255	 bfcull = 0;
256      }
257      else {
258	 glEnable(GL_CULL_FACE);
259	 bfcull = 1;
260      }
261      break;
262   case 'm':
263      cstrip = (!cstrip);
264      break;
265
266   case 'd':
267      fprintf(stderr, "Deleting textures...\n");
268      glDeleteTextures(1, &t1id);
269      glDeleteTextures(1, &t2id);
270      fprintf(stderr, "Loading textures...\n");
271      inittextures();
272      fprintf(stderr, "Done.\n");
273      break;
274   }
275}
276
277static void
278reshapechannel0(int w, int h)
279{
280   float ratio;
281
282   WIDTHC0 = w;
283   HEIGHTC0 = h;
284   glMatrixMode(GL_PROJECTION);
285   glLoadIdentity();
286
287   ratio = 0.5f * w / (float) h;
288
289   glFrustum(-2.0, 0.0, -1.0 * ratio, 1.0 * ratio, 1.0, 60.0);
290
291   glMatrixMode(GL_MODELVIEW);
292   glLoadIdentity();
293   glViewport(0, 0, w, h);
294}
295
296static void
297reshapechannel1(int w, int h)
298{
299   float ratio;
300
301   WIDTHC1 = w;
302   HEIGHTC1 = h;
303   glMatrixMode(GL_PROJECTION);
304   glLoadIdentity();
305
306   ratio = 0.5f * w / (float) h;
307
308   glFrustum(0.0, 2.0, -1.0 * ratio, 1.0 * ratio, 1.0, 60.0);
309
310   glMatrixMode(GL_MODELVIEW);
311   glLoadIdentity();
312   glViewport(0, 0, w, h);
313}
314
315static void
316printstring(void *font, char *string)
317{
318   int len, i;
319
320   len = (int) strlen(string);
321   for (i = 0; i < len; i++)
322      glutBitmapCharacter(font, string[i]);
323}
324
325static void
326printhelp(void)
327{
328   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
329   glColor4f(0.0, 0.0, 0.0, 0.5);
330   glRecti(40, 40, 600, 440);
331
332   glColor3f(1.0, 0.0, 0.0);
333   glRasterPos2i(300, 420);
334   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help");
335
336   glRasterPos2i(60, 390);
337   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Toggle Help");
338   glRasterPos2i(60, 360);
339   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Toggle Textures");
340   glRasterPos2i(60, 330);
341   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Toggle Fog");
342   glRasterPos2i(60, 300);
343   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "m - Toggle strips");
344   glRasterPos2i(60, 270);
345   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "b - Toggle Back face culling");
346   glRasterPos2i(60, 240);
347   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate");
348   glRasterPos2i(60, 210);
349   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity");
350   glRasterPos2i(60, 180);
351   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity");
352
353   glRasterPos2i(60, 150);
354   if (joyavailable)
355      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
356		  "j - Toggle jostick control (Joystick control available)");
357   else
358      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
359		  "(No Joystick control available)");
360}
361
362static void
363dojoy(void)
364{
365#ifdef WIN32
366   static UINT max[2] = { 0, 0 };
367   static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
368   MMRESULT res;
369   JOYINFO joy;
370
371   res = joyGetPos(JOYSTICKID1, &joy);
372
373   if (res == JOYERR_NOERROR) {
374      joyavailable = 1;
375
376      if (max[0] < joy.wXpos)
377	 max[0] = joy.wXpos;
378      if (min[0] > joy.wXpos)
379	 min[0] = joy.wXpos;
380      center[0] = (max[0] + min[0]) / 2;
381
382      if (max[1] < joy.wYpos)
383	 max[1] = joy.wYpos;
384      if (min[1] > joy.wYpos)
385	 min[1] = joy.wYpos;
386      center[1] = (max[1] + min[1]) / 2;
387
388      if (joyactive) {
389	 if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
390	    alpha -=
391	       2.0 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
392	 if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
393	    beta += 2.0 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
394
395	 if (joy.wButtons & JOY_BUTTON1)
396	    v += 0.01;
397	 if (joy.wButtons & JOY_BUTTON2)
398	    v -= 0.01;
399      }
400   }
401   else
402      joyavailable = 0;
403#endif
404}
405
406static void
407draw(void)
408{
409   static char frbuf[80] = "";
410   int i;
411   float base, offset;
412
413   dojoy();
414
415   glClear(GL_COLOR_BUFFER_BIT);
416
417   glClear(GL_COLOR_BUFFER_BIT);
418
419   if (usetex)
420      glEnable(GL_TEXTURE_2D);
421   else
422      glDisable(GL_TEXTURE_2D);
423
424   if (fog)
425      glEnable(GL_FOG);
426   else
427      glDisable(GL_FOG);
428
429   glShadeModel(GL_SMOOTH);
430
431   glPushMatrix();
432   calcposobs();
433   gluLookAt(obs[0], obs[1], obs[2],
434	     obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
435	     0.0, 0.0, 1.0);
436
437   if (dir[0] > 0) {
438      offset = 8.0;
439      base = obs[0] - fmod(obs[0], 8.0);
440   }
441   else {
442      offset = -8.0;
443      base = obs[0] + (8.0 - fmod(obs[0], 8.0));
444   }
445
446   glPushMatrix();
447   glTranslatef(base - offset / 2.0, 0.0, 0.0);
448   for (i = 0; i < NUMBLOC; i++) {
449      glTranslatef(offset, 0.0, 0.0);
450      glBindTexture(GL_TEXTURE_2D, t1id);
451      drawobjs(striplength_skin_11, stripdata_skin_11);
452      glBindTexture(GL_TEXTURE_2D, t2id);
453      drawobjs(striplength_skin_12, stripdata_skin_12);
454      drawobjs(striplength_skin_9, stripdata_skin_9);
455      drawobjs(striplength_skin_13, stripdata_skin_13);
456   }
457   glPopMatrix();
458   glPopMatrix();
459
460   glDisable(GL_TEXTURE_2D);
461   glDisable(GL_FOG);
462   glShadeModel(GL_FLAT);
463
464   glMatrixMode(GL_PROJECTION);
465   glPushMatrix();
466   glLoadIdentity();
467   glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
468
469   glMatrixMode(GL_MODELVIEW);
470   glLoadIdentity();
471
472   glColor3f(1.0, 0.0, 0.0);
473   glRasterPos2i(10, 10);
474   printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
475   glRasterPos2i(350, 470);
476   printstring(GLUT_BITMAP_HELVETICA_10,
477	       "Tunnel2 V1.0 Written by David Bucciarelli (tech.hmw@plus.it)");
478
479   if (help)
480      printhelp();
481
482   glMatrixMode(GL_PROJECTION);
483   glPopMatrix();
484   glMatrixMode(GL_MODELVIEW);
485
486   Frames++;
487   {
488      GLint t = glutGet(GLUT_ELAPSED_TIME);
489      if (t - T0 >= 2000) {
490         GLfloat seconds = (t - T0) / 1000.0;
491         GLfloat fps = Frames / seconds;
492         sprintf(frbuf, "Frame rate: %f", fps);
493         printf("%s\n", frbuf);
494         fflush(stdout);
495         T0 = t;
496         Frames = 0;
497      }
498   }
499}
500
501static void
502drawchannel0(void)
503{
504   glutSetWindow(channel[0]);
505   draw();
506   glutSwapBuffers();
507}
508
509static void
510drawchannel1(void)
511{
512   glutSetWindow(channel[1]);
513   draw();
514   glutSwapBuffers();
515}
516
517static void
518drawall(void)
519{
520   glutSetWindow(channel[0]);
521   draw();
522   glutSetWindow(channel[1]);
523   draw();
524
525   glutSetWindow(channel[0]);
526   glutSwapBuffers();
527   glutSetWindow(channel[1]);
528   glutSwapBuffers();
529}
530
531static void
532init(void)
533{
534   float fogcolor[4] = { 0.7, 0.7, 0.7, 1.0 };
535
536   glShadeModel(GL_SMOOTH);
537   glDisable(GL_DEPTH_TEST);
538   glEnable(GL_CULL_FACE);
539   glEnable(GL_TEXTURE_2D);
540
541   glEnable(GL_FOG);
542   glFogi(GL_FOG_MODE, GL_EXP2);
543   glFogfv(GL_FOG_COLOR, fogcolor);
544
545   glFogf(GL_FOG_DENSITY, 0.06);
546   glHint(GL_FOG_HINT, GL_NICEST);
547
548   glEnable(GL_BLEND);
549   /*
550   glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
551   glEnable(GL_POLYGON_SMOOTH);
552   */
553
554   glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
555   glClear(GL_COLOR_BUFFER_BIT);
556}
557
558int
559main(int ac, char **av)
560{
561   fprintf(stderr,
562	   "Tunnel2 V1.0\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
563
564   glutInitWindowSize(WIDTHC0, HEIGHTC0);
565   glutInit(&ac, av);
566
567   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
568
569#ifdef FX
570   if (fxMesaSelectCurrentBoard(0) < 0) {
571      fprintf(stderr, "The first Voodoo Graphics board is missing !?!?\n");
572      return -1;
573   }
574#endif
575   if (!(channel[0] = glutCreateWindow("Channel 0"))) {
576      fprintf(stderr, "Error, couldn't open window\n");
577      return -1;
578   }
579
580   reshapechannel0(WIDTHC0, HEIGHTC0);
581   init();
582   inittextures();
583   glutDisplayFunc(drawchannel0);
584   glutReshapeFunc(reshapechannel0);
585   glutKeyboardFunc(key);
586   glutSpecialFunc(special);
587
588#ifdef FX
589   if (fxMesaSelectCurrentBoard(1) < 0) {
590      fprintf(stderr, "The second Voodoo Graphics board is missing !\n");
591      exit(-1);
592   }
593#endif
594   glutInitWindowPosition(WIDTHC0, 0);
595   glutInitWindowSize(WIDTHC1, HEIGHTC1);
596   if (!(channel[1] = glutCreateWindow("Channel 1"))) {
597      fprintf(stderr, "Error, couldn't open window\n");
598      exit(-1);
599   }
600
601   reshapechannel1(WIDTHC1, HEIGHTC1);
602   init();
603   inittextures();
604   glutDisplayFunc(drawchannel1);
605   glutReshapeFunc(reshapechannel1);
606   glutKeyboardFunc(key);
607   glutSpecialFunc(special);
608
609   glutIdleFunc(drawall);
610
611   calcposobs();
612
613   glutMainLoop();
614   cleanup();
615
616   return 0;
617}
618