initial check-in
authorBrian Paul <brian.paul@tungstengraphics.com>
Tue, 27 Jun 2000 16:52:38 +0000 (16:52 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Tue, 27 Jun 2000 16:52:38 +0000 (16:52 +0000)
13 files changed:
progs/demos/fire.c [new file with mode: 0644]
progs/demos/gltestperf.c [new file with mode: 0644]
progs/demos/ipers.c [new file with mode: 0644]
progs/demos/particles.cxx [new file with mode: 0644]
progs/demos/particles.h [new file with mode: 0644]
progs/demos/rain.cxx [new file with mode: 0644]
progs/demos/ray.c [new file with mode: 0644]
progs/demos/shadow.c [new file with mode: 0644]
progs/demos/teapot.c [new file with mode: 0644]
progs/demos/terrain.c [new file with mode: 0644]
progs/demos/tunnel.c [new file with mode: 0644]
progs/demos/tunnel2.c [new file with mode: 0644]
progs/demos/tunneldat.c [new file with mode: 0644]

diff --git a/progs/demos/fire.c b/progs/demos/fire.c
new file mode 100644 (file)
index 0000000..056598d
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (tech.hmw@plus.it)
+ *            Humanware s.r.l.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <mmsystem.h>
+#endif
+
+#include <GL/glut.h>
+#include "../util/readtex.c"
+
+#ifdef XMESA
+#include "GL/xmesa.h"
+static int fullscreen = 1;
+#endif
+
+#ifndef M_PI
+#define M_PI 3.1415926535
+#endif
+
+#define vinit(a,i,j,k) {\
+  (a)[0]=i;\
+  (a)[1]=j;\
+  (a)[2]=k;\
+}
+
+#define vinit4(a,i,j,k,w) {\
+  (a)[0]=i;\
+  (a)[1]=j;\
+  (a)[2]=k;\
+  (a)[3]=w;\
+}
+
+
+#define vadds(a,dt,b) {\
+  (a)[0]+=(dt)*(b)[0];\
+  (a)[1]+=(dt)*(b)[1];\
+  (a)[2]+=(dt)*(b)[2];\
+}
+
+#define vequ(a,b) {\
+  (a)[0]=(b)[0];\
+  (a)[1]=(b)[1];\
+  (a)[2]=(b)[2];\
+}
+
+#define vinter(a,dt,b,c) {\
+  (a)[0]=(dt)*(b)[0]+(1.0-dt)*(c)[0];\
+  (a)[1]=(dt)*(b)[1]+(1.0-dt)*(c)[1];\
+  (a)[2]=(dt)*(b)[2]+(1.0-dt)*(c)[2];\
+}
+
+#define clamp(a)        ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0))
+
+#define vclamp(v) {\
+  (v)[0]=clamp((v)[0]);\
+  (v)[1]=clamp((v)[1]);\
+  (v)[2]=clamp((v)[2]);\
+}
+
+static int WIDTH = 640;
+static int HEIGHT = 480;
+
+#define FRAME 50
+#define DIMP 20.0
+#define DIMTP 16.0
+
+#define RIDCOL 0.4
+
+#define NUMTREE 50
+#define TREEINR 2.5
+#define TREEOUTR 8.0
+
+#define AGRAV -9.8
+
+typedef struct
+{
+   int age;
+   float p[3][3];
+   float v[3];
+   float c[3][4];
+}
+part;
+
+static float treepos[NUMTREE][3];
+
+static float black[3] = { 0.0, 0.0, 0.0 };
+static float blu[3] = { 0.0, 0.2, 1.0 };
+static float blu2[3] = { 0.0, 1.0, 1.0 };
+
+static float fogcolor[4] = { 1.0, 1.0, 1.0, 1.0 };
+
+static float q[4][3] = {
+   {-DIMP, 0.0, -DIMP},
+   {DIMP, 0.0, -DIMP},
+   {DIMP, 0.0, DIMP},
+   {-DIMP, 0.0, DIMP}
+};
+
+static float qt[4][2] = {
+   {-DIMTP, -DIMTP},
+   {DIMTP, -DIMTP},
+   {DIMTP, DIMTP},
+   {-DIMTP, DIMTP}
+};
+
+static int win = 0;
+
+static int np;
+static float eject_r, dt, maxage, eject_vy, eject_vl;
+static short shadows;
+static float ridtri;
+static int fog = 1;
+static int help = 1;
+static int joyavailable = 0;
+static int joyactive = 0;
+
+static part *p;
+
+static GLuint groundid;
+static GLuint treeid;
+
+static float obs[3] = { 2.0, 1.0, 0.0 };
+static float dir[3];
+static float v = 0.0;
+static float alpha = -90.0;
+static float beta = 90.0;
+
+static float
+gettime(void)
+{
+   static clock_t told = 0;
+   clock_t tnew, ris;
+
+   tnew = clock();
+
+   ris = tnew - told;
+
+   told = tnew;
+
+   return (ris / (float) CLOCKS_PER_SEC);
+}
+
+float
+vrnd(void)
+{
+   return (((float) rand()) / RAND_MAX);
+}
+
+static void
+setnewpart(part * p)
+{
+   float a, v[3], *c;
+
+   p->age = 0;
+
+   a = vrnd() * 3.14159265359 * 2.0;
+
+   vinit(v, sin(a) * eject_r * vrnd(), 0.15, cos(a) * eject_r * vrnd());
+   vinit(p->p[0], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri,
+        v[2] + vrnd() * ridtri);
+   vinit(p->p[1], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri,
+        v[2] + vrnd() * ridtri);
+   vinit(p->p[2], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri,
+        v[2] + vrnd() * ridtri);
+
+   vinit(p->v, v[0] * eject_vl / (eject_r / 2),
+        vrnd() * eject_vy + eject_vy / 2, v[2] * eject_vl / (eject_r / 2));
+
+   c = blu;
+
+   vinit4(p->c[0], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
+         c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
+         c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
+   vinit4(p->c[1], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
+         c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
+         c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
+   vinit4(p->c[2], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
+         c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
+         c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
+}
+
+static void
+setpart(part * p)
+{
+   float fact;
+
+   if (p->p[0][1] < 0.1) {
+      setnewpart(p);
+      return;
+   }
+
+   p->v[1] += AGRAV * dt;
+
+   vadds(p->p[0], dt, p->v);
+   vadds(p->p[1], dt, p->v);
+   vadds(p->p[2], dt, p->v);
+
+   p->age++;
+
+   if ((p->age) > maxage) {
+      vequ(p->c[0], blu2);
+      vequ(p->c[1], blu2);
+      vequ(p->c[2], blu2);
+   }
+   else {
+      fact = 1.0 / maxage;
+      vadds(p->c[0], fact, blu2);
+      vclamp(p->c[0]);
+      p->c[0][3] = fact * (maxage - p->age);
+
+      vadds(p->c[1], fact, blu2);
+      vclamp(p->c[1]);
+      p->c[1][3] = fact * (maxage - p->age);
+
+      vadds(p->c[2], fact, blu2);
+      vclamp(p->c[2]);
+      p->c[2][3] = fact * (maxage - p->age);
+   }
+}
+
+static void
+drawtree(float x, float y, float z)
+{
+   glBegin(GL_QUADS);
+   glTexCoord2f(0.0, 0.0);
+   glVertex3f(x - 1.5, y + 0.0, z);
+
+   glTexCoord2f(1.0, 0.0);
+   glVertex3f(x + 1.5, y + 0.0, z);
+
+   glTexCoord2f(1.0, 1.0);
+   glVertex3f(x + 1.5, y + 3.0, z);
+
+   glTexCoord2f(0.0, 1.0);
+   glVertex3f(x - 1.5, y + 3.0, z);
+
+
+   glTexCoord2f(0.0, 0.0);
+   glVertex3f(x, y + 0.0, z - 1.5);
+
+   glTexCoord2f(1.0, 0.0);
+   glVertex3f(x, y + 0.0, z + 1.5);
+
+   glTexCoord2f(1.0, 1.0);
+   glVertex3f(x, y + 3.0, z + 1.5);
+
+   glTexCoord2f(0.0, 1.0);
+   glVertex3f(x, y + 3.0, z - 1.5);
+
+   glEnd();
+
+}
+
+static void
+calcposobs(void)
+{
+   dir[0] = sin(alpha * M_PI / 180.0);
+   dir[2] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
+   dir[1] = cos(beta * M_PI / 180.0);
+
+   obs[0] += v * dir[0];
+   obs[1] += v * dir[1];
+   obs[2] += v * dir[2];
+}
+
+static void
+printstring(void *font, char *string)
+{
+   int len, i;
+
+   len = (int) strlen(string);
+   for (i = 0; i < len; i++)
+      glutBitmapCharacter(font, string[i]);
+}
+
+static void
+reshape(int width, int height)
+{
+   WIDTH = width;
+   HEIGHT = height;
+   glViewport(0, 0, (GLint) width, (GLint) height);
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   gluPerspective(70.0, width / (float) height, 0.1, 30.0);
+
+   glMatrixMode(GL_MODELVIEW);
+}
+
+static void
+printhelp(void)
+{
+   glColor4f(0.0, 0.0, 0.0, 0.5);
+   glRecti(40, 40, 600, 440);
+
+   glColor3f(1.0, 0.0, 0.0);
+   glRasterPos2i(300, 420);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help");
+
+   glRasterPos2i(60, 390);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Togle Help");
+
+   glRasterPos2i(60, 360);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Increase particle size");
+   glRasterPos2i(60, 330);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "T - Decrease particle size");
+
+   glRasterPos2i(60, 300);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "r - Increase emission radius");
+   glRasterPos2i(60, 270);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "R - Decrease emission radius");
+
+   glRasterPos2i(60, 240);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Togle Fog");
+   glRasterPos2i(60, 210);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "s - Togle shadows");
+   glRasterPos2i(60, 180);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate");
+   glRasterPos2i(60, 150);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity");
+   glRasterPos2i(60, 120);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity");
+
+   glRasterPos2i(60, 90);
+   if (joyavailable)
+      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+                 "j - Togle jostick control (Joystick control available)");
+   else
+      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+                 "(No Joystick control available)");
+}
+
+static void
+dojoy(void)
+{
+#ifdef WIN32
+   static UINT max[2] = { 0, 0 };
+   static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
+   MMRESULT res;
+   JOYINFO joy;
+
+   res = joyGetPos(JOYSTICKID1, &joy);
+
+   if (res == JOYERR_NOERROR) {
+      joyavailable = 1;
+
+      if (max[0] < joy.wXpos)
+        max[0] = joy.wXpos;
+      if (min[0] > joy.wXpos)
+        min[0] = joy.wXpos;
+      center[0] = (max[0] + min[0]) / 2;
+
+      if (max[1] < joy.wYpos)
+        max[1] = joy.wYpos;
+      if (min[1] > joy.wYpos)
+        min[1] = joy.wYpos;
+      center[1] = (max[1] + min[1]) / 2;
+
+      if (joyactive) {
+        if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
+           alpha +=
+              2.5 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
+        if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
+           beta += 2.5 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
+
+        if (joy.wButtons & JOY_BUTTON1)
+           v += 0.01;
+        if (joy.wButtons & JOY_BUTTON2)
+           v -= 0.01;
+      }
+   }
+   else
+      joyavailable = 0;
+#endif
+}
+
+static void
+drawfire(void)
+{
+   static int count = 0;
+   static char frbuf[80];
+   int j;
+   float fr;
+
+   dojoy();
+
+   glEnable(GL_DEPTH_TEST);
+
+   if (fog)
+      glEnable(GL_FOG);
+   else
+      glDisable(GL_FOG);
+
+   glDepthMask(GL_TRUE);
+   glClearColor(1.0, 1.0, 1.0, 1.0);
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   glPushMatrix();
+   calcposobs();
+   gluLookAt(obs[0], obs[1], obs[2],
+            obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
+            0.0, 1.0, 0.0);
+
+   glColor4f(1.0, 1.0, 1.0, 1.0);
+
+   glEnable(GL_TEXTURE_2D);
+
+   glBindTexture(GL_TEXTURE_2D, groundid);
+   glBegin(GL_QUADS);
+   glTexCoord2fv(qt[0]);
+   glVertex3fv(q[0]);
+   glTexCoord2fv(qt[1]);
+   glVertex3fv(q[1]);
+   glTexCoord2fv(qt[2]);
+   glVertex3fv(q[2]);
+   glTexCoord2fv(qt[3]);
+   glVertex3fv(q[3]);
+   glEnd();
+
+   glEnable(GL_ALPHA_TEST);
+   glAlphaFunc(GL_GEQUAL, 0.9);
+
+   glBindTexture(GL_TEXTURE_2D, treeid);
+   for (j = 0; j < NUMTREE; j++)
+      drawtree(treepos[j][0], treepos[j][1], treepos[j][2]);
+
+   glDisable(GL_TEXTURE_2D);
+   glDepthMask(GL_FALSE);
+   glDisable(GL_ALPHA_TEST);
+
+   if (shadows) {
+      glBegin(GL_TRIANGLES);
+      for (j = 0; j < np; j++) {
+        glColor4f(black[0], black[1], black[2], p[j].c[0][3]);
+        glVertex3f(p[j].p[0][0], 0.1, p[j].p[0][2]);
+
+        glColor4f(black[0], black[1], black[2], p[j].c[1][3]);
+        glVertex3f(p[j].p[1][0], 0.1, p[j].p[1][2]);
+
+        glColor4f(black[0], black[1], black[2], p[j].c[2][3]);
+        glVertex3f(p[j].p[2][0], 0.1, p[j].p[2][2]);
+      }
+      glEnd();
+   }
+
+   glBegin(GL_TRIANGLES);
+   for (j = 0; j < np; j++) {
+      glColor4fv(p[j].c[0]);
+      glVertex3fv(p[j].p[0]);
+
+      glColor4fv(p[j].c[1]);
+      glVertex3fv(p[j].p[1]);
+
+      glColor4fv(p[j].c[2]);
+      glVertex3fv(p[j].p[2]);
+
+      setpart(&p[j]);
+   }
+   glEnd();
+
+   if ((count % FRAME) == 0) {
+      fr = gettime();
+      sprintf(frbuf, "Frame rate: %f", FRAME / fr);
+   }
+
+   glDisable(GL_TEXTURE_2D);
+   glDisable(GL_ALPHA_TEST);
+   glDisable(GL_DEPTH_TEST);
+   glDisable(GL_FOG);
+
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+
+   glColor3f(1.0, 0.0, 0.0);
+   glRasterPos2i(10, 10);
+   printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
+   glRasterPos2i(370, 470);
+   printstring(GLUT_BITMAP_HELVETICA_10,
+              "Fire V1.5 Written by David Bucciarelli (tech.hmw@plus.it)");
+
+   if (help)
+      printhelp();
+
+   reshape(WIDTH, HEIGHT);
+   glPopMatrix();
+
+   glutSwapBuffers();
+
+   count++;
+}
+
+
+static void
+special(int key, int x, int y)
+{
+   switch (key) {
+   case GLUT_KEY_LEFT:
+      alpha += 2.0;
+      break;
+   case GLUT_KEY_RIGHT:
+      alpha -= 2.0;
+      break;
+   case GLUT_KEY_DOWN:
+      beta -= 2.0;
+      break;
+   case GLUT_KEY_UP:
+      beta += 2.0;
+      break;
+   }
+}
+
+static void
+key(unsigned char key, int x, int y)
+{
+   switch (key) {
+   case 27:
+      exit(0);
+      break;
+
+   case 'a':
+      v += 0.01;
+      break;
+   case 'z':
+      v -= 0.01;
+      break;
+
+   case 'j':
+      joyactive = (!joyactive);
+      break;
+   case 'h':
+      help = (!help);
+      break;
+   case 'f':
+      fog = (!fog);
+      break;
+   case 's':
+      shadows = !shadows;
+      break;
+   case 'R':
+      eject_r -= 0.03;
+      break;
+   case 'r':
+      eject_r += 0.03;
+      break;
+   case 't':
+      ridtri += 0.005;
+      break;
+   case 'T':
+      ridtri -= 0.005;
+      break;
+#ifdef XMESA
+   case ' ':
+      XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
+      fullscreen = (!fullscreen);
+      break;
+#endif
+   }
+}
+
+static void
+inittextures(void)
+{
+   GLenum gluerr;
+   GLubyte tex[128][128][4];
+
+   glGenTextures(1, &groundid);
+   glBindTexture(GL_TEXTURE_2D, groundid);
+
+   glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+   if (!LoadRGBMipmaps("../images/s128.rgb", GL_RGB)) {
+      fprintf(stderr, "Error reading a texture.\n");
+      exit(-1);
+   }
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_LINEAR);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+
+   glGenTextures(1, &treeid);
+   glBindTexture(GL_TEXTURE_2D, treeid);
+
+   {
+      int w, h;
+      GLenum format;
+      int x, y;
+      GLubyte *image = LoadRGBImage("../images/tree2.rgb", &w, &h, &format);
+
+      if (!image) {
+        fprintf(stderr, "Error reading a texture.\n");
+        exit(-1);
+      }
+
+      for (y = 0; y < 128; y++)
+        for (x = 0; x < 128; x++) {
+           tex[x][y][0] = image[(y + x * 128) * 3];
+           tex[x][y][1] = image[(y + x * 128) * 3 + 1];
+           tex[x][y][2] = image[(y + x * 128) * 3 + 2];
+           if ((tex[x][y][0] == tex[x][y][1]) &&
+               (tex[x][y][1] == tex[x][y][2]) && (tex[x][y][2] == 255))
+              tex[x][y][3] = 0;
+           else
+              tex[x][y][3] = 255;
+        }
+
+      if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 128, 128, GL_RGBA,
+                                     GL_UNSIGNED_BYTE, (GLvoid *) (tex)))) {
+        fprintf(stderr, "GLULib%s\n", gluErrorString(gluerr));
+        exit(-1);
+      }
+   }
+
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_LINEAR);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+static void
+inittree(void)
+{
+   int i;
+   float dist;
+
+   for (i = 0; i < NUMTREE; i++)
+      do {
+        treepos[i][0] = vrnd() * TREEOUTR * 2.0 - TREEOUTR;
+        treepos[i][1] = 0.0;
+        treepos[i][2] = vrnd() * TREEOUTR * 2.0 - TREEOUTR;
+        dist =
+           sqrt(treepos[i][0] * treepos[i][0] +
+                treepos[i][2] * treepos[i][2]);
+      } while ((dist < TREEINR) || (dist > TREEOUTR));
+}
+
+int
+main(int ac, char **av)
+{
+   int i;
+
+   fprintf(stderr,
+          "Fire V1.5\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
+
+   /* Default settings */
+
+   WIDTH = 640;
+   HEIGHT = 480;
+   np = 800;
+   eject_r = 0.1;
+   dt = 0.015;
+   eject_vy = 4;
+   eject_vl = 1;
+   shadows = 1;
+   ridtri = 0.1;
+
+   maxage = 1.0 / dt;
+
+   if (ac == 2)
+      np = atoi(av[1]);
+
+   if (ac == 4) {
+      WIDTH = atoi(av[2]);
+      HEIGHT = atoi(av[3]);
+   }
+
+   glutInitWindowPosition(0, 0);
+   glutInitWindowSize(WIDTH, HEIGHT);
+   glutInit(&ac, av);
+
+   glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
+
+   if (!(win = glutCreateWindow("Fire"))) {
+      fprintf(stderr, "Error opening a window.\n");
+      exit(-1);
+   }
+
+   reshape(WIDTH, HEIGHT);
+
+   inittextures();
+
+   glShadeModel(GL_FLAT);
+   glEnable(GL_DEPTH_TEST);
+
+   glEnable(GL_BLEND);
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+   glEnable(GL_FOG);
+   glFogi(GL_FOG_MODE, GL_EXP);
+   glFogfv(GL_FOG_COLOR, fogcolor);
+   glFogf(GL_FOG_DENSITY, 0.1);
+#ifdef FX
+   glHint(GL_FOG_HINT, GL_NICEST);
+#endif
+
+   p = malloc(sizeof(part) * np);
+
+   for (i = 0; i < np; i++)
+      setnewpart(&p[i]);
+
+   inittree();
+
+   glutKeyboardFunc(key);
+   glutSpecialFunc(special);
+   glutDisplayFunc(drawfire);
+   glutIdleFunc(drawfire);
+   glutReshapeFunc(reshape);
+   glutMainLoop();
+
+   return (0);
+}
diff --git a/progs/demos/gltestperf.c b/progs/demos/gltestperf.c
new file mode 100644 (file)
index 0000000..2df168b
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (tech.hmw@plus.it)
+ *            Humanware s.r.l.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <GL/glut.h>
+
+typedef struct
+{
+   char *name;
+   char *unit;
+   void (*init) (void);
+   int (*run) (int, int);
+   int type;
+   int numsize;
+   int size[10];
+}
+benchmark;
+
+static int frontbuffer = 1;
+
+/***************************************************************************/
+
+static void
+init_test01(void)
+{
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   gluOrtho2D(-0.5, 639.5, -0.5, 479.5);
+   glMatrixMode(GL_MODELVIEW);
+
+   glShadeModel(GL_FLAT);
+   glDisable(GL_DEPTH_TEST);
+
+   glClearColor(0.0, 0.1, 1.0, 0.0);
+   glClear(GL_COLOR_BUFFER_BIT);
+   glColor3f(1.0, 0.0, 0.0);
+}
+
+static int
+test01(int size, int num)
+{
+   int x, y;
+
+   glBegin(GL_POINTS);
+   for (y = 0; y < num; y++)
+      for (x = 0; x < 480; x++)
+        glVertex2i(x, x);
+   glEnd();
+
+   return 480 * num;
+}
+
+/***************************************************************************/
+
+static void
+init_test02(void)
+{
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   gluOrtho2D(-0.5, 639.5, -0.5, 479.5);
+   glMatrixMode(GL_MODELVIEW);
+
+   glShadeModel(GL_SMOOTH);
+   glDisable(GL_DEPTH_TEST);
+
+   glClearColor(0.0, 0.1, 1.0, 0.0);
+   glClear(GL_COLOR_BUFFER_BIT);
+}
+
+static int
+test02(int size, int num)
+{
+   int x, y;
+
+   glBegin(GL_LINES);
+   for (y = 0; y < num; y++)
+      for (x = 0; x < size; x++) {
+        glColor3f(0.0, 1.0, y / (float) num);
+        glVertex2i(0, size - 1);
+        glColor3f(1.0, 0.0, x / (float) size);
+        glVertex2i(x, x);
+      }
+   glEnd();
+
+   return num * size;
+}
+
+/***************************************************************************/
+
+static void
+init_test03(void)
+{
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glOrtho(-0.5, 639.5, -0.5, 479.5, 1.0, -1000.0 * 480.0);
+   glMatrixMode(GL_MODELVIEW);
+
+   glShadeModel(GL_SMOOTH);
+   glEnable(GL_DEPTH_TEST);
+
+   glClearColor(0.0, 0.1, 1.0, 0.0);
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+static int
+test03(int size, int num)
+{
+   int x, y, z;
+
+   glBegin(GL_TRIANGLES);
+   for (y = 0; y < num; y++)
+      for (x = 0; x < size; x += 5) {
+        z = num * size - (y * size + x);
+        glColor3f(0.0, 1.0, 0.0);
+        glVertex3i(0, x, z);
+
+        glColor3f(1.0, 0.0, x / (float) size);
+        glVertex3i(size - 1 - x, 0, z);
+
+        glColor3f(1.0, x / (float) size, 0.0);
+        glVertex3i(x, size - 1 - x, z);
+      }
+   glEnd();
+
+   return size * num / 5;
+}
+
+/***************************************************************************/
+
+static void
+init_test04(void)
+{
+   int x, y;
+   GLubyte tex[128 * 128 * 3];
+   GLenum gluerr;
+
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glOrtho(-0.5, 639.5, -0.5, 479.5, 1.0, -1000.0 * 480.0);
+
+   glMatrixMode(GL_MODELVIEW);
+
+   glShadeModel(GL_SMOOTH);
+   glEnable(GL_DEPTH_TEST);
+
+   glEnable(GL_BLEND);
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+   for (y = 0; y < 128; y++)
+      for (x = 0; x < 128; x++) {
+        tex[(x + y * 128) * 3 + 0] = ((x % (128 / 4)) < (128 / 8)) ? 255 : 0;
+        tex[(x + y * 128) * 3 + 1] = ((y % (128 / 4)) < (128 / 8)) ? 255 : 0;
+        tex[(x + y * 128) * 3 + 2] = x;
+      }
+
+   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+   if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 128, 128, GL_RGB,
+                                  GL_UNSIGNED_BYTE, (GLvoid *) (&tex[0])))) {
+      fprintf(stderr, "GLULib%s\n", gluErrorString(gluerr));
+      exit(-1);
+   }
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+   glEnable(GL_TEXTURE_2D);
+
+   glClearColor(0.0, 0.1, 1.0, 0.0);
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+static int
+test04(int size, int num)
+{
+   int x, y, z;
+
+   glBegin(GL_TRIANGLES);
+   for (y = 0; y < num; y++)
+      for (x = 0; x < size; x += 5) {
+        z = num * size - (y * size + x);
+        glTexCoord2f(1.0, 1.0);
+        glColor3f(1.0, 0.0, 0.0);
+        glVertex3i(0, x, z);
+
+        glTexCoord2f(0.0, 1.0);
+        glColor3f(0.0, 1.0, 0.0);
+        glVertex3i(size - 1 - x, 0, z);
+
+        glTexCoord2f(1.0, 0.0);
+        glColor3f(0.0, 0.0, 1.0);
+        glVertex3i(x, size - 1 - x, z);
+      }
+   glEnd();
+
+   return num * size / 5;
+}
+
+/***************************************************************************/
+
+static void
+init_test05(void)
+{
+   int x, y;
+   GLubyte tex[128 * 128 * 3];
+   GLenum gluerr;
+
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
+
+   glMatrixMode(GL_MODELVIEW);
+
+   glShadeModel(GL_SMOOTH);
+   glEnable(GL_DEPTH_TEST);
+
+   glEnable(GL_BLEND);
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+   for (y = 0; y < 128; y++)
+      for (x = 0; x < 128; x++) {
+        tex[(x + y * 128) * 3 + 0] = ((x % (128 / 4)) < (128 / 8)) ? 255 : 0;
+        tex[(x + y * 128) * 3 + 1] = ((y % (128 / 4)) < (128 / 8)) ? 255 : 0;
+        tex[(x + y * 128) * 3 + 2] = x;
+      }
+
+   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+   if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 128, 128, GL_RGB,
+                                  GL_UNSIGNED_BYTE, (GLvoid *) (&tex[0])))) {
+      fprintf(stderr, "GLULib%s\n", gluErrorString(gluerr));
+      exit(-1);
+   }
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+   glEnable(GL_TEXTURE_2D);
+
+   glDepthFunc(GL_ALWAYS);
+
+   glClearColor(0.0, 0.1, 1.0, 0.0);
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+static int
+test05(int size, int num)
+{
+   int y;
+   float v0[3], v1[3], v2[3], v3[3];
+   float cv0[3], cv1[3], cv2[3], cv3[3];
+   float tv0[3], tv1[3], tv2[3], tv3[3];
+
+   v0[0] = 320 - size / 2;
+   v0[1] = 240 - size / 2;
+   v0[2] = 0.0;
+   v1[0] = 320 + size / 2;
+   v1[1] = 240 - size / 2;
+   v1[2] = 0.0;
+   v2[0] = 320 - size / 2;
+   v2[1] = 240 + size / 2;
+   v2[2] = 0.0;
+   v3[0] = 320 + size / 2;
+   v3[1] = 240 + size / 2;
+   v3[2] = 0.0;
+   cv0[0] = 1.0;
+   cv0[1] = 0.0;
+   cv0[2] = 0.0;
+   cv1[0] = 1.0;
+   cv1[1] = 1.0;
+   cv1[2] = 0.0;
+   cv2[0] = 1.0;
+   cv2[1] = 0.0;
+   cv2[2] = 1.0;
+   cv3[0] = 1.0;
+   cv3[1] = 1.0;
+   cv3[2] = 1.0;
+   tv0[0] = 0.0;
+   tv0[1] = 0.0;
+   tv0[2] = 0.0;
+   tv1[0] = 1.0;
+   tv1[1] = 0.0;
+   tv1[2] = 0.0;
+   tv2[0] = 0.0;
+   tv2[1] = 1.0;
+   tv2[2] = 0.0;
+   tv3[0] = 1.0;
+   tv3[1] = 1.0;
+   tv3[2] = 0.0;
+
+   glBegin(GL_TRIANGLE_STRIP);
+   for (y = 0; y < num; y++) {
+      glColor3fv(cv0);
+      glTexCoord2fv(tv0);
+      glVertex3fv(v0);
+
+      glColor3fv(cv1);
+      glTexCoord2fv(tv1);
+      glVertex3fv(v1);
+
+      glColor3fv(cv2);
+      glTexCoord2fv(tv2);
+      glVertex3fv(v2);
+
+      glColor3fv(cv3);
+      glTexCoord2fv(tv3);
+      glVertex3fv(v3);
+   }
+   glEnd();
+
+   return 4 * num - 2;
+}
+
+/***************************************************************************/
+
+static void
+init_test06(void)
+{
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   gluOrtho2D(-0.5, 639.5, -0.5, 479.5);
+   glMatrixMode(GL_MODELVIEW);
+
+   glShadeModel(GL_SMOOTH);
+   glEnable(GL_DEPTH_TEST);
+
+   glClearColor(0.0, 0.1, 1.0, 0.0);
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+static int
+test06(int size, int num)
+{
+   int y;
+
+   for (y = 0; y < num; y++) {
+      glClearColor(y / (float) num, 0.1, 1.0, 0.0);
+      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+   }
+
+   return num;
+}
+
+/***************************************************************************/
+
+#define BMARKS_TIME 5.0
+
+#define NUM_BMARKS 6
+
+/* 554 ~= sqrt(640*480) */
+
+static benchmark bmarks[NUM_BMARKS] = {
+   {"Simple Points", "Pnts", init_test01, test01, 0, 0,
+    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+   {"Smooth Lines", "Lins", init_test02, test02, 1, 5,
+    {480, 250, 100, 50, 25, 0, 0, 0, 0, 0}},
+   {"ZSmooth Triangles", "Tris", init_test03, test03, 1, 5,
+    {480, 250, 100, 50, 25, 0, 0, 0, 0, 0}},
+   {"ZSmooth Tex Blend Triangles", "Tris", init_test04, test04, 1, 5,
+    {480, 250, 100, 50, 25, 0, 0, 0, 0, 0}},
+   {"ZSmooth Tex Blend TMesh Triangles", "Tris", init_test05, test05, 2, 8,
+    {400, 250, 100, 50, 25, 10, 5, 2, 0, 0}},
+   {"Color/Depth Buffer Clears", "Clrs", init_test06, test06, 3, 0,
+    {554, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
+};
+
+/***************************************************************************/
+
+static void
+dotest0param(benchmark * bmark)
+{
+   float stime, etime, dtime, tottime, maxtime, mintime;
+   int num, numelem, calibnum, j;
+
+   glPushAttrib(GL_ALL_ATTRIB_BITS);
+   bmark->init();
+
+   stime = glutGet(GLUT_ELAPSED_TIME);
+
+   dtime = 0.0;
+   calibnum = 0;
+   while (dtime < 2.0) {
+      bmark->run(0, 1);
+      glFinish();
+      etime = glutGet(GLUT_ELAPSED_TIME);
+      dtime = (etime - stime) / 1000.0;
+      calibnum++;
+   }
+   glPopAttrib();
+
+   fprintf(stderr, "Elapsed time for the calibration test (%d): %f\n",
+          calibnum, dtime);
+
+   num = (int) ((BMARKS_TIME / dtime) * calibnum);
+
+   if (num < 1)
+      num = 1;
+
+   fprintf(stderr, "Selected number of benchmark iterations: %d\n", num);
+
+   mintime = HUGE_VAL;
+   maxtime = -HUGE_VAL;
+
+   for (tottime = 0.0, j = 0; j < 5; j++) {
+      glPushAttrib(GL_ALL_ATTRIB_BITS);
+      bmark->init();
+
+      stime = glutGet(GLUT_ELAPSED_TIME);
+      numelem = bmark->run(0, num);
+      glFinish();
+      etime = glutGet(GLUT_ELAPSED_TIME);
+
+      glPopAttrib();
+
+      dtime = (etime - stime) / 1000.0;
+      tottime += dtime;
+
+      fprintf(stderr, "Elapsed time for run %d: %f\n", j, dtime);
+
+      if (dtime < mintime)
+        mintime = dtime;
+      if (dtime > maxtime)
+        maxtime = dtime;
+   }
+
+   tottime -= mintime + maxtime;
+
+   fprintf(stdout, "%s\n%f %s/sec", bmark->name, numelem / (tottime / 3.0),
+          bmark->unit);
+
+   if (bmark->type == 3)
+      fprintf(stdout, ", MPixel Fill/sec: %f\n\n",
+             (numelem * bmark->size[0] * (float) bmark->size[0]) /
+             (1000000.0 * tottime / 3.0));
+   else
+      fprintf(stdout, "\n\n");
+}
+
+/***************************************************************************/
+
+static void
+dotest1param(benchmark * bmark)
+{
+   float stime, etime, dtime, tottime, maxtime, mintime;
+   int num, numelem, calibnum, j, k;
+
+   fprintf(stdout, "%s\n", bmark->name);
+
+   for (j = 0; j < bmark->numsize; j++) {
+      fprintf(stderr, "Current size: %d\n", bmark->size[j]);
+
+      glPushAttrib(GL_ALL_ATTRIB_BITS);
+      bmark->init();
+
+      stime = glutGet(GLUT_ELAPSED_TIME);
+
+      dtime = 0.0;
+      calibnum = 0;
+      while (dtime < 2.0) {
+        bmark->run(bmark->size[j], 1);
+        glFinish();
+        etime = glutGet(GLUT_ELAPSED_TIME);
+        dtime = (etime - stime) / 1000.0;
+        calibnum++;
+      }
+      glPopAttrib();
+
+      fprintf(stderr, "Elapsed time for the calibration test (%d): %f\n",
+             calibnum, dtime);
+
+      num = (int) ((BMARKS_TIME / dtime) * calibnum);
+
+      if (num < 1)
+        num = 1;
+
+      fprintf(stderr, "Selected number of benchmark iterations: %d\n", num);
+
+      mintime = HUGE_VAL;
+      maxtime = -HUGE_VAL;
+
+      for (numelem = 1, tottime = 0.0, k = 0; k < 5; k++) {
+        glPushAttrib(GL_ALL_ATTRIB_BITS);
+        bmark->init();
+
+        stime = glutGet(GLUT_ELAPSED_TIME);
+        numelem = bmark->run(bmark->size[j], num);
+        glFinish();
+        etime = glutGet(GLUT_ELAPSED_TIME);
+
+        glPopAttrib();
+
+        dtime = (etime - stime) / 1000.0;
+        tottime += dtime;
+
+        fprintf(stderr, "Elapsed time for run %d: %f\n", k, dtime);
+
+        if (dtime < mintime)
+           mintime = dtime;
+        if (dtime > maxtime)
+           maxtime = dtime;
+      }
+
+      tottime -= mintime + maxtime;
+
+      fprintf(stdout, "SIZE=%03d => %f %s/sec", bmark->size[j],
+             numelem / (tottime / 3.0), bmark->unit);
+      if (bmark->type == 2)
+        fprintf(stdout, ", MPixel Fill/sec: %f\n",
+                (numelem * bmark->size[j] * bmark->size[j] / 2) /
+                (1000000.0 * tottime / 3.0));
+      else
+        fprintf(stdout, "\n");
+   }
+
+   fprintf(stdout, "\n\n");
+}
+
+/***************************************************************************/
+
+static void
+display(void)
+{
+   int i;
+
+   if (frontbuffer)
+      glDrawBuffer(GL_FRONT);
+   else
+      glDrawBuffer(GL_BACK);
+
+   for (i = 0; i < NUM_BMARKS; i++) {
+      fprintf(stderr, "Benchmark: %d\n", i);
+
+      switch (bmarks[i].type) {
+      case 0:
+      case 3:
+        dotest0param(&bmarks[i]);
+        break;
+      case 1:
+      case 2:
+        dotest1param(&bmarks[i]);
+        break;
+      }
+   }
+
+   exit(0);
+}
+
+int
+main(int ac, char **av)
+{
+   fprintf(stderr, "GLTest v1.0\nWritten by David Bucciarelli\n");
+
+   if (ac == 2)
+      frontbuffer = 0;
+
+   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+   glutInitWindowPosition(0, 0);
+   glutInitWindowSize(640, 480);
+   glutCreateWindow("OpenGL/Mesa Performances");
+   glutDisplayFunc(display);
+   glutMainLoop();
+
+   return 0;
+}
diff --git a/progs/demos/ipers.c b/progs/demos/ipers.c
new file mode 100644 (file)
index 0000000..76da4c0
--- /dev/null
@@ -0,0 +1,704 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (tech.hmw@plus.it)
+ *            Humanware s.r.l.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <mmsystem.h>
+#endif
+
+#include <GL/glut.h>
+
+#include "../util/readtex.c"
+
+#ifdef XMESA
+#include "GL/xmesa.h"
+static int fullscreen = 1;
+#endif
+
+static int WIDTH = 640;
+static int HEIGHT = 480;
+
+#define MAX_LOD 9
+
+#define TEX_SKY_WIDTH 256
+#define TEX_SKY_HEIGHT TEX_SKY_WIDTH
+
+#ifndef M_PI
+#define M_PI 3.1415926535
+#endif
+
+#define FROM_NONE   0
+#define FROM_DOWN   1
+#define FROM_UP     2
+#define FROM_LEFT   3
+#define FROM_RIGHT  4
+#define FROM_FRONT  5
+#define FROM_BACK   6
+
+static int win = 0;
+
+static float obs[3] = { 3.8, 0.0, 0.0 };
+static float dir[3];
+static float v = 0.0;
+static float alpha = -90.0;
+static float beta = 90.0;
+
+static int fog = 1;
+static int bfcull = 1;
+static int usetex = 1;
+static int help = 1;
+static int poutline = 0;
+static int normext = 1;
+static int joyavailable = 0;
+static int joyactive = 0;
+static int LODbias = 3;
+static int maxdepth = MAX_LOD;
+
+static unsigned int totpoly = 0;
+
+static GLuint t1id, t2id;
+static GLuint skydlist, LODdlist[MAX_LOD], LODnumpoly[MAX_LOD];
+
+static void
+initlight(void)
+{
+   GLfloat lspec[4] = { 1.0, 1.0, 1.0, 1.0 };
+   static GLfloat lightpos[4] = { 30, 15.0, 30.0, 1.0 };
+
+   glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
+   glLightfv(GL_LIGHT0, GL_SPECULAR, lspec);
+
+   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 32.0);
+   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, lspec);
+}
+
+static void
+initdlists(void)
+{
+   static slicetable[MAX_LOD][2] = {
+      {21, 10},
+      {18, 9},
+      {15, 8},
+      {12, 7},
+      {9, 6},
+      {7, 5},
+      {5, 4},
+      {4, 3},
+      {3, 2}
+   };
+   GLUquadricObj *obj;
+   int i, xslices, yslices;
+
+   obj = gluNewQuadric();
+
+   skydlist = glGenLists(1);
+   glNewList(skydlist, GL_COMPILE);
+   glBindTexture(GL_TEXTURE_2D, t2id);
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+   glColor3f(1.0f, 1.0f, 1.0f);
+
+   gluQuadricDrawStyle(obj, GLU_FILL);
+   gluQuadricNormals(obj, GLU_NONE);
+   gluQuadricTexture(obj, GL_TRUE);
+   gluQuadricOrientation(obj, GLU_INSIDE);
+   gluSphere(obj, 40.0f, 18, 9);
+
+   glEndList();
+
+   for (i = 0; i < MAX_LOD; i++) {
+      LODdlist[i] = glGenLists(1);
+      glNewList(LODdlist[i], GL_COMPILE);
+
+      gluQuadricDrawStyle(obj, GLU_FILL);
+      gluQuadricNormals(obj, GLU_SMOOTH);
+      gluQuadricTexture(obj, GL_TRUE);
+      gluQuadricOrientation(obj, GLU_OUTSIDE);
+      xslices = slicetable[i][0];
+      yslices = slicetable[i][1];
+      gluSphere(obj, 1.0f, xslices, yslices);
+      LODnumpoly[i] = xslices * (yslices - 2) + 2 * (xslices - 1);
+
+      glEndList();
+   }
+}
+
+static void
+inittextures(void)
+{
+   GLubyte tsky[TEX_SKY_HEIGHT][TEX_SKY_WIDTH][3];
+   GLuint x, y;
+   GLfloat fact;
+   GLenum gluerr;
+
+   /* Brick */
+
+   glGenTextures(1, &t1id);
+   glBindTexture(GL_TEXTURE_2D, t1id);
+
+   if (!LoadRGBMipmaps("../images/bw.rgb", 3)) {
+      fprintf(stderr, "Error reading a texture.\n");
+      exit(-1);
+   }
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_LINEAR);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   /* Sky */
+
+   glGenTextures(1, &t2id);
+   glBindTexture(GL_TEXTURE_2D, t2id);
+
+   for (y = 0; y < TEX_SKY_HEIGHT; y++)
+      for (x = 0; x < TEX_SKY_WIDTH; x++)
+        if (y < TEX_SKY_HEIGHT / 2) {
+           fact = y / (GLfloat) (TEX_SKY_HEIGHT / 2);
+           tsky[y][x][0] =
+              (GLubyte) (255.0f * (0.1f * fact + 0.3f * (1.0f - fact)));
+           tsky[y][x][1] =
+              (GLubyte) (255.0f * (0.2f * fact + 1.0f * (1.0f - fact)));
+           tsky[y][x][2] = 255;
+        }
+        else {
+           tsky[y][x][0] = tsky[TEX_SKY_HEIGHT - y - 1][x][0];
+           tsky[y][x][1] = tsky[TEX_SKY_HEIGHT - y - 1][x][1];
+           tsky[y][x][2] = 255;
+        }
+
+   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+   if (
+       (gluerr =
+       gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TEX_SKY_WIDTH, TEX_SKY_HEIGHT,
+                         GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *) (tsky)))) {
+      fprintf(stderr, "GLULib%s\n", gluErrorString(gluerr));
+      exit(-1);
+   }
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_LINEAR);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+}
+
+static float
+gettime(void)
+{
+   static clock_t told = 0;
+   clock_t tnew, ris;
+
+   tnew = clock();
+
+   ris = tnew - told;
+
+   told = tnew;
+
+   return (ris / (float) CLOCKS_PER_SEC);
+}
+
+static void
+calcposobs(void)
+{
+   dir[0] = sin(alpha * M_PI / 180.0);
+   dir[1] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
+   dir[2] = cos(beta * M_PI / 180.0);
+
+   obs[0] += v * dir[0];
+   obs[1] += v * dir[1];
+   obs[2] += v * dir[2];
+}
+
+static void
+special(int k, int x, int y)
+{
+   switch (k) {
+   case GLUT_KEY_LEFT:
+      alpha -= 2.0;
+      break;
+   case GLUT_KEY_RIGHT:
+      alpha += 2.0;
+      break;
+   case GLUT_KEY_DOWN:
+      beta -= 2.0;
+      break;
+   case GLUT_KEY_UP:
+      beta += 2.0;
+      break;
+   }
+}
+
+static void
+key(unsigned char k, int x, int y)
+{
+   switch (k) {
+   case 27:
+      exit(0);
+      break;
+
+   case 'a':
+      v += 0.01;
+      break;
+   case 'z':
+      v -= 0.01;
+      break;
+
+#ifdef XMESA
+   case ' ':
+      fullscreen = (!fullscreen);
+      XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
+      break;
+#endif
+
+   case '+':
+      LODbias--;
+      break;
+   case '-':
+      LODbias++;
+      break;
+   case 'j':
+      joyactive = (!joyactive);
+      break;
+   case 'h':
+      help = (!help);
+      break;
+   case 'f':
+      fog = (!fog);
+      break;
+   case 't':
+      usetex = (!usetex);
+      break;
+   case 'n':
+      normext = (!normext);
+      break;
+   case 'b':
+      if (bfcull) {
+        glDisable(GL_CULL_FACE);
+        bfcull = 0;
+      }
+      else {
+        glEnable(GL_CULL_FACE);
+        bfcull = 1;
+      }
+      break;
+   case 'p':
+      if (poutline) {
+        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+        poutline = 0;
+        usetex = 1;
+      }
+      else {
+        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+        poutline = 1;
+        usetex = 0;
+      }
+      break;
+   }
+}
+
+static void
+reshape(int w, int h)
+{
+   WIDTH = w;
+   HEIGHT = h;
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   gluPerspective(90.0, w / (float) h, 0.8, 100.0);
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glViewport(0, 0, w, h);
+}
+
+static void
+printstring(void *font, char *string)
+{
+   int len, i;
+
+   len = (int) strlen(string);
+   for (i = 0; i < len; i++)
+      glutBitmapCharacter(font, string[i]);
+}
+
+static void
+printhelp(void)
+{
+   glEnable(GL_BLEND);
+   glColor4f(0.5, 0.5, 0.5, 0.5);
+   glRecti(40, 40, 600, 440);
+   glDisable(GL_BLEND);
+
+   glColor3f(1.0, 0.0, 0.0);
+   glRasterPos2i(300, 420);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help");
+
+   glRasterPos2i(60, 390);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Toggle Help");
+   glRasterPos2i(60, 360);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Toggle Textures");
+   glRasterPos2i(60, 330);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Toggle Fog");
+   glRasterPos2i(60, 300);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "b - Toggle Back face culling");
+   glRasterPos2i(60, 270);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate");
+   glRasterPos2i(60, 240);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity");
+   glRasterPos2i(60, 210);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity");
+   glRasterPos2i(60, 180);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "p - Toggle Wire frame");
+   glRasterPos2i(60, 150);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+              "b - Toggle GL_EXT_rescale_normal extension");
+   glRasterPos2i(60, 120);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+              "+/- - Increase/decrease the Object maximum LOD");
+
+   glRasterPos2i(60, 90);
+   if (joyavailable)
+      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+                 "j - Toggle jostick control (Joystick control available)");
+   else
+      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+                 "(No Joystick control available)");
+}
+
+static void
+dojoy(void)
+{
+#ifdef _WIN32
+   static UINT max[2] = { 0, 0 };
+   static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
+   MMRESULT res;
+   JOYINFO joy;
+
+   res = joyGetPos(JOYSTICKID1, &joy);
+
+   if (res == JOYERR_NOERROR) {
+      joyavailable = 1;
+
+      if (max[0] < joy.wXpos)
+        max[0] = joy.wXpos;
+      if (min[0] > joy.wXpos)
+        min[0] = joy.wXpos;
+      center[0] = (max[0] + min[0]) / 2;
+
+      if (max[1] < joy.wYpos)
+        max[1] = joy.wYpos;
+      if (min[1] > joy.wYpos)
+        min[1] = joy.wYpos;
+      center[1] = (max[1] + min[1]) / 2;
+
+      if (joyactive) {
+        if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
+           alpha -=
+              2.0 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
+        if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
+           beta += 2.0 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
+
+        if (joy.wButtons & JOY_BUTTON1)
+           v += 0.01;
+        if (joy.wButtons & JOY_BUTTON2)
+           v -= 0.01;
+      }
+   }
+   else
+      joyavailable = 0;
+#endif
+}
+
+static void
+drawipers(int depth, int from)
+{
+   int lod;
+
+   if (depth == maxdepth)
+      return;
+
+   lod = depth + LODbias;
+   if (lod < 0)
+      lod = 0;
+   if (lod >= MAX_LOD)
+      return;
+
+   switch (from) {
+   case FROM_NONE:
+      glCallList(LODdlist[lod]);
+
+      depth++;
+      drawipers(depth, FROM_DOWN);
+      drawipers(depth, FROM_UP);
+      drawipers(depth, FROM_FRONT);
+      drawipers(depth, FROM_BACK);
+      drawipers(depth, FROM_LEFT);
+      drawipers(depth, FROM_RIGHT);
+      break;
+   case FROM_FRONT:
+      glPushMatrix();
+      glTranslatef(0.0f, -1.5f, 0.0f);
+      glScalef(0.5f, 0.5f, 0.5f);
+
+      glCallList(LODdlist[lod]);
+
+      depth++;
+      drawipers(depth, FROM_DOWN);
+      drawipers(depth, FROM_UP);
+      drawipers(depth, FROM_FRONT);
+      drawipers(depth, FROM_LEFT);
+      drawipers(depth, FROM_RIGHT);
+      glPopMatrix();
+      break;
+   case FROM_BACK:
+      glPushMatrix();
+      glTranslatef(0.0f, 1.5f, 0.0f);
+      glScalef(0.5f, 0.5f, 0.5f);
+
+      glCallList(LODdlist[lod]);
+
+      depth++;
+      drawipers(depth, FROM_DOWN);
+      drawipers(depth, FROM_UP);
+      drawipers(depth, FROM_BACK);
+      drawipers(depth, FROM_LEFT);
+      drawipers(depth, FROM_RIGHT);
+      glPopMatrix();
+      break;
+   case FROM_LEFT:
+      glPushMatrix();
+      glTranslatef(-1.5f, 0.0f, 0.0f);
+      glScalef(0.5f, 0.5f, 0.5f);
+
+      glCallList(LODdlist[lod]);
+
+      depth++;
+      drawipers(depth, FROM_DOWN);
+      drawipers(depth, FROM_UP);
+      drawipers(depth, FROM_FRONT);
+      drawipers(depth, FROM_BACK);
+      drawipers(depth, FROM_LEFT);
+      glPopMatrix();
+      break;
+   case FROM_RIGHT:
+      glPushMatrix();
+      glTranslatef(1.5f, 0.0f, 0.0f);
+      glScalef(0.5f, 0.5f, 0.5f);
+
+      glCallList(LODdlist[lod]);
+
+      depth++;
+      drawipers(depth, FROM_DOWN);
+      drawipers(depth, FROM_UP);
+      drawipers(depth, FROM_FRONT);
+      drawipers(depth, FROM_BACK);
+      drawipers(depth, FROM_RIGHT);
+      glPopMatrix();
+      break;
+   case FROM_DOWN:
+      glPushMatrix();
+      glTranslatef(0.0f, 0.0f, 1.5f);
+      glScalef(0.5f, 0.5f, 0.5f);
+
+      glCallList(LODdlist[lod]);
+
+      depth++;
+      drawipers(depth, FROM_DOWN);
+      drawipers(depth, FROM_FRONT);
+      drawipers(depth, FROM_BACK);
+      drawipers(depth, FROM_LEFT);
+      drawipers(depth, FROM_RIGHT);
+      glPopMatrix();
+      break;
+   case FROM_UP:
+      glPushMatrix();
+      glTranslatef(0.0f, 0.0f, -1.5f);
+      glScalef(0.5f, 0.5f, 0.5f);
+
+      glCallList(LODdlist[lod]);
+
+      depth++;
+      drawipers(depth, FROM_UP);
+      drawipers(depth, FROM_FRONT);
+      drawipers(depth, FROM_BACK);
+      drawipers(depth, FROM_LEFT);
+      drawipers(depth, FROM_RIGHT);
+      glPopMatrix();
+      break;
+   }
+
+   totpoly += LODnumpoly[lod];
+}
+
+static void
+draw(void)
+{
+   static int count = 0;
+   static char frbuf[80];
+   static GLfloat alpha = 0.0f;
+   static GLfloat beta = 0.0f;
+   float fr;
+
+   dojoy();
+
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   if (usetex)
+      glEnable(GL_TEXTURE_2D);
+   else
+      glDisable(GL_TEXTURE_2D);
+
+   if (fog)
+      glEnable(GL_FOG);
+   else
+      glDisable(GL_FOG);
+
+   glPushMatrix();
+   calcposobs();
+   gluLookAt(obs[0], obs[1], obs[2],
+            obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
+            0.0, 0.0, 1.0);
+
+   /* Scene */
+   glEnable(GL_DEPTH_TEST);
+
+   glShadeModel(GL_SMOOTH);
+   glBindTexture(GL_TEXTURE_2D, t1id);
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+   glColor3f(1.0f, 1.0f, 1.0f);
+   glEnable(GL_LIGHT0);
+   glEnable(GL_LIGHTING);
+
+   if (normext)
+      glEnable(GL_RESCALE_NORMAL_EXT);
+   else
+      glEnable(GL_NORMALIZE);
+
+   glPushMatrix();
+   glRotatef(alpha, 0.0f, 0.0f, 1.0f);
+   glRotatef(beta, 1.0f, 0.0f, 0.0f);
+   totpoly = 0;
+   drawipers(0, FROM_NONE);
+   glPopMatrix();
+
+   alpha += 0.5f;
+   beta += 0.3f;
+
+   glDisable(GL_LIGHTING);
+   glDisable(GL_LIGHT0);
+   glShadeModel(GL_FLAT);
+
+   if (normext)
+      glDisable(GL_RESCALE_NORMAL_EXT);
+   else
+      glDisable(GL_NORMALIZE);
+
+   glCallList(skydlist);
+
+   glPopMatrix();
+
+   /* Help Screen */
+
+   fr = gettime();
+   sprintf(frbuf,
+          "Frame rate: %0.2f   LOD: %d   Tot. poly.: %d   Poly/sec: %.1f",
+          1.0 / fr, LODbias, totpoly, totpoly / fr);
+
+   glDisable(GL_TEXTURE_2D);
+   glDisable(GL_FOG);
+   glShadeModel(GL_FLAT);
+   glDisable(GL_DEPTH_TEST);
+
+   glMatrixMode(GL_PROJECTION);
+   glPushMatrix();
+   glLoadIdentity();
+   glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
+
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+
+   glColor3f(1.0, 0.0, 0.0);
+   glRasterPos2i(10, 10);
+   printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
+   glRasterPos2i(350, 470);
+   printstring(GLUT_BITMAP_HELVETICA_10,
+              "IperS V1.0 Written by David Bucciarelli (tech.hmw@plus.it)");
+
+   if (help)
+      printhelp();
+
+   glMatrixMode(GL_PROJECTION);
+   glPopMatrix();
+   glMatrixMode(GL_MODELVIEW);
+
+   glutSwapBuffers();
+
+   count++;
+}
+
+int
+main(int ac, char **av)
+{
+   float fogcolor[4] = { 0.7, 0.7, 0.7, 1.0 };
+
+   fprintf(stderr,
+          "IperS V1.0\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
+
+   glutInitWindowPosition(0, 0);
+   glutInitWindowSize(WIDTH, HEIGHT);
+   glutInit(&ac, av);
+
+   glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
+
+   if (!(win = glutCreateWindow("IperS"))) {
+      fprintf(stderr, "Error, couldn't open window\n");
+      exit(-1);
+   }
+
+   reshape(WIDTH, HEIGHT);
+
+   glShadeModel(GL_SMOOTH);
+   glEnable(GL_DEPTH_TEST);
+   glEnable(GL_CULL_FACE);
+   glEnable(GL_TEXTURE_2D);
+
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+   glEnable(GL_FOG);
+   glFogi(GL_FOG_MODE, GL_EXP2);
+   glFogfv(GL_FOG_COLOR, fogcolor);
+
+   glFogf(GL_FOG_DENSITY, 0.006);
+
+   glHint(GL_FOG_HINT, GL_NICEST);
+
+   inittextures();
+   initdlists();
+   initlight();
+
+   glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
+   glClear(GL_COLOR_BUFFER_BIT);
+
+   calcposobs();
+
+   glutReshapeFunc(reshape);
+   glutDisplayFunc(draw);
+   glutKeyboardFunc(key);
+   glutSpecialFunc(special);
+   glutIdleFunc(draw);
+
+   glutMainLoop();
+
+   return 0;
+}
diff --git a/progs/demos/particles.cxx b/progs/demos/particles.cxx
new file mode 100644 (file)
index 0000000..b88c318
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (humanware@plus.it)
+ *            Humanware s.r.l.
+ */
+
+#include <stdlib.h>
+
+#include "particles.h"
+
+#define vinit(a,i,j,k) {\
+  (a)[0]=i;\
+  (a)[1]=j;\
+  (a)[2]=k;\
+}
+
+#define vadds(a,dt,b) {\
+  (a)[0]+=(dt)*(b)[0];\
+  (a)[1]+=(dt)*(b)[1];\
+  (a)[2]+=(dt)*(b)[2];\
+}
+
+#define vequ(a,b) {\
+  (a)[0]=(b)[0];\
+  (a)[1]=(b)[1];\
+  (a)[2]=(b)[2];\
+}
+
+#define vinter(a,dt,b,c) {\
+  (a)[0]=(dt)*(b)[0]+(1.0-dt)*(c)[0];\
+  (a)[1]=(dt)*(b)[1]+(1.0-dt)*(c)[1];\
+  (a)[2]=(dt)*(b)[2]+(1.0-dt)*(c)[2];\
+}
+
+#define clamp(a)        ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0))
+
+#define vclamp(v) {\
+  (v)[0]=clamp((v)[0]);\
+  (v)[1]=clamp((v)[1]);\
+  (v)[2]=clamp((v)[2]);\
+}
+
+
+float rainParticle::min[3];
+float rainParticle::max[3];
+float rainParticle::partLength=0.2f;
+
+
+static float vrnd(void)
+{
+  return(((float)rand())/RAND_MAX);
+}
+
+
+particle::particle()
+{
+  age=0.0f;
+
+  vinit(acc,0.0f,0.0f,0.0f);
+  vinit(vel,0.0f,0.0f,0.0f);
+  vinit(pos,0.0f,0.0f,0.0f);
+}
+
+void particle::elapsedTime(float dt)
+{
+  age+=dt;
+
+  vadds(vel,dt,acc);
+
+  vadds(pos,dt,vel);
+}
+
+/////////////////////////////////////////
+// Particle System
+/////////////////////////////////////////
+
+particleSystem::particleSystem()
+{
+  t=0.0f;
+
+  part=NULL;
+
+  particleNum=0;
+}
+
+particleSystem::~particleSystem()
+{
+  if(part)
+    free(part);
+}
+
+void particleSystem::addParticle(particle *p)
+{
+  if(!part) {
+    part=(particle **)calloc(1,sizeof(particle *));
+    part[0]=p;
+    particleNum=1;
+  } else {
+    particleNum++;
+    part=(particle **)realloc(part,sizeof(particle *)*particleNum);
+    part[particleNum-1]=p;
+  }
+}
+
+void particleSystem::reset(void)
+{
+  if(part)
+    free(part);
+
+  t=0.0f;
+
+  part=NULL;
+
+  particleNum=0;
+}
+
+void particleSystem::draw(void)
+{
+  if(!part)
+    return;
+
+  part[0]->beginDraw();
+  for(unsigned int i=0;i<particleNum;i++)
+    part[i]->draw();
+  part[0]->endDraw();
+}
+
+void particleSystem::addTime(float dt)
+{
+  if(!part)
+    return;
+
+  for(unsigned int i=0;i<particleNum;i++) {
+    part[i]->elapsedTime(dt);
+    part[i]->checkAge();
+  }
+}
+
+/////////////////////////////////////////
+// Rain
+/////////////////////////////////////////
+
+void rainParticle::init(void)
+{
+  age=0.0f;
+
+  acc[0]=0.0f;
+  acc[1]=-0.98f;
+  acc[2]=0.0f;
+
+  vel[0]=0.0f;
+  vel[1]=0.0f;
+  vel[2]=0.0f;
+
+  oldpos[0]=pos[0]=min[0]+(max[0]-min[0])*vrnd();
+  oldpos[1]=pos[1]=max[1]+0.2f*max[1]*vrnd();
+  oldpos[2]=pos[2]=min[2]+(max[2]-min[2])*vrnd();
+
+  vadds(oldpos,-partLength,vel);
+}
+
+rainParticle::rainParticle()
+{ 
+  init();
+}
+
+void rainParticle::setRainingArea(float minx, float miny, float minz,
+                                 float maxx, float maxy, float maxz)
+{
+  vinit(min,minx,miny,minz);
+  vinit(max,maxx,maxy,maxz);
+}
+
+void rainParticle::setLength(float l)
+{
+  partLength=l;
+}
+
+void rainParticle::draw(void)
+{
+  glColor4f(0.7f,0.95f,1.0f,0.0f);
+  glVertex3fv(oldpos);
+
+  glColor4f(0.3f,0.7f,1.0f,1.0f);
+  glVertex3fv(pos);
+}
+
+void rainParticle::checkAge(void)
+{
+  if(pos[1]<min[1])
+    init();
+}
+
+void rainParticle::elapsedTime(float dt)
+{
+  particle::elapsedTime(dt);
+
+  if(pos[0]<min[0])
+    pos[0]=max[0]-(min[0]-pos[0]);
+  if(pos[2]<min[2])
+    pos[2]=max[2]-(min[2]-pos[2]);
+
+  if(pos[0]>max[0])
+    pos[0]=min[0]+(pos[0]-max[0]);
+  if(pos[2]>max[2])
+    pos[2]=min[2]+(pos[2]-max[2]);
+
+  vequ(oldpos,pos);
+  vadds(oldpos,-partLength,vel);
+}
+
+void rainParticle::randomHeight(void)
+{
+  pos[1]=(max[1]-min[1])*vrnd()+min[1];
+
+  oldpos[1]=pos[1]-partLength*vel[1];
+}
diff --git a/progs/demos/particles.h b/progs/demos/particles.h
new file mode 100644 (file)
index 0000000..a49dd69
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (humanware@plus.it)
+ *            Humanware s.r.l.
+ */
+
+#ifndef PARTICLES_H
+#define PARTICLES_H
+
+#include <GL/gl.h>
+
+class particle {
+ protected:
+  float age;         // in seconds
+  float acc[3];
+  float vel[3];
+  float pos[3];
+
+ public:
+  particle();
+  virtual ~particle() {};
+
+  virtual void beginDraw(void) {};
+  virtual void draw(void)=0;
+  virtual void endDraw(void) {};
+
+  virtual void elapsedTime(float);
+  virtual void checkAge(void) {};
+};
+
+class particleSystem {
+ protected:
+  particle **part;
+
+  float t;
+
+  unsigned long particleNum;
+ public:
+  particleSystem();
+  ~particleSystem();
+
+  void addParticle(particle *);
+
+  void reset(void);
+
+  void draw(void);
+
+  void addTime(float);
+};
+
+class rainParticle : public particle {
+ protected:
+  static float min[3];
+  static float max[3];
+  static float partLength;
+
+  float oldpos[3];
+
+  void init(void);
+ public:
+  rainParticle();
+
+  static void setRainingArea(float, float, float,
+                            float, float, float);
+  static void setLength(float);
+  static float getLength(void) { return partLength; };
+
+  void beginDraw(void) { glBegin(GL_LINES); };
+  void draw(void);
+  void endDraw(void) { glEnd(); };
+
+  void elapsedTime(float);
+
+  void checkAge(void);
+
+  void randomHeight(void);
+};
+
+#endif
diff --git a/progs/demos/rain.cxx b/progs/demos/rain.cxx
new file mode 100644 (file)
index 0000000..4a7ecde
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (humanware@plus.it)
+ *            Humanware s.r.l.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include <GL/glut.h>
+
+#include "particles.h"
+extern "C" {
+#include "image.h"
+}
+
+#ifdef WIN32
+#include <windows.h>
+#include <mmsystem.h>
+#endif
+
+#ifdef XMESA
+#include "GL/xmesa.h"
+static int fullscreen=1;
+#endif
+
+static int WIDTH=640;
+static int HEIGHT=480;
+static int NUMPART=7500;
+
+#define FRAME 50
+
+static float fogcolor[4]={1.0,1.0,1.0,1.0};
+
+#define DIMP 40.0
+#define DIMTP 32.0
+
+static float q[4][3]={
+  {-DIMP,0.0,-DIMP},
+  {DIMP,0.0,-DIMP},
+  {DIMP,0.0,DIMP},
+  {-DIMP,0.0,DIMP}
+};
+
+static float qt[4][2]={
+  {-DIMTP,-DIMTP},
+  {DIMTP,-DIMTP},
+  {DIMTP,DIMTP},
+  {-DIMTP,DIMTP}
+};
+
+static int win=0;
+
+static int fog=1;
+static int help=1;
+
+static GLuint groundid;
+
+static float obs[3]={2.0,1.0,0.0};
+static float dir[3];
+static float v=0.0;
+static float alpha=-90.0;
+static float beta=90.0;
+
+static particleSystem *ps;
+
+static float gettime()
+{
+  static clock_t told=0;
+  clock_t tnew,ris;
+
+  tnew=clock();
+
+  ris=tnew-told;
+
+  told=tnew;
+
+  return(ris/(float)CLOCKS_PER_SEC);
+}
+
+static float gettimerain()
+{
+  static clock_t told=0;
+  clock_t tnew,ris;
+
+  tnew=clock();
+
+  ris=tnew-told;
+
+  told=tnew;
+
+  return(ris/(float)CLOCKS_PER_SEC);
+}
+
+static void calcposobs(void)
+{
+  dir[0]=sin(alpha*M_PI/180.0);
+  dir[2]=cos(alpha*M_PI/180.0)*sin(beta*M_PI/180.0);
+  dir[1]=cos(beta*M_PI/180.0);
+
+  obs[0]+=v*dir[0];
+  obs[1]+=v*dir[1];
+  obs[2]+=v*dir[2];
+
+  rainParticle::setRainingArea(obs[0]-7.0f,-0.2f,obs[2]-7.0f,obs[0]+7.0f,8.0f,obs[2]+7.0f);
+}
+
+static void printstring(void *font, char *string)
+{
+  int len,i;
+
+  len=(int)strlen(string);
+  for(i=0;i<len;i++)
+    glutBitmapCharacter(font,string[i]);
+}
+
+static void reshape(int width, int height)
+{
+  WIDTH=width;
+  HEIGHT=height;
+  glViewport(0,0,(GLint)width,(GLint)height);
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  gluPerspective(70.0,width/(float)height,0.1,30.0);
+
+  glMatrixMode(GL_MODELVIEW);
+}
+
+static void printhelp(void)
+{
+  glEnable(GL_BLEND);
+  glColor4f(0.0,0.0,0.0,0.5);
+  glRecti(40,40,600,440);
+  glDisable(GL_BLEND);
+
+  glColor3f(1.0,0.0,0.0);
+  glRasterPos2i(300,420);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"Help");
+
+  glRasterPos2i(60,390);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"h - Togle Help");
+
+  glRasterPos2i(60,360);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"f - Togle Fog");
+  glRasterPos2i(60,330);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"Arrow Keys - Rotate");
+  glRasterPos2i(60,300);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"a - Increase velocity");
+  glRasterPos2i(60,270);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"z - Decrease velocity");
+  glRasterPos2i(60,240);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"l - Increase rain length");
+  glRasterPos2i(60,210);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"k - Increase rain length");
+}
+
+static void drawrain(void)
+{
+  static int count=0;
+  static char frbuf[80];
+  float fr;
+
+  glEnable(GL_DEPTH_TEST);
+
+  if(fog)
+    glEnable(GL_FOG);
+  else
+    glDisable(GL_FOG);
+
+  glDepthMask(GL_TRUE);
+  glClearColor(1.0,1.0,1.0,1.0);
+  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+
+  glPushMatrix();
+  calcposobs();
+  gluLookAt(obs[0],obs[1],obs[2],
+           obs[0]+dir[0],obs[1]+dir[1],obs[2]+dir[2],
+           0.0,1.0,0.0);
+
+  glColor4f(1.0,1.0,1.0,1.0);
+
+  glEnable(GL_TEXTURE_2D);
+
+  glBindTexture(GL_TEXTURE_2D,groundid);
+  glBegin(GL_QUADS);
+  glTexCoord2fv(qt[0]);
+  glVertex3fv(q[0]);
+  glTexCoord2fv(qt[1]);
+  glVertex3fv(q[1]);
+  glTexCoord2fv(qt[2]);
+  glVertex3fv(q[2]);
+  glTexCoord2fv(qt[3]);
+  glVertex3fv(q[3]);
+  glEnd();
+
+  // Particle System
+
+  glDisable(GL_TEXTURE_2D);
+  glShadeModel(GL_SMOOTH);
+  glEnable(GL_BLEND);
+
+  ps->draw();
+  ps->addTime(gettimerain());
+  
+  glShadeModel(GL_FLAT);
+
+  if((count % FRAME)==0) {
+    fr=gettime();
+    sprintf(frbuf,"Frame rate: %f",FRAME/fr);
+  }
+
+  glDisable(GL_TEXTURE_2D);
+  glDisable(GL_DEPTH_TEST);
+  glDisable(GL_FOG);
+
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  glOrtho(-0.5,639.5,-0.5,479.5,-1.0,1.0);
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+
+  glColor3f(1.0,0.0,0.0);
+  glRasterPos2i(10,10);
+  printstring(GLUT_BITMAP_HELVETICA_18,frbuf);
+  glRasterPos2i(350,470);
+  printstring(GLUT_BITMAP_HELVETICA_10,"Rain V1.0 Written by David Bucciarelli (humanware@plus.it)");
+
+  if(help)
+    printhelp();
+
+  reshape(WIDTH,HEIGHT);
+  glPopMatrix();
+
+  glutSwapBuffers();
+
+  count++;
+}
+
+
+static void special(int key, int x, int y)
+{
+  switch (key) {
+  case GLUT_KEY_LEFT:
+    alpha+=2.0;
+    break;
+  case GLUT_KEY_RIGHT:
+    alpha-=2.0;
+    break;
+  case GLUT_KEY_DOWN:
+    beta-=2.0;
+    break;
+  case GLUT_KEY_UP:
+    beta+=2.0;
+    break;
+  }
+}
+
+static void key(unsigned char key, int x, int y)
+{
+  switch (key) {
+  case 27:
+    exit(0);
+    break;
+
+  case 'a':
+    v+=0.01;
+    break;
+  case 'z':
+    v-=0.01;
+    break;
+
+  case 'l':
+    rainParticle::setLength(rainParticle::getLength()+0.025f);
+    break;
+  case 'k':
+    rainParticle::setLength(rainParticle::getLength()-0.025f);
+    break;
+
+  case 'h':
+    help=(!help);
+    break;
+  case 'f':
+    fog=(!fog);
+    break;
+#ifdef XMESA
+  case ' ':
+    XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
+    fullscreen=(!fullscreen);
+    break;
+#endif
+  }
+}
+
+static void inittextures(void)
+{
+  IMAGE *img;
+  GLenum gluerr;
+
+  glGenTextures(1,&groundid);
+  glBindTexture(GL_TEXTURE_2D,groundid);
+
+  if(!(img=ImageLoad("s128.rgb"))) {
+    fprintf(stderr,"Error reading a texture.\n");
+    exit(-1);
+  }
+
+  glPixelStorei(GL_UNPACK_ALIGNMENT,4);
+  if((gluerr=(GLenum)gluBuild2DMipmaps(GL_TEXTURE_2D, 3, img->sizeX, img->sizeY, GL_RGB,
+                              GL_UNSIGNED_BYTE, (GLvoid *)(img->data)))) {
+    fprintf(stderr,"GLULib%s\n",gluErrorString(gluerr));
+    exit(-1);
+  }
+
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
+
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+
+  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
+}
+
+static void initparticle(void)
+{
+  ps=new particleSystem;
+
+  rainParticle::setRainingArea(-7.0f,-0.2f,-7.0f,7.0f,8.0f,7.0f);
+
+  for(int i=0;i<NUMPART;i++) {
+    rainParticle *p=new rainParticle;
+    p->randomHeight();
+
+    ps->addParticle((particle *)p);
+  }
+}
+
+int main(int ac,char **av)
+{
+  fprintf(stderr,"Rain V1.0\nWritten by David Bucciarelli (humanware@plus.it)\n");
+
+  /* Default settings */
+
+  WIDTH=640;
+  HEIGHT=480;
+
+  glutInitWindowPosition(0,0);
+  glutInitWindowSize(WIDTH,HEIGHT);
+  glutInit(&ac,av);
+
+  glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE);
+
+  if(!(win=glutCreateWindow("Rain"))) {
+    fprintf(stderr,"Error opening a window.\n");
+    exit(-1);
+  }
+  
+  reshape(WIDTH,HEIGHT);
+
+  inittextures();
+
+  glShadeModel(GL_FLAT);
+  glEnable(GL_DEPTH_TEST);
+
+  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+  glEnable(GL_FOG);
+  glFogi(GL_FOG_MODE,GL_EXP);
+  glFogfv(GL_FOG_COLOR,fogcolor);
+  glFogf(GL_FOG_DENSITY,0.1);
+#ifdef FX
+  glHint(GL_FOG_HINT,GL_NICEST);
+#endif
+
+  initparticle();
+
+  glutKeyboardFunc(key);
+  glutSpecialFunc(special);
+  glutDisplayFunc(drawrain);
+  glutIdleFunc(drawrain);
+  glutReshapeFunc(reshape);
+  glutMainLoop();
+
+  return(0);
+}
diff --git a/progs/demos/ray.c b/progs/demos/ray.c
new file mode 100644 (file)
index 0000000..24f27a0
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (tech.hmw@plus.it)
+ *            Humanware s.r.l.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <GL/glut.h>
+
+#ifdef XMESA
+#include "GL/xmesa.h"
+static int fullscreen = 1;
+#endif
+
+static int WIDTH = 640;
+static int HEIGHT = 480;
+
+#define FRAME 50
+
+#define BASESIZE 7.5f
+#define SPHERE_RADIUS 0.75f
+
+#define TEX_CHECK_WIDTH 256
+#define TEX_CHECK_HEIGHT 256
+#define TEX_CHECK_SLOT_SIZE (TEX_CHECK_HEIGHT/16)
+#define TEX_CHECK_NUMSLOT (TEX_CHECK_HEIGHT/TEX_CHECK_SLOT_SIZE)
+
+#define TEX_REFLECT_WIDTH 256
+#define TEX_REFLECT_HEIGHT 256
+#define TEX_REFLECT_SLOT_SIZE (TEX_REFLECT_HEIGHT/16)
+#define TEX_REFLECT_NUMSLOT (TEX_REFLECT_HEIGHT/TEX_REFLECT_SLOT_SIZE)
+
+#ifndef M_PI
+#define M_PI 3.1415926535
+#endif
+
+#define EPSILON 0.0001
+
+#define clamp255(a)  ( (a)<(0.0f) ? (0.0f) : ((a)>(255.0f) ? (255.0f) : (a)) )
+
+#define fabs(x) ((x)<0.0f?-(x):(x))
+
+#define vequ(a,b) { (a)[0]=(b)[0]; (a)[1]=(b)[1]; (a)[2]=(b)[2]; }
+#define vsub(a,b,c) { (a)[0]=(b)[0]-(c)[0]; (a)[1]=(b)[1]-(c)[1]; (a)[2]=(b)[2]-(c)[2]; }
+#define        dprod(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2])
+#define vnormalize(a,b) { \
+  register float m_norm; \
+  m_norm=sqrt((double)dprod((a),(a))); \
+  (a)[0] /=m_norm; \
+  (a)[1] /=m_norm; \
+  (a)[2] /=m_norm; }
+
+static GLubyte checkmap[TEX_CHECK_HEIGHT][TEX_CHECK_WIDTH][3];
+static GLuint checkid;
+static int checkmap_currentslot = 0;
+
+static GLubyte reflectmap[TEX_REFLECT_HEIGHT][TEX_REFLECT_WIDTH][3];
+static GLuint reflectid;
+static int reflectmap_currentslot = 0;
+
+static GLuint lightdlist;
+static GLuint objdlist;
+
+static float lightpos[3] = { 2.1, 2.1, 2.8 };
+static float objpos[3] = { 0.0, 0.0, 1.0 };
+
+static float sphere_pos[TEX_CHECK_HEIGHT][TEX_REFLECT_WIDTH][3];
+
+static int win = 0;
+
+static float fogcolor[4] = { 0.05, 0.05, 0.05, 1.0 };
+
+static float obs[3] = { 7.0, 0.0, 2.0 };
+static float dir[3];
+static float v = 0.0;
+static float alpha = -90.0;
+static float beta = 90.0;
+
+static int fog = 1;
+static int bfcull = 1;
+static int poutline = 0;
+static int help = 1;
+static int showcheckmap = 1;
+static int showreflectmap = 1;
+static int joyavailable = 0;
+static int joyactive = 0;
+
+static float
+gettime(void)
+{
+   static float told = 0.0f;
+   float tnew, ris;
+
+   tnew = glutGet(GLUT_ELAPSED_TIME);
+
+   ris = tnew - told;
+
+   told = tnew;
+
+   return ris / 1000.0;
+}
+
+static void
+calcposobs(void)
+{
+   dir[0] = sin(alpha * M_PI / 180.0);
+   dir[1] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
+   dir[2] = cos(beta * M_PI / 180.0);
+
+   obs[0] += v * dir[0];
+   obs[1] += v * dir[1];
+   obs[2] += v * dir[2];
+}
+
+static void
+special(int k, int x, int y)
+{
+   switch (k) {
+   case GLUT_KEY_LEFT:
+      alpha -= 2.0;
+      break;
+   case GLUT_KEY_RIGHT:
+      alpha += 2.0;
+      break;
+   case GLUT_KEY_DOWN:
+      beta -= 2.0;
+      break;
+   case GLUT_KEY_UP:
+      beta += 2.0;
+      break;
+   }
+}
+
+static void
+key(unsigned char k, int x, int y)
+{
+   switch (k) {
+   case 27:
+      exit(0);
+      break;
+
+   case 's':
+      lightpos[1] -= 0.1;
+      break;
+   case 'd':
+      lightpos[1] += 0.1;
+      break;
+   case 'e':
+      lightpos[0] -= 0.1;
+      break;
+   case 'x':
+      lightpos[0] += 0.1;
+      break;
+   case 'w':
+      lightpos[2] -= 0.1;
+      break;
+   case 'r':
+      lightpos[2] += 0.1;
+      break;
+
+   case 'j':
+      objpos[1] -= 0.1;
+      break;
+   case 'k':
+      objpos[1] += 0.1;
+      break;
+   case 'i':
+      objpos[0] -= 0.1;
+      break;
+   case 'm':
+      objpos[0] += 0.1;
+      break;
+   case 'u':
+      objpos[2] -= 0.1;
+      break;
+   case 'o':
+      objpos[2] += 0.1;
+      break;
+
+   case 'a':
+      v += 0.005;
+      break;
+   case 'z':
+      v -= 0.005;
+      break;
+
+   case 'g':
+      joyactive = (!joyactive);
+      break;
+   case 'h':
+      help = (!help);
+      break;
+   case 'f':
+      fog = (!fog);
+      break;
+
+   case '1':
+      showcheckmap = (!showcheckmap);
+      break;
+   case '2':
+      showreflectmap = (!showreflectmap);
+      break;
+
+   case 'b':
+      if (bfcull) {
+        glDisable(GL_CULL_FACE);
+        bfcull = 0;
+      }
+      else {
+        glEnable(GL_CULL_FACE);
+        bfcull = 1;
+      }
+      break;
+   case 'p':
+      if (poutline) {
+        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+        poutline = 0;
+      }
+      else {
+        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+        poutline = 1;
+      }
+      break;
+#ifdef XMESA
+   case ' ':
+      XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
+      fullscreen = (!fullscreen);
+      break;
+#endif
+   }
+}
+
+static void
+reshape(int w, int h)
+{
+   WIDTH = w;
+   HEIGHT = h;
+   glViewport(0, 0, w, h);
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   gluPerspective(45.0, w / (float) h, 0.8, 40.0);
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+}
+
+static void
+printstring(void *font, char *string)
+{
+   int len, i;
+
+   len = (int) strlen(string);
+   for (i = 0; i < len; i++)
+      glutBitmapCharacter(font, string[i]);
+}
+
+static void
+printhelp(void)
+{
+   glEnable(GL_BLEND);
+   glColor4f(0.5, 0.5, 0.5, 0.5);
+   glRecti(40, 40, 600, 440);
+   glDisable(GL_BLEND);
+
+   glColor3f(0.0, 0.0, 1.0);
+   glRasterPos2i(300, 420);
+   printstring(GLUT_BITMAP_HELVETICA_18, "Help");
+
+   glRasterPos2i(60, 390);
+   printstring(GLUT_BITMAP_HELVETICA_12, "h - Togle Help");
+   glRasterPos2i(60, 370);
+   printstring(GLUT_BITMAP_HELVETICA_12, "f - Togle Fog");
+   glRasterPos2i(60, 350);
+   printstring(GLUT_BITMAP_HELVETICA_12, "b - Togle Back face culling");
+   glRasterPos2i(60, 330);
+   printstring(GLUT_BITMAP_HELVETICA_12, "p - Togle Wire frame");
+   glRasterPos2i(60, 310);
+   printstring(GLUT_BITMAP_HELVETICA_12, "Arrow Keys - Rotate");
+   glRasterPos2i(60, 290);
+   printstring(GLUT_BITMAP_HELVETICA_12, "a - Increase velocity");
+   glRasterPos2i(60, 270);
+   printstring(GLUT_BITMAP_HELVETICA_12, "z - Decrease velocity");
+
+   glRasterPos2i(60, 250);
+   if (joyavailable)
+      printstring(GLUT_BITMAP_HELVETICA_12,
+                 "j - Togle jostick control (Joystick control available)");
+   else
+      printstring(GLUT_BITMAP_HELVETICA_12,
+                 "(No Joystick control available)");
+
+   glRasterPos2i(60, 230);
+   printstring(GLUT_BITMAP_HELVETICA_12,
+              "To move the light source: s - left,  d - right,  e - far,  x - near,  w - down r - up");
+   glRasterPos2i(60, 210);
+   printstring(GLUT_BITMAP_HELVETICA_12,
+              "To move the mirror sphere: j - left,  k - right,  i - far,  m - near,  u - down o - up");
+
+   glRasterPos2i(60, 190);
+   printstring(GLUT_BITMAP_HELVETICA_12,
+              "1 - Togle the plane texture map window");
+
+   glRasterPos2i(60, 170);
+   printstring(GLUT_BITMAP_HELVETICA_12,
+              "2 - Togle the sphere texture map window");
+}
+
+static GLboolean
+seelight(float p[3], float dir[3])
+{
+   float c[3], b, a, d, t, dist[3];
+
+   vsub(c, p, objpos);
+   b = -dprod(c, dir);
+   a = dprod(c, c) - SPHERE_RADIUS * SPHERE_RADIUS;
+
+   if ((d = b * b - a) < 0.0 || (b < 0.0 && a > 0.0))
+      return GL_FALSE;
+
+   d = sqrt(d);
+
+   t = b - d;
+
+   if (t < EPSILON) {
+      t = b + d;
+      if (t < EPSILON)
+        return GL_FALSE;
+   }
+
+   vsub(dist, lightpos, p);
+   if (dprod(dist, dist) < t * t)
+      return GL_FALSE;
+
+   return GL_TRUE;
+}
+
+static int
+colorcheckmap(float ppos[3], float c[3])
+{
+   static float norm[3] = { 0.0f, 0.0f, 1.0f };
+   float ldir[3], vdir[3], h[3], dfact, kfact, r, g, b;
+   int x, y;
+
+   x = (int) ((ppos[0] + BASESIZE / 2) * (10.0f / BASESIZE));
+   if ((x < 0) || (x > 10))
+      return GL_FALSE;
+
+   y = (int) ((ppos[1] + BASESIZE / 2) * (10.0f / BASESIZE));
+   if ((y < 0) || (y > 10))
+      return GL_FALSE;
+
+   r = 255.0f;
+   if (y & 1) {
+      if (x & 1)
+        g = 255.0f;
+      else
+        g = 0.0f;
+   }
+   else {
+      if (x & 1)
+        g = 0.0f;
+      else
+        g = 255.0f;
+   }
+   b = 0.0f;
+
+   vsub(ldir, lightpos, ppos);
+   vnormalize(ldir, ldir);
+
+   if (seelight(ppos, ldir)) {
+      c[0] = r * 0.05f;
+      c[1] = g * 0.05f;
+      c[2] = b * 0.05f;
+
+      return GL_TRUE;
+   }
+
+   dfact = dprod(ldir, norm);
+   if (dfact < 0.0f)
+      dfact = 0.0f;
+
+   vsub(vdir, obs, ppos);
+   vnormalize(vdir, vdir);
+   h[0] = 0.5f * (vdir[0] + ldir[0]);
+   h[1] = 0.5f * (vdir[1] + ldir[1]);
+   h[2] = 0.5f * (vdir[2] + ldir[2]);
+   kfact = dprod(h, norm);
+   kfact =
+      kfact * kfact * kfact * kfact * kfact * kfact * kfact * 7.0f * 255.0f;
+
+   r = r * dfact + kfact;
+   g = g * dfact + kfact;
+   b = b * dfact + kfact;
+
+   c[0] = clamp255(r);
+   c[1] = clamp255(g);
+   c[2] = clamp255(b);
+
+   return GL_TRUE;
+}
+
+static void
+updatecheckmap(int slot)
+{
+   float c[3], ppos[3];
+   int x, y;
+
+   glBindTexture(GL_TEXTURE_2D, checkid);
+
+   ppos[2] = 0.0f;
+   for (y = slot * TEX_CHECK_SLOT_SIZE; y < (slot + 1) * TEX_CHECK_SLOT_SIZE;
+       y++) {
+      ppos[1] = (y / (float) TEX_CHECK_HEIGHT) * BASESIZE - BASESIZE / 2;
+
+      for (x = 0; x < TEX_CHECK_WIDTH; x++) {
+        ppos[0] = (x / (float) TEX_CHECK_WIDTH) * BASESIZE - BASESIZE / 2;
+
+        colorcheckmap(ppos, c);
+        checkmap[y][x][0] = (GLubyte) c[0];
+        checkmap[y][x][1] = (GLubyte) c[1];
+        checkmap[y][x][2] = (GLubyte) c[2];
+      }
+   }
+
+   glTexSubImage2D(GL_TEXTURE_2D, 0, 0, slot * TEX_CHECK_SLOT_SIZE,
+                  TEX_CHECK_WIDTH, TEX_CHECK_SLOT_SIZE, GL_RGB,
+                  GL_UNSIGNED_BYTE,
+                  &checkmap[slot * TEX_CHECK_SLOT_SIZE][0][0]);
+
+}
+
+static void
+updatereflectmap(int slot)
+{
+   float rf, r, g, b, t, dfact, kfact, rdir[3];
+   float rcol[3], ppos[3], norm[3], ldir[3], h[3], vdir[3], planepos[3];
+   int x, y;
+
+   glBindTexture(GL_TEXTURE_2D, reflectid);
+
+   for (y = slot * TEX_REFLECT_SLOT_SIZE;
+       y < (slot + 1) * TEX_REFLECT_SLOT_SIZE; y++)
+      for (x = 0; x < TEX_REFLECT_WIDTH; x++) {
+        ppos[0] = sphere_pos[y][x][0] + objpos[0];
+        ppos[1] = sphere_pos[y][x][1] + objpos[1];
+        ppos[2] = sphere_pos[y][x][2] + objpos[2];
+
+        vsub(norm, ppos, objpos);
+        vnormalize(norm, norm);
+
+        vsub(ldir, lightpos, ppos);
+        vnormalize(ldir, ldir);
+        vsub(vdir, obs, ppos);
+        vnormalize(vdir, vdir);
+
+        rf = 2.0f * dprod(norm, vdir);
+        if (rf > EPSILON) {
+           rdir[0] = rf * norm[0] - vdir[0];
+           rdir[1] = rf * norm[1] - vdir[1];
+           rdir[2] = rf * norm[2] - vdir[2];
+
+           t = -objpos[2] / rdir[2];
+
+           if (t > EPSILON) {
+              planepos[0] = objpos[0] + t * rdir[0];
+              planepos[1] = objpos[1] + t * rdir[1];
+              planepos[2] = 0.0f;
+
+              if (!colorcheckmap(planepos, rcol))
+                 rcol[0] = rcol[1] = rcol[2] = 0.0f;
+           }
+           else
+              rcol[0] = rcol[1] = rcol[2] = 0.0f;
+        }
+        else
+           rcol[0] = rcol[1] = rcol[2] = 0.0f;
+
+        dfact = 0.1f * dprod(ldir, norm);
+
+        if (dfact < 0.0f) {
+           dfact = 0.0f;
+           kfact = 0.0f;
+        }
+        else {
+           h[0] = 0.5f * (vdir[0] + ldir[0]);
+           h[1] = 0.5f * (vdir[1] + ldir[1]);
+           h[2] = 0.5f * (vdir[2] + ldir[2]);
+           kfact = dprod(h, norm);
+           kfact *= kfact;
+           kfact *= kfact;
+           kfact *= kfact;
+           kfact *= kfact;
+           kfact *= 10.0f;
+        }
+
+        r = dfact + kfact;
+        g = dfact + kfact;
+        b = dfact + kfact;
+
+        r *= 255.0f;
+        g *= 255.0f;
+        b *= 255.0f;
+
+        r += rcol[0];
+        g += rcol[1];
+        b += rcol[2];
+
+        r = clamp255(r);
+        g = clamp255(g);
+        b = clamp255(b);
+
+        reflectmap[y][x][0] = (GLubyte) r;
+        reflectmap[y][x][1] = (GLubyte) g;
+        reflectmap[y][x][2] = (GLubyte) b;
+      }
+
+   glTexSubImage2D(GL_TEXTURE_2D, 0, 0, slot * TEX_REFLECT_SLOT_SIZE,
+                  TEX_REFLECT_WIDTH, TEX_REFLECT_SLOT_SIZE, GL_RGB,
+                  GL_UNSIGNED_BYTE,
+                  &reflectmap[slot * TEX_REFLECT_SLOT_SIZE][0][0]);
+}
+
+static void
+drawbase(void)
+{
+   glColor3f(0.0, 0.0, 0.0);
+   glBindTexture(GL_TEXTURE_2D, checkid);
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+   glBegin(GL_QUADS);
+   glTexCoord2f(0.0f, 0.0f);
+   glVertex3f(-BASESIZE / 2.0f, -BASESIZE / 2.0f, 0.0f);
+
+   glTexCoord2f(1.0f, 0.0f);
+   glVertex3f(BASESIZE / 2.0f, -BASESIZE / 2.0f, 0.0f);
+
+   glTexCoord2f(1.0f, 1.0f);
+   glVertex3f(BASESIZE / 2.0f, BASESIZE / 2.0f, 0.0f);
+
+   glTexCoord2f(0.0f, 1.0f);
+   glVertex3f(-BASESIZE / 2.0f, BASESIZE / 2.0f, 0.0f);
+
+   glEnd();
+}
+
+static void
+drawobj(void)
+{
+   glColor3f(0.0, 0.0, 0.0);
+   glBindTexture(GL_TEXTURE_2D, reflectid);
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+   glPushMatrix();
+   glTranslatef(objpos[0], objpos[1], objpos[2]);
+   glCallList(objdlist);
+   glPopMatrix();
+}
+
+static void
+dojoy(void)
+{
+#ifdef WIN32
+   static UINT max[2] = { 0, 0 };
+   static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
+   MMRESULT res;
+   JOYINFO joy;
+
+   res = joyGetPos(JOYSTICKID1, &joy);
+
+   if (res == JOYERR_NOERROR) {
+      joyavailable = 1;
+
+      if (max[0] < joy.wXpos)
+        max[0] = joy.wXpos;
+      if (min[0] > joy.wXpos)
+        min[0] = joy.wXpos;
+      center[0] = (max[0] + min[0]) / 2;
+
+      if (max[1] < joy.wYpos)
+        max[1] = joy.wYpos;
+      if (min[1] > joy.wYpos)
+        min[1] = joy.wYpos;
+      center[1] = (max[1] + min[1]) / 2;
+
+      if (joyactive) {
+        if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
+           alpha -=
+              2.5 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
+        if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
+           beta += 2.5 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
+
+        if (joy.wButtons & JOY_BUTTON1)
+           v += 0.005;
+        if (joy.wButtons & JOY_BUTTON2)
+           v -= 0.005;
+      }
+   }
+   else
+      joyavailable = 0;
+#endif
+}
+
+static void
+updatemaps(void)
+{
+   updatecheckmap(checkmap_currentslot);
+   checkmap_currentslot = (checkmap_currentslot + 1) % TEX_CHECK_NUMSLOT;
+
+   updatereflectmap(reflectmap_currentslot);
+   reflectmap_currentslot =
+      (reflectmap_currentslot + 1) % TEX_REFLECT_NUMSLOT;
+}
+
+static void
+draw(void)
+{
+   static int count = 0;
+   static char frbuf[80];
+   float fr;
+
+   dojoy();
+
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   glEnable(GL_TEXTURE_2D);
+   glEnable(GL_DEPTH_TEST);
+   if (fog)
+      glEnable(GL_FOG);
+   else
+      glDisable(GL_FOG);
+
+   glPushMatrix();
+   calcposobs();
+
+   gluLookAt(obs[0], obs[1], obs[2],
+            obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
+            0.0, 0.0, 1.0);
+
+   drawbase();
+   drawobj();
+
+   glColor3f(1.0, 1.0, 1.0);
+   glDisable(GL_TEXTURE_2D);
+
+   glPushMatrix();
+   glTranslatef(lightpos[0], lightpos[1], lightpos[2]);
+   glCallList(lightdlist);
+   glPopMatrix();
+
+   glPopMatrix();
+
+   if ((count % FRAME) == 0) {
+      fr = gettime();
+      sprintf(frbuf, "Frame rate: %f", FRAME / fr);
+   }
+
+   glDisable(GL_DEPTH_TEST);
+   glDisable(GL_FOG);
+
+   glMatrixMode(GL_PROJECTION);
+   glPushMatrix();
+   glLoadIdentity();
+   glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
+   glMatrixMode(GL_MODELVIEW);
+
+   glColor3f(0.0f, 0.3f, 1.0f);
+
+   if (showcheckmap) {
+      glEnable(GL_TEXTURE_2D);
+      glBindTexture(GL_TEXTURE_2D, checkid);
+      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+      glBegin(GL_QUADS);
+      glTexCoord2f(1.0f, 0.0f);
+      glVertex2i(10, 30);
+      glTexCoord2f(1.0f, 1.0f);
+      glVertex2i(10 + 90, 30);
+      glTexCoord2f(0.0f, 1.0f);
+      glVertex2i(10 + 90, 30 + 90);
+      glTexCoord2f(0.0f, 0.0f);
+      glVertex2i(10, 30 + 90);
+      glEnd();
+
+      glDisable(GL_TEXTURE_2D);
+      glBegin(GL_LINE_LOOP);
+      glVertex2i(10, 30);
+      glVertex2i(10 + 90, 30);
+      glVertex2i(10 + 90, 30 + 90);
+      glVertex2i(10, 30 + 90);
+      glEnd();
+      glRasterPos2i(105, 65);
+      printstring(GLUT_BITMAP_HELVETICA_18, "Plane Texture Map");
+   }
+
+   if (showreflectmap) {
+      glEnable(GL_TEXTURE_2D);
+      glBindTexture(GL_TEXTURE_2D, reflectid);
+      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+      glBegin(GL_QUADS);
+      glTexCoord2f(1.0f, 0.0f);
+      glVertex2i(540, 30);
+      glTexCoord2f(1.0f, 1.0f);
+      glVertex2i(540 + 90, 30);
+      glTexCoord2f(0.0f, 1.0f);
+      glVertex2i(540 + 90, 30 + 90);
+      glTexCoord2f(0.0f, 0.0f);
+      glVertex2i(540, 30 + 90);
+      glEnd();
+
+      glDisable(GL_TEXTURE_2D);
+      glBegin(GL_LINE_LOOP);
+      glVertex2i(540, 30);
+      glVertex2i(540 + 90, 30);
+      glVertex2i(540 + 90, 30 + 90);
+      glVertex2i(540, 30 + 90);
+      glEnd();
+      glRasterPos2i(360, 65);
+      printstring(GLUT_BITMAP_HELVETICA_18, "Sphere Texture Map");
+   }
+
+   glDisable(GL_TEXTURE_2D);
+
+   glRasterPos2i(10, 10);
+   printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
+   glRasterPos2i(360, 470);
+   printstring(GLUT_BITMAP_HELVETICA_10,
+              "Ray V1.0 Written by David Bucciarelli (tech.hmw@plus.it)");
+
+   if (help)
+      printhelp();
+
+   glMatrixMode(GL_PROJECTION);
+   glPopMatrix();
+   glMatrixMode(GL_MODELVIEW);
+
+   updatemaps();
+
+   glutSwapBuffers();
+
+   count++;
+}
+
+static void
+inittextures(void)
+{
+   int y;
+
+   glGenTextures(1, &checkid);
+   glBindTexture(GL_TEXTURE_2D, checkid);
+
+   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+   glTexImage2D(GL_TEXTURE_2D, 0, 3, TEX_CHECK_WIDTH, TEX_CHECK_HEIGHT,
+               0, GL_RGB, GL_UNSIGNED_BYTE, checkmap);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   for (y = 0; y < TEX_CHECK_NUMSLOT; y++)
+      updatecheckmap(y);
+
+
+
+   glGenTextures(1, &reflectid);
+   glBindTexture(GL_TEXTURE_2D, reflectid);
+
+   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+   glTexImage2D(GL_TEXTURE_2D, 0, 3, TEX_REFLECT_WIDTH, TEX_REFLECT_HEIGHT,
+               0, GL_RGB, GL_UNSIGNED_BYTE, reflectmap);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   for (y = 0; y < TEX_REFLECT_NUMSLOT; y++)
+      updatereflectmap(y);
+
+
+}
+
+static void
+initspherepos(void)
+{
+   float alpha, beta, sa, ca, sb, cb;
+   int x, y;
+
+   for (y = 0; y < TEX_REFLECT_HEIGHT; y++) {
+      beta = M_PI - y * (M_PI / TEX_REFLECT_HEIGHT);
+
+      for (x = 0; x < TEX_REFLECT_WIDTH; x++) {
+        alpha = -x * (2.0f * M_PI / TEX_REFLECT_WIDTH);
+
+        sa = sin(alpha);
+        ca = cos(alpha);
+
+        sb = sin(beta);
+        cb = cos(beta);
+
+        sphere_pos[y][x][0] = SPHERE_RADIUS * sa * sb;
+        sphere_pos[y][x][1] = SPHERE_RADIUS * ca * sb;
+        sphere_pos[y][x][2] = SPHERE_RADIUS * cb;
+      }
+   }
+}
+
+static void
+initdlists(void)
+{
+   GLUquadricObj *obj;
+
+   obj = gluNewQuadric();
+
+   lightdlist = glGenLists(1);
+   glNewList(lightdlist, GL_COMPILE);
+   gluQuadricDrawStyle(obj, GLU_FILL);
+   gluQuadricNormals(obj, GLU_NONE);
+   gluQuadricTexture(obj, GL_TRUE);
+   gluSphere(obj, 0.25f, 6, 6);
+   glEndList();
+
+   objdlist = glGenLists(1);
+   glNewList(objdlist, GL_COMPILE);
+   gluQuadricDrawStyle(obj, GLU_FILL);
+   gluQuadricNormals(obj, GLU_NONE);
+   gluQuadricTexture(obj, GL_TRUE);
+   gluSphere(obj, SPHERE_RADIUS, 16, 16);
+   glEndList();
+}
+
+int
+main(int ac, char **av)
+{
+   fprintf(stderr,
+          "Ray V1.0\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
+
+   /*
+      if(!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS)) {
+      fprintf(stderr,"Error setting the process class.\n");
+      return 0;
+      }
+
+      if(!SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL)) {
+      fprintf(stderr,"Error setting the process priority.\n");
+      return 0;
+      }
+    */
+
+   glutInitWindowPosition(0, 0);
+   glutInitWindowSize(WIDTH, HEIGHT);
+   glutInit(&ac, av);
+
+   glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
+
+   if (!(win = glutCreateWindow("Ray"))) {
+      fprintf(stderr, "Error, couldn't open window\n");
+      return -1;
+   }
+
+   reshape(WIDTH, HEIGHT);
+
+   glShadeModel(GL_FLAT);
+   glEnable(GL_DEPTH_TEST);
+   glDepthFunc(GL_LEQUAL);
+   glEnable(GL_CULL_FACE);
+   glEnable(GL_TEXTURE_2D);
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+   glEnable(GL_FOG);
+   glFogi(GL_FOG_MODE, GL_EXP2);
+   glFogfv(GL_FOG_COLOR, fogcolor);
+
+   glFogf(GL_FOG_DENSITY, 0.01);
+#ifdef FX
+   glHint(GL_FOG_HINT, GL_NICEST);
+#endif
+
+   calcposobs();
+
+   initspherepos();
+
+   inittextures();
+   initdlists();
+
+   glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
+
+   glutReshapeFunc(reshape);
+   glutDisplayFunc(draw);
+   glutKeyboardFunc(key);
+   glutSpecialFunc(special);
+   glutIdleFunc(draw);
+
+   glutMainLoop();
+
+   return 0;
+}
diff --git a/progs/demos/shadow.c b/progs/demos/shadow.c
new file mode 100644 (file)
index 0000000..a1b3fde
--- /dev/null
@@ -0,0 +1,117 @@
+/**
+(c) Copyright 1993, Silicon Graphics, Inc.
+
+ALL RIGHTS RESERVED
+
+Permission to use, copy, modify, and distribute this software
+for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that
+both the copyright notice and this permission notice appear in
+supporting documentation, and that the name of Silicon
+Graphics, Inc. not be used in advertising or publicity
+pertaining to distribution of the software without specific,
+written prior permission.
+
+THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU
+"AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR
+OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  IN NO
+EVENT SHALL SILICON GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE
+ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER,
+INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE,
+SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR
+NOT SILICON GRAPHICS, INC.  HAS BEEN ADVISED OF THE POSSIBILITY
+OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+US Government Users Restricted Rights
+
+Use, duplication, or disclosure by the Government is subject to
+restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+(c)(1)(ii) of the Rights in Technical Data and Computer
+Software clause at DFARS 252.227-7013 and/or in similar or
+successor clauses in the FAR or the DOD or NASA FAR
+Supplement.  Unpublished-- rights reserved under the copyright
+laws of the United States.  Contractor/manufacturer is Silicon
+Graphics, Inc., 2011 N.  Shoreline Blvd., Mountain View, CA
+94039-7311.
+
+OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+*/
+
+/* Taken from the projshadow.c - by Tom McReynolds, SGI */
+
+/* Modified by David Bucciarelli */
+
+/* Rendering shadows using projective shadows. */
+
+#include <GL/glut.h>
+
+enum {
+  X, Y, Z, W
+};
+enum {
+  A, B, C, D
+};
+
+/* create a matrix that will project the desired shadow */
+void
+shadowmatrix(GLfloat shadowMat[4][4],
+  GLfloat groundplane[4],
+  GLfloat lightpos[4])
+{
+  GLfloat dot;
+
+  /* find dot product between light position vector and ground plane normal */
+  dot = groundplane[X] * lightpos[X] +
+    groundplane[Y] * lightpos[Y] +
+    groundplane[Z] * lightpos[Z] +
+    groundplane[W] * lightpos[W];
+
+  shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
+  shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
+  shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
+  shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
+
+  shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
+  shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
+  shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
+  shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
+
+  shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
+  shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
+  shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
+  shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
+
+  shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
+  shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
+  shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
+  shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
+
+}
+
+/* find the plane equation given 3 points */
+void
+findplane(GLfloat plane[4],
+  GLfloat v0[3], GLfloat v1[3], GLfloat v2[3])
+{
+  GLfloat vec0[3], vec1[3];
+
+  /* need 2 vectors to find cross product */
+  vec0[X] = v1[X] - v0[X];
+  vec0[Y] = v1[Y] - v0[Y];
+  vec0[Z] = v1[Z] - v0[Z];
+
+  vec1[X] = v2[X] - v0[X];
+  vec1[Y] = v2[Y] - v0[Y];
+  vec1[Z] = v2[Z] - v0[Z];
+
+  /* find cross product to get A, B, and C of plane equation */
+  plane[A] = vec0[Y] * vec1[Z] - vec0[Z] * vec1[Y];
+  plane[B] = -(vec0[X] * vec1[Z] - vec0[Z] * vec1[X]);
+  plane[C] = vec0[X] * vec1[Y] - vec0[Y] * vec1[X];
+
+  plane[D] = -(plane[A] * v0[X] + plane[B] * v0[Y] + plane[C] * v0[Z]);
+}
diff --git a/progs/demos/teapot.c b/progs/demos/teapot.c
new file mode 100644 (file)
index 0000000..addee03
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (tech.hmw@plus.it)
+ *            Humanware s.r.l.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <GL/glut.h>
+#include "../util/readtex.c"
+#include "shadow.c"
+
+#ifdef XMESA
+#include "GL/xmesa.h"
+static int fullscreen=1;
+#endif
+
+static int WIDTH=640;
+static int HEIGHT=480;
+
+#define FRAME 50
+
+#define BASESIZE 10.0
+
+#define BASERES 12
+#define TEAPOTRES 3
+
+#ifndef M_PI
+#define M_PI 3.1415926535
+#endif
+
+extern void shadowmatrix(GLfloat [4][4], GLfloat [4], GLfloat [4]);
+extern void findplane(GLfloat [4], GLfloat [3], GLfloat [3], GLfloat [3]);
+
+
+static int win=0;
+
+static float obs[3]={5.0,0.0,1.0};
+static float dir[3];
+static float v=0.0;
+static float alpha=-90.0;
+static float beta=90.0;
+
+static GLfloat baseshadow[4][4];
+static GLfloat lightpos[4]={2.3,0.0,3.0,1.0};
+static GLfloat lightdir[3]={-2.3,0.0,-3.0};
+static GLfloat lightalpha=0.0;
+
+static int fog=1;
+static int bfcull=1;
+static int usetex=1;
+static int help=1;
+static int joyavailable=0;
+static int joyactive=0;
+
+static GLuint t1id,t2id;
+static GLuint teapotdlist,basedlist,lightdlist;
+
+static float gettime(void)
+{
+  static clock_t told=0;
+  clock_t tnew,ris;
+
+  tnew=clock();
+
+  ris=tnew-told;
+
+  told=tnew;
+
+  return(ris/(float)CLOCKS_PER_SEC);
+}
+
+static void calcposobs(void)
+{
+  dir[0]=sin(alpha*M_PI/180.0);
+  dir[1]=cos(alpha*M_PI/180.0)*sin(beta*M_PI/180.0);
+  dir[2]=cos(beta*M_PI/180.0);
+
+  obs[0]+=v*dir[0];
+  obs[1]+=v*dir[1];
+  obs[2]+=v*dir[2];
+}
+
+static void special(int k, int x, int y)
+{
+  switch(k) {
+  case GLUT_KEY_LEFT:
+    alpha-=2.0;
+    break;
+  case GLUT_KEY_RIGHT:
+    alpha+=2.0;
+    break;
+  case GLUT_KEY_DOWN:
+    beta-=2.0;
+    break;
+  case GLUT_KEY_UP:
+    beta+=2.0;
+    break;
+  }
+}
+
+static void key(unsigned char k, int x, int y)
+{
+  switch(k) {
+  case 27:
+    exit(0);
+    break;
+    
+  case 'a':
+    v+=0.005;
+    break;
+  case 'z':
+    v-=0.005;
+    break;
+
+  case 'j':
+    joyactive=(!joyactive);
+    break;
+  case 'h':
+    help=(!help);
+    break;
+  case 'f':
+    fog=(!fog);
+    break;
+  case 't':
+    usetex=(!usetex);
+    break;
+  case 'b':
+    if(bfcull) {
+      glDisable(GL_CULL_FACE);
+      bfcull=0;
+    } else {
+      glEnable(GL_CULL_FACE);
+      bfcull=1;
+    }
+    break;
+#ifdef XMESA
+  case ' ':
+    XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
+    fullscreen=(!fullscreen);
+    break;
+#endif
+  }
+}
+
+static void reshape(int w, int h) 
+{
+  WIDTH=w;
+  HEIGHT=h;
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  gluPerspective(45.0,w/(float)h,0.2,40.0);
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+  glViewport(0,0,w,h);
+}
+
+static void printstring(void *font, char *string)
+{
+  int len,i;
+
+  len=(int)strlen(string);
+  for(i=0;i<len;i++)
+    glutBitmapCharacter(font,string[i]);
+}
+
+static void printhelp(void)
+{
+  glEnable(GL_BLEND);
+  glColor4f(0.5,0.5,0.5,0.5);
+  glRecti(40,40,600,440);
+  glDisable(GL_BLEND);
+
+  glColor3f(1.0,0.0,0.0);
+  glRasterPos2i(300,420);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"Help");
+
+  glRasterPos2i(60,390);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"h - Togle Help");
+  glRasterPos2i(60,360);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"t - Togle Textures");
+  glRasterPos2i(60,330);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"f - Togle Fog");
+  glRasterPos2i(60,300);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"b - Togle Back face culling");
+  glRasterPos2i(60,270);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"Arrow Keys - Rotate");
+  glRasterPos2i(60,240);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"a - Increase velocity");
+  glRasterPos2i(60,210);
+  printstring(GLUT_BITMAP_TIMES_ROMAN_24,"z - Decrease velocity");
+
+  glRasterPos2i(60,180);
+  if(joyavailable)
+    printstring(GLUT_BITMAP_TIMES_ROMAN_24,"j - Togle jostick control (Joystick control available)");
+  else
+    printstring(GLUT_BITMAP_TIMES_ROMAN_24,"(No Joystick control available)");
+}
+
+static void drawbase(void)
+{
+  int i,j;
+  float x,y,dx,dy;
+
+  glBindTexture(GL_TEXTURE_2D,t1id);
+
+  dx=BASESIZE/BASERES;
+  dy=-BASESIZE/BASERES;
+  for(y=BASESIZE/2.0,j=0;j<BASERES;y+=dy,j++) {
+    glBegin(GL_QUAD_STRIP);
+    glColor3f(1.0,1.0,1.0);
+    glNormal3f(0.0,0.0,1.0);
+    for(x=-BASESIZE/2.0,i=0;i<BASERES;x+=dx,i++) {
+      glTexCoord2f(x,y);
+      glVertex3f(x,y,0.0);
+
+      glTexCoord2f(x,y+dy);
+      glVertex3f(x,y+dy,0.0);
+    }
+    glEnd();
+  }
+}
+
+static void drawteapot(void)
+{
+  static float xrot=0.0;
+  static float zrot=0.0;
+
+  glPushMatrix();
+  glRotatef(lightalpha,0.0,0.0,1.0);
+  glMultMatrixf((GLfloat *)baseshadow);
+  glRotatef(-lightalpha,0.0,0.0,1.0);
+
+  glTranslatef(0.0,0.0,1.0);
+  glRotatef(xrot,1.0,0.0,0.0);
+  glRotatef(zrot,0.0,0.0,1.0);
+
+  glDisable(GL_TEXTURE_2D);
+  glDisable(GL_DEPTH_TEST);
+  glDisable(GL_LIGHTING);
+
+  glColor3f(0.0,0.0,0.0);
+  glCallList(teapotdlist);
+
+  glEnable(GL_DEPTH_TEST);
+  glEnable(GL_LIGHTING);
+  if(usetex)
+    glEnable(GL_TEXTURE_2D);
+
+  glPopMatrix();
+
+  glPushMatrix();
+  glTranslatef(0.0,0.0,1.0);
+  glRotatef(xrot,1.0,0.0,0.0);
+  glRotatef(zrot,0.0,0.0,1.0);
+
+  glCallList(teapotdlist);
+  glPopMatrix();
+
+  xrot+=2.0;
+  zrot+=1.0;
+}
+
+static void drawlight1(void)
+{
+  glPushMatrix();
+  glRotatef(lightalpha,0.0,0.0,1.0);
+  glLightfv(GL_LIGHT0,GL_POSITION,lightpos);
+  glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,lightdir);
+
+  glPopMatrix();
+}
+
+static void drawlight2(void)
+{
+  glPushMatrix();
+  glRotatef(lightalpha,0.0,0.0,1.0);
+  glTranslatef(lightpos[0],lightpos[1],lightpos[2]);
+
+  glDisable(GL_TEXTURE_2D);
+  glCallList(lightdlist);
+  if(usetex)
+    glEnable(GL_TEXTURE_2D);
+  
+  glPopMatrix();
+
+  lightalpha+=1.0;
+}
+
+static void dojoy(void)
+{
+#ifdef WIN32
+  static UINT max[2]={0,0};
+  static UINT min[2]={0xffffffff,0xffffffff},center[2];
+  MMRESULT res;
+  JOYINFO joy;
+
+  res=joyGetPos(JOYSTICKID1,&joy);
+
+  if(res==JOYERR_NOERROR) {
+    joyavailable=1;
+
+    if(max[0]<joy.wXpos)
+      max[0]=joy.wXpos;
+    if(min[0]>joy.wXpos)
+      min[0]=joy.wXpos;
+    center[0]=(max[0]+min[0])/2;
+
+    if(max[1]<joy.wYpos)
+      max[1]=joy.wYpos;
+    if(min[1]>joy.wYpos)
+      min[1]=joy.wYpos;
+    center[1]=(max[1]+min[1])/2;
+
+    if(joyactive) {
+      if(fabs(center[0]-(float)joy.wXpos)>0.1*(max[0]-min[0]))
+       alpha-=2.5*(center[0]-(float)joy.wXpos)/(max[0]-min[0]);
+      if(fabs(center[1]-(float)joy.wYpos)>0.1*(max[1]-min[1]))
+       beta+=2.5*(center[1]-(float)joy.wYpos)/(max[1]-min[1]);
+
+      if(joy.wButtons & JOY_BUTTON1)
+       v+=0.005;
+      if(joy.wButtons & JOY_BUTTON2)
+       v-=0.005;
+    }
+  } else
+    joyavailable=0;
+#endif
+}
+
+static void draw(void)
+{
+  static int count=0;
+  static char frbuf[80];
+  float fr;
+
+  dojoy();
+
+  glEnable(GL_DEPTH_TEST);
+  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+
+  if(usetex)
+    glEnable(GL_TEXTURE_2D);
+  else
+    glDisable(GL_TEXTURE_2D);
+
+  if(fog)
+    glEnable(GL_FOG);
+  else
+    glDisable(GL_FOG);
+
+  glEnable(GL_LIGHTING);
+
+  glShadeModel(GL_SMOOTH);
+
+  glPushMatrix();
+  calcposobs();
+
+  gluLookAt(obs[0],obs[1],obs[2],
+           obs[0]+dir[0],obs[1]+dir[1],obs[2]+dir[2],
+           0.0,0.0,1.0);
+
+  drawlight1();
+  glCallList(basedlist);
+  drawteapot();
+  drawlight2();
+  glPopMatrix();
+  
+  if((count % FRAME)==0) {
+    fr=gettime();
+    sprintf(frbuf,"Frame rate: %f",FRAME/fr);
+  }
+
+  glDisable(GL_LIGHTING);
+  glDisable(GL_TEXTURE_2D);
+  glDisable(GL_DEPTH_TEST);
+  glDisable(GL_FOG);
+  glShadeModel(GL_FLAT);
+
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  glOrtho(-0.5,639.5,-0.5,479.5,-1.0,1.0);
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+
+  glColor3f(1.0,0.0,0.0);
+  glRasterPos2i(10,10);
+  printstring(GLUT_BITMAP_HELVETICA_18,frbuf);
+  glRasterPos2i(350,470);
+  printstring(GLUT_BITMAP_HELVETICA_10,"Teapot V1.2 Written by David Bucciarelli (tech.hmw@plus.it)");
+
+  if(help)
+    printhelp();
+
+  reshape(WIDTH,HEIGHT);
+
+  glutSwapBuffers();
+
+  count++;
+}
+
+static void inittextures(void)
+{
+  GLenum gluerr;
+  
+  glGenTextures(1,&t1id);
+  glBindTexture(GL_TEXTURE_2D,t1id);
+
+  glPixelStorei(GL_UNPACK_ALIGNMENT,4);
+  if (!LoadRGBMipmaps("../images/tile.rgb", GL_RGB)) {
+    fprintf(stderr,"Error reading a texture.\n");
+    exit(-1);
+  }
+
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
+  
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+
+  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
+
+  glGenTextures(1,&t2id);
+  glBindTexture(GL_TEXTURE_2D,t2id);
+
+  if (!LoadRGBMipmaps("../images/bw.rgb", GL_RGB)) {
+    fprintf(stderr,"Error reading a texture.\n");
+    exit(-1);
+  }
+
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
+  
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
+  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+
+  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
+}
+
+static void initlight(void)
+{
+  float lamb[4]={0.2,0.2,0.2,1.0};
+  float lspec[4]={1.0,1.0,1.0,1.0};
+
+  glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,70.0);
+  glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,20.0);
+  glLightfv(GL_LIGHT0,GL_AMBIENT,lamb);
+  glLightfv(GL_LIGHT0,GL_SPECULAR,lspec);
+
+  glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,20.0);
+  glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,lspec);
+
+  glEnable(GL_LIGHT0);
+}
+
+static void initdlists(void)
+{
+  GLUquadricObj *lcone,*lbase;
+  GLfloat plane[4];
+  GLfloat v0[3]={0.0,0.0,0.0};
+  GLfloat v1[3]={1.0,0.0,0.0};
+  GLfloat v2[3]={0.0,1.0,0.0};
+
+  findplane(plane,v0,v1,v2);
+  shadowmatrix(baseshadow,plane,lightpos);
+
+  teapotdlist=glGenLists(1);
+  glNewList(teapotdlist,GL_COMPILE);
+  glRotatef(90.0,1.0,0.0,0.0);
+  glCullFace(GL_FRONT);
+  glBindTexture(GL_TEXTURE_2D,t2id);
+  glutSolidTeapot(0.75);
+  glCullFace(GL_BACK);
+  glEndList();
+
+  basedlist=glGenLists(1);
+  glNewList(basedlist,GL_COMPILE);
+  drawbase();
+  glEndList();
+
+  lightdlist=glGenLists(1);
+  glNewList(lightdlist,GL_COMPILE);
+  glDisable(GL_LIGHTING);
+  lcone=gluNewQuadric();
+  lbase=gluNewQuadric();
+  glRotatef(45.0,0.0,1.0,0.0);
+
+  glColor3f(1.0,1.0,1.0);
+  glCullFace(GL_FRONT);
+  gluDisk(lbase,0.0,0.2,12.0,1.0);
+  glCullFace(GL_BACK);
+
+  glColor3f(0.5,0.0,0.0);
+  gluCylinder(lcone,0.2,0.0,0.5,12,1);
+
+  gluDeleteQuadric(lcone);
+  gluDeleteQuadric(lbase);
+
+  glEnable(GL_LIGHTING);
+  glEndList();
+}
+
+int main(int ac, char **av)
+{
+  float fogcolor[4]={0.025,0.025,0.025,1.0};
+
+  fprintf(stderr,"Teapot V1.2\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
+
+  /*
+    if(!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS)) {
+    fprintf(stderr,"Error setting the process class.\n");
+    return 0;
+    }
+
+    if(!SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL)) {
+    fprintf(stderr,"Error setting the process priority.\n");
+    return 0;
+    }
+    */
+
+  glutInitWindowPosition(0,0);
+  glutInitWindowSize(WIDTH,HEIGHT);
+  glutInit(&ac,av);
+
+  glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE);
+
+  if(!(win=glutCreateWindow("Teapot"))) {
+    fprintf(stderr,"Error, couldn't open window\n");
+       return -1;
+  }
+
+  reshape(WIDTH,HEIGHT);
+
+  glShadeModel(GL_SMOOTH);
+  glEnable(GL_DEPTH_TEST);
+  glEnable(GL_CULL_FACE);
+  glEnable(GL_TEXTURE_2D);
+
+  glEnable(GL_FOG);
+  glFogi(GL_FOG_MODE,GL_EXP2);
+  glFogfv(GL_FOG_COLOR,fogcolor);
+
+  glFogf(GL_FOG_DENSITY,0.04);
+  glHint(GL_FOG_HINT,GL_NICEST);
+  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+  calcposobs();
+
+  inittextures();
+  initlight();
+
+  initdlists();
+
+  glClearColor(fogcolor[0],fogcolor[1],fogcolor[2],fogcolor[3]);
+
+  glutReshapeFunc(reshape);
+  glutDisplayFunc(draw);
+  glutKeyboardFunc(key);
+  glutSpecialFunc(special);
+  glutIdleFunc(draw);
+
+  glutMainLoop();
+
+  return 0;
+}
diff --git a/progs/demos/terrain.c b/progs/demos/terrain.c
new file mode 100644 (file)
index 0000000..b708ff8
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (tech.hmw@plus.it)
+ *            Humanware s.r.l.
+ *
+ * based on a Mikael SkiZoWalker's (MoDEL) / France (Skizo@Hol.Fr) demo
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <GL/glut.h>
+
+#ifdef XMESA
+#include "GL/xmesa.h"
+static int fullscreen = 1;
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+#define heightMnt      450
+#define        lenghtXmnt      62
+#define lenghtYmnt     62
+
+#define stepXmnt     96.0
+#define stepYmnt     96.0
+
+#define WIDTH 640
+#define HEIGHT 480
+
+#define TSCALE 4
+
+#define        FRAME 50
+
+#define FOV 85
+
+static GLfloat terrain[256 * 256];
+static GLfloat terraincolor[256 * 256][3];
+
+static int win = 0;
+
+static int fog = 1;
+static int bfcull = 1;
+static int usetex = 1;
+static int poutline = 0;
+static int help = 1;
+static int joyavailable = 0;
+static int joyactive = 0;
+static float ModZMnt;
+static long GlobalMnt = 0;
+
+static int scrwidth = WIDTH;
+static int scrheight = HEIGHT;
+
+#define OBSSTARTX 992.0
+#define OBSSTARTY 103.0
+
+static float obs[3] = { OBSSTARTX, heightMnt * 1.3, OBSSTARTY };
+static float dir[3], v1[2], v2[2];
+static float v = 15.0;
+static float alpha = 75.0;
+static float beta = 90.0;
+
+static float
+gettime(void)
+{
+   static clock_t told = 0;
+   clock_t tnew, ris;
+
+   tnew = clock();
+
+   ris = tnew - told;
+
+   told = tnew;
+
+   return (ris / (float) CLOCKS_PER_SEC);
+}
+
+static void
+calcposobs(void)
+{
+   float alpha1, alpha2;
+
+   dir[0] = sin(alpha * M_PI / 180.0);
+   dir[2] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
+   dir[1] = cos(beta * M_PI / 180.0);
+
+   alpha1 = alpha + FOV / 2.0;
+   v1[0] = sin(alpha1 * M_PI / 180.0);
+   v1[1] = cos(alpha1 * M_PI / 180.0);
+
+   alpha2 = alpha - FOV / 2.0;
+   v2[0] = sin(alpha2 * M_PI / 180.0);
+   v2[1] = cos(alpha2 * M_PI / 180.0);
+
+   obs[0] += v * dir[0];
+   obs[1] += v * dir[1];
+   obs[2] += v * dir[2];
+
+   if (obs[1] < 0.0)
+      obs[1] = 0.0;
+}
+
+static void
+reshape(int width, int height)
+{
+   scrwidth = width;
+   scrheight = height;
+   glViewport(0, 0, (GLint) width, (GLint) height);
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   gluPerspective(50.0, ((GLfloat) width / (GLfloat) height),
+                 lenghtXmnt * stepYmnt * 0.01, lenghtXmnt * stepYmnt * 0.7);
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+}
+
+int
+clipstrip(float y, float *start, float *end)
+{
+   float x1, x2, t1, t2, tmp;
+
+   if (v1[1] == 0.0) {
+      t1 = 0.0;
+      x1 = -HUGE_VAL;
+   }
+   else {
+      t1 = y / v1[1];
+      x1 = t1 * v1[0];
+   }
+
+   if (v2[1] == 0.0) {
+      t2 = 0.0;
+      x2 = HUGE_VAL;
+   }
+   else {
+      t2 = y / v2[1];
+      x2 = t2 * v2[0];
+   }
+
+   if (((x1 < -(lenghtXmnt * stepXmnt) / 2) && (t2 <= 0.0)) ||
+       ((t1 <= 0.0) && (x2 > (lenghtXmnt * stepXmnt) / 2)) ||
+       ((t1 < 0.0) && (t2 < 0.0)))
+      return 0;
+
+   if ((t1 == 0.0) && (t2 == 0.0)) {
+      if ((v1[0] < 0.0) && (v1[1] > 0.0) && (v2[0] < 0.0) && (v2[1] < 0.0)) {
+        *start = -(lenghtXmnt * stepXmnt) / 2;
+        *end = stepXmnt;
+        return 1;
+      }
+      else {
+        if ((v1[0] > 0.0) && (v1[1] < 0.0) && (v2[0] > 0.0) && (v2[1] > 0.0)) {
+           *start = -stepXmnt;
+           *end = (lenghtXmnt * stepXmnt) / 2;
+           return 1;
+        }
+        else
+           return 0;
+      }
+   }
+   else {
+      if (t2 < 0.0) {
+        if (x1 < 0.0)
+           x2 = -(lenghtXmnt * stepXmnt) / 2;
+        else
+           x2 = (lenghtXmnt * stepXmnt) / 2;
+      }
+
+      if (t1 < 0.0) {
+        if (x2 < 0.0)
+           x1 = -(lenghtXmnt * stepXmnt) / 2;
+        else
+           x1 = (lenghtXmnt * stepXmnt) / 2;
+      }
+   }
+
+   if (x1 > x2) {
+      tmp = x1;
+      x1 = x2;
+      x2 = tmp;
+   }
+
+   x1 -= stepXmnt;
+   if (x1 < -(lenghtXmnt * stepXmnt) / 2)
+      x1 = -(lenghtXmnt * stepXmnt) / 2;
+
+   x2 += stepXmnt;
+   if (x2 > (lenghtXmnt * stepXmnt) / 2)
+      x2 = (lenghtXmnt * stepXmnt) / 2;
+
+   *start = ((int) (x1 / stepXmnt)) * stepXmnt;
+   *end = ((int) (x2 / stepXmnt)) * stepXmnt;
+
+   return 1;
+}
+
+static void
+printstring(void *font, char *string)
+{
+   int len, i;
+
+   len = (int) strlen(string);
+   for (i = 0; i < len; i++)
+      glutBitmapCharacter(font, string[i]);
+}
+
+static void
+printhelp(void)
+{
+   glEnable(GL_BLEND);
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+   glColor4f(0.0, 0.0, 0.0, 0.5);
+   glRecti(40, 40, 600, 440);
+   glDisable(GL_BLEND);
+
+   glColor3f(1.0, 0.0, 0.0);
+   glRasterPos2i(300, 420);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help");
+
+   glRasterPos2i(60, 390);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Togle Help");
+   glRasterPos2i(60, 360);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Togle Textures");
+   glRasterPos2i(60, 330);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Togle Fog");
+   glRasterPos2i(60, 300);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "p - Wire frame");
+   glRasterPos2i(60, 270);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "b - Togle Back face culling");
+   glRasterPos2i(60, 240);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate");
+   glRasterPos2i(60, 210);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity");
+   glRasterPos2i(60, 180);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity");
+
+   glRasterPos2i(60, 150);
+   if (joyavailable)
+      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+                 "j - Togle jostick control (Joystick control available)");
+   else
+      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+                 "(No Joystick control available)");
+}
+
+void
+drawterrain(void)
+{
+   int h, i, idx, ox, oy;
+   float j, k, start, end;
+
+   ox = (int) (obs[0] / stepXmnt);
+   oy = (int) (obs[2] / stepYmnt);
+   GlobalMnt = ((ox * TSCALE) & 255) + ((oy * TSCALE) & 255) * 256;
+
+   glPushMatrix();
+   glTranslatef((float) ox * stepXmnt, 0, (float) oy * stepYmnt);
+
+   for (h = 0, k = -(lenghtYmnt * stepYmnt) / 2; h < lenghtYmnt;
+       k += stepYmnt, h++) {
+      if (!clipstrip(k, &start, &end))
+        continue;
+
+      glBegin(GL_TRIANGLE_STRIP);      /* I hope that the optimizer will be able to improve this code */
+      for (i = (int) (lenghtXmnt / 2 + start / stepXmnt), j = start; j <= end;
+          j += stepXmnt, i++) {
+        idx = (i * TSCALE + h * 256 * TSCALE + GlobalMnt) & 65535;
+        glColor3fv(terraincolor[idx]);
+        glTexCoord2f((ox + i) / 8.0, (oy + h) / 8.0);
+        glVertex3f(j, terrain[idx], k);
+
+        idx =
+           (i * TSCALE + h * 256 * TSCALE + 256 * TSCALE +
+            GlobalMnt) & 65535;
+        glColor3fv(terraincolor[idx]);
+        glTexCoord2f((ox + i) / 8.0, (oy + h + 1) / 8.0);
+        glVertex3f(j, terrain[idx], k + stepYmnt);
+      }
+      glEnd();
+   }
+
+   glDisable(GL_CULL_FACE);
+   glDisable(GL_TEXTURE_2D);
+   glEnable(GL_BLEND);
+   glBegin(GL_QUADS);
+   glColor4f(0.1, 0.7, 1.0, 0.4);
+   glVertex3f(-(lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
+             -(lenghtYmnt * stepYmnt) / 2.0);
+   glVertex3f(-(lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
+             (lenghtYmnt * stepYmnt) / 2.0);
+   glVertex3f((lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
+             (lenghtYmnt * stepYmnt) / 2.0);
+   glVertex3f((lenghtXmnt * stepXmnt) / 2.0, heightMnt * 0.6,
+             -(lenghtYmnt * stepYmnt) / 2.0);
+   glEnd();
+   glDisable(GL_BLEND);
+   if (bfcull)
+      glEnable(GL_CULL_FACE);
+   glEnable(GL_TEXTURE_2D);
+
+   glPopMatrix();
+
+}
+
+static void
+dojoy(void)
+{
+#ifdef WIN32
+   static UINT max[2] = { 0, 0 };
+   static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
+   MMRESULT res;
+   JOYINFO joy;
+
+   res = joyGetPos(JOYSTICKID1, &joy);
+
+   if (res == JOYERR_NOERROR) {
+      joyavailable = 1;
+
+      if (max[0] < joy.wXpos)
+        max[0] = joy.wXpos;
+      if (min[0] > joy.wXpos)
+        min[0] = joy.wXpos;
+      center[0] = (max[0] + min[0]) / 2;
+
+      if (max[1] < joy.wYpos)
+        max[1] = joy.wYpos;
+      if (min[1] > joy.wYpos)
+        min[1] = joy.wYpos;
+      center[1] = (max[1] + min[1]) / 2;
+
+      if (joyactive) {
+        if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
+           alpha +=
+              2.5 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
+        if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
+           beta += 2.5 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
+
+        if (joy.wButtons & JOY_BUTTON1)
+           v += 0.5;
+        if (joy.wButtons & JOY_BUTTON2)
+           v -= 0.5;
+      }
+   }
+   else
+      joyavailable = 0;
+#endif
+}
+
+void
+drawscene(void)
+{
+   static int count = 0;
+   static char frbuf[80];
+   float fr;
+
+   dojoy();
+
+   glShadeModel(GL_SMOOTH);
+   glEnable(GL_DEPTH_TEST);
+
+   if (usetex)
+      glEnable(GL_TEXTURE_2D);
+   else
+      glDisable(GL_TEXTURE_2D);
+
+   if (fog)
+      glEnable(GL_FOG);
+   else
+      glDisable(GL_FOG);
+
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   glPushMatrix();
+
+   calcposobs();
+   gluLookAt(obs[0], obs[1], obs[2],
+            obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
+            0.0, 1.0, 0.0);
+
+   drawterrain();
+   glPopMatrix();
+
+   if ((count % FRAME) == 0) {
+      fr = gettime();
+      sprintf(frbuf, "Frame rate: %.3f", FRAME / fr);
+   }
+
+   glDisable(GL_TEXTURE_2D);
+   glDisable(GL_DEPTH_TEST);
+   glDisable(GL_FOG);
+   glShadeModel(GL_FLAT);
+
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+
+   glColor3f(1.0, 0.0, 0.0);
+   glRasterPos2i(10, 10);
+   printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
+   glRasterPos2i(350, 470);
+   printstring(GLUT_BITMAP_HELVETICA_10,
+              "Terrain V1.2 Written by David Bucciarelli (tech.hmw@plus.it)");
+   glRasterPos2i(434, 457);
+   printstring(GLUT_BITMAP_HELVETICA_10,
+              "Based on a Mickael's demo (Skizo@Hol.Fr)");
+
+   if (help)
+      printhelp();
+
+   reshape(scrwidth, scrheight);
+
+   glutSwapBuffers();
+
+   count++;
+}
+
+static void
+key(unsigned char k, int x, int y)
+{
+   switch (k) {
+   case 27:
+      exit(0);
+      break;
+   case 'a':
+      v += 0.5;
+      break;
+   case 'z':
+      v -= 0.5;
+      break;
+   case 'p':
+      if (poutline) {
+        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+        poutline = 0;
+      }
+      else {
+        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+        poutline = 1;
+      }
+      break;
+   case 'j':
+      joyactive = (!joyactive);
+      break;
+   case 'h':
+      help = (!help);
+      break;
+   case 'f':
+      fog = (!fog);
+      break;
+   case 't':
+      usetex = (!usetex);
+      break;
+   case 'b':
+      if (bfcull) {
+        glDisable(GL_CULL_FACE);
+        bfcull = 0;
+      }
+      else {
+        glEnable(GL_CULL_FACE);
+        bfcull = 1;
+      }
+      break;
+#ifdef XMESA
+   case ' ':
+      XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
+      fullscreen = (!fullscreen);
+      break;
+#endif
+   }
+}
+
+static void
+special(int k, int x, int y)
+{
+   switch (k) {
+   case GLUT_KEY_LEFT:
+      alpha += 2.0;
+      break;
+   case GLUT_KEY_RIGHT:
+      alpha -= 2.0;
+      break;
+   case GLUT_KEY_DOWN:
+      beta -= 2.0;
+      break;
+   case GLUT_KEY_UP:
+      beta += 2.0;
+      break;
+   }
+}
+
+static void
+calccolor(GLfloat height, GLfloat c[3])
+{
+   GLfloat color[4][3] = {
+      {1.0, 1.0, 1.0},
+      {0.0, 0.8, 0.0},
+      {1.0, 1.0, 0.3},
+      {0.0, 0.0, 0.8}
+   };
+   GLfloat fact;
+
+   height = height * (1.0 / 255.0);
+
+   if (height >= 0.9) {
+      c[0] = color[0][0];
+      c[1] = color[0][1];
+      c[2] = color[0][2];
+      return;
+   }
+
+   if ((height < 0.9) && (height >= 0.7)) {
+      fact = (height - 0.7) * 5.0;
+      c[0] = fact * color[0][0] + (1.0 - fact) * color[1][0];
+      c[1] = fact * color[0][1] + (1.0 - fact) * color[1][1];
+      c[2] = fact * color[0][2] + (1.0 - fact) * color[1][2];
+      return;
+   }
+
+   if ((height < 0.7) && (height >= 0.6)) {
+      fact = (height - 0.6) * 10.0;
+      c[0] = fact * color[1][0] + (1.0 - fact) * color[2][0];
+      c[1] = fact * color[1][1] + (1.0 - fact) * color[2][1];
+      c[2] = fact * color[1][2] + (1.0 - fact) * color[2][2];
+      return;
+   }
+
+   if ((height < 0.6) && (height >= 0.5)) {
+      fact = (height - 0.5) * 10.0;
+      c[0] = fact * color[2][0] + (1.0 - fact) * color[3][0];
+      c[1] = fact * color[2][1] + (1.0 - fact) * color[3][1];
+      c[2] = fact * color[2][2] + (1.0 - fact) * color[3][2];
+      return;
+   }
+
+   c[0] = color[3][0];
+   c[1] = color[3][1];
+   c[2] = color[3][2];
+}
+
+static void
+loadpic(void)
+{
+   GLubyte bufferter[256 * 256], terrainpic[256 * 256];
+   FILE *FilePic;
+   int i, tmp;
+   GLenum gluerr;
+
+   if ((FilePic = fopen("terrain.dat", "r")) == NULL) {
+      fprintf(stderr, "Error loading Mnt.bin\n");
+      exit(-1);
+   }
+   fread(bufferter, 256 * 256, 1, FilePic);
+   fclose(FilePic);
+
+   for (i = 0; i < (256 * 256); i++) {
+      terrain[i] = (bufferter[i] * (heightMnt / 255.0f));
+      calccolor((GLfloat) bufferter[i], terraincolor[i]);
+      tmp = (((int) bufferter[i]) + 96);
+      terrainpic[i] = (tmp > 255) ? 255 : tmp;
+   }
+
+   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+   if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 1, 256, 256, GL_LUMINANCE,
+                                  GL_UNSIGNED_BYTE,
+                                  (GLvoid *) (&terrainpic[0])))) {
+      fprintf(stderr, "GLULib%s\n", gluErrorString(gluerr));
+      exit(-1);
+   }
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_LINEAR);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+   glEnable(GL_TEXTURE_2D);
+}
+
+static void
+init(void)
+{
+   float fogcolor[4] = { 0.6, 0.7, 0.7, 1.0 };
+
+   glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
+   glClearDepth(1.0);
+   glDepthFunc(GL_LEQUAL);
+   glShadeModel(GL_SMOOTH);
+   glEnable(GL_DEPTH_TEST);
+   glEnable(GL_CULL_FACE);
+
+   glDisable(GL_BLEND);
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+   glEnable(GL_FOG);
+   glFogi(GL_FOG_MODE, GL_EXP2);
+   glFogfv(GL_FOG_COLOR, fogcolor);
+   glFogf(GL_FOG_DENSITY, 0.0007);
+#ifdef FX
+   glHint(GL_FOG_HINT, GL_NICEST);
+#endif
+
+   reshape(scrwidth, scrheight);
+}
+
+
+int
+main(int ac, char **av)
+{
+   glutInitWindowPosition(0, 0);
+   glutInitWindowSize(WIDTH, HEIGHT);
+   glutInit(&ac, av);
+
+   glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
+
+   if (!(win = glutCreateWindow("Terrain"))) {
+      fprintf(stderr, "Error, couldn't open window\n");
+      return -1;
+   }
+
+   ModZMnt = 0.0f;
+   loadpic();
+
+   init();
+
+#ifndef FX
+   glDisable(GL_TEXTURE_2D);
+   usetex = 0;
+#endif
+
+   glutReshapeFunc(reshape);
+   glutDisplayFunc(drawscene);
+   glutKeyboardFunc(key);
+   glutSpecialFunc(special);
+   glutIdleFunc(drawscene);
+
+   glutMainLoop();
+
+   return 0;
+}
diff --git a/progs/demos/tunnel.c b/progs/demos/tunnel.c
new file mode 100644 (file)
index 0000000..3cced8b
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * written by David Bucciarelli (tech.hmw@plus.it)
+ *            Humanware s.r.l.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <GL/glut.h>
+#include "../util/readtex.c"
+#include "tunneldat.c"
+
+#ifdef XMESA
+#include "GL/xmesa.h"
+static int fullscreen = 1;
+#endif
+
+static int WIDTH = 640;
+static int HEIGHT = 480;
+
+#define FRAME 50
+
+#define NUMBLOC 5
+
+#ifndef M_PI
+#define M_PI 3.1415926535
+#endif
+
+extern int striplength_skin_13[];
+extern float stripdata_skin_13[];
+
+extern int striplength_skin_12[];
+extern float stripdata_skin_12[];
+
+extern int striplength_skin_11[];
+extern float stripdata_skin_11[];
+
+extern int striplength_skin_9[];
+extern float stripdata_skin_9[];
+
+
+static int win = 0;
+
+static float obs[3] = { 1000.0, 0.0, 2.0 };
+static float dir[3];
+static float v = 0.5;
+static float alpha = 90.0;
+static float beta = 90.0;
+
+static int fog = 0;
+static int bfcull = 1;
+static int usetex = 1;
+static int cstrip = 0;
+static int help = 1;
+static int joyavailable = 0;
+static int joyactive = 0;
+
+static GLuint t1id, t2id;
+
+static void
+inittextures(void)
+{
+   GLenum gluerr;
+
+   glGenTextures(1, &t1id);
+   glBindTexture(GL_TEXTURE_2D, t1id);
+
+   if (!LoadRGBMipmaps("../images/tile.rgb", GL_RGB)) {
+      fprintf(stderr, "Error reading a texture.\n");
+      exit(-1);
+   }
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_LINEAR);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glGenTextures(1, &t2id);
+   glBindTexture(GL_TEXTURE_2D, t2id);
+
+   if (!LoadRGBMipmaps("../images/bw.rgb", GL_RGB)) {
+      fprintf(stderr, "Error reading a texture.\n");
+      exit(-1);
+   }
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_LINEAR);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+static void
+drawobjs(int *l, float *f)
+{
+   int mend, j;
+
+   if (cstrip) {
+      float r = 0.33, g = 0.33, b = 0.33;
+
+      for (; (*l) != 0;) {
+        mend = *l++;
+
+        r += 0.33;
+        if (r > 1.0) {
+           r = 0.33;
+           g += 0.33;
+           if (g > 1.0) {
+              g = 0.33;
+              b += 0.33;
+              if (b > 1.0)
+                 b = 0.33;
+           }
+        }
+
+        glColor3f(r, g, b);
+        glBegin(GL_TRIANGLE_STRIP);
+        for (j = 0; j < mend; j++) {
+           f += 4;
+           glTexCoord2fv(f);
+           f += 2;
+           glVertex3fv(f);
+           f += 3;
+        }
+        glEnd();
+      }
+   }
+   else
+      for (; (*l) != 0;) {
+        mend = *l++;
+
+        glBegin(GL_TRIANGLE_STRIP);
+        for (j = 0; j < mend; j++) {
+           glColor4fv(f);
+           f += 4;
+           glTexCoord2fv(f);
+           f += 2;
+           glVertex3fv(f);
+           f += 3;
+        }
+        glEnd();
+      }
+}
+
+static float
+gettime(void)
+{
+   static clock_t told = 0;
+   clock_t tnew, ris;
+
+   tnew = clock();
+
+   ris = tnew - told;
+
+   told = tnew;
+
+   return (ris / (float) CLOCKS_PER_SEC);
+}
+
+static void
+calcposobs(void)
+{
+   dir[0] = sin(alpha * M_PI / 180.0);
+   dir[1] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
+   dir[2] = cos(beta * M_PI / 180.0);
+
+   obs[0] += v * dir[0];
+   obs[1] += v * dir[1];
+   obs[2] += v * dir[2];
+}
+
+static void
+special(int k, int x, int y)
+{
+   switch (k) {
+   case GLUT_KEY_LEFT:
+      alpha -= 2.0;
+      break;
+   case GLUT_KEY_RIGHT:
+      alpha += 2.0;
+      break;
+   case GLUT_KEY_DOWN:
+      beta -= 2.0;
+      break;
+   case GLUT_KEY_UP:
+      beta += 2.0;
+      break;
+   }
+}
+
+static void
+key(unsigned char k, int x, int y)
+{
+   switch (k) {
+   case 27:
+      exit(0);
+      break;
+
+   case 'a':
+      v += 0.01;
+      break;
+   case 'z':
+      v -= 0.01;
+      break;
+
+#ifdef XMESA
+   case ' ':
+      fullscreen = (!fullscreen);
+      XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
+      break;
+#endif
+
+   case 'j':
+      joyactive = (!joyactive);
+      break;
+   case 'h':
+      help = (!help);
+      break;
+   case 'f':
+      fog = (!fog);
+      break;
+   case 't':
+      usetex = (!usetex);
+      break;
+   case 'b':
+      if (bfcull) {
+        glDisable(GL_CULL_FACE);
+        bfcull = 0;
+      }
+      else {
+        glEnable(GL_CULL_FACE);
+        bfcull = 1;
+      }
+      break;
+   case 'm':
+      cstrip = (!cstrip);
+      break;
+
+   case 'd':
+      fprintf(stderr, "Deleting textures...\n");
+      glDeleteTextures(1, &t1id);
+      glDeleteTextures(1, &t2id);
+      fprintf(stderr, "Loading textures...\n");
+      inittextures();
+      fprintf(stderr, "Done.\n");
+      break;
+   }
+}
+
+static void
+reshape(int w, int h)
+{
+   WIDTH = w;
+   HEIGHT = h;
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   gluPerspective(80.0, w / (float) h, 1.0, 50.0);
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glViewport(0, 0, w, h);
+}
+
+static void
+printstring(void *font, char *string)
+{
+   int len, i;
+
+   len = (int) strlen(string);
+   for (i = 0; i < len; i++)
+      glutBitmapCharacter(font, string[i]);
+}
+
+static void
+printhelp(void)
+{
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+   glColor4f(0.0, 0.0, 0.0, 0.5);
+   glRecti(40, 40, 600, 440);
+
+   glColor3f(1.0, 0.0, 0.0);
+   glRasterPos2i(300, 420);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help");
+
+   glRasterPos2i(60, 390);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Togle Help");
+   glRasterPos2i(60, 360);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Togle Textures");
+   glRasterPos2i(60, 330);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Togle Fog");
+   glRasterPos2i(60, 300);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "m - Togle strips");
+   glRasterPos2i(60, 270);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "b - Togle Back face culling");
+   glRasterPos2i(60, 240);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate");
+   glRasterPos2i(60, 210);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity");
+   glRasterPos2i(60, 180);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity");
+
+   glRasterPos2i(60, 150);
+   if (joyavailable)
+      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+                 "j - Togle jostick control (Joystick control available)");
+   else
+      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+                 "(No Joystick control available)");
+}
+
+static void
+dojoy(void)
+{
+#ifdef WIN32
+   static UINT max[2] = { 0, 0 };
+   static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
+   MMRESULT res;
+   JOYINFO joy;
+
+   res = joyGetPos(JOYSTICKID1, &joy);
+
+   if (res == JOYERR_NOERROR) {
+      joyavailable = 1;
+
+      if (max[0] < joy.wXpos)
+        max[0] = joy.wXpos;
+      if (min[0] > joy.wXpos)
+        min[0] = joy.wXpos;
+      center[0] = (max[0] + min[0]) / 2;
+
+      if (max[1] < joy.wYpos)
+        max[1] = joy.wYpos;
+      if (min[1] > joy.wYpos)
+        min[1] = joy.wYpos;
+      center[1] = (max[1] + min[1]) / 2;
+
+      if (joyactive) {
+        if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
+           alpha -=
+              2.0 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
+        if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
+           beta += 2.0 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
+
+        if (joy.wButtons & JOY_BUTTON1)
+           v += 0.01;
+        if (joy.wButtons & JOY_BUTTON2)
+           v -= 0.01;
+      }
+   }
+   else
+      joyavailable = 0;
+#endif
+}
+
+static void
+draw(void)
+{
+   static int count = 0;
+   static char frbuf[80];
+   int i;
+   float fr, base, offset;
+
+   dojoy();
+
+   glClear(GL_COLOR_BUFFER_BIT);
+
+   if (usetex)
+      glEnable(GL_TEXTURE_2D);
+   else
+      glDisable(GL_TEXTURE_2D);
+
+   if (fog)
+      glEnable(GL_FOG);
+   else
+      glDisable(GL_FOG);
+
+   glShadeModel(GL_SMOOTH);
+
+   glPushMatrix();
+   calcposobs();
+   gluLookAt(obs[0], obs[1], obs[2],
+            obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
+            0.0, 0.0, 1.0);
+
+   if (dir[0] > 0) {
+      offset = 8.0;
+      base = obs[0] - fmod(obs[0], 8.0);
+   }
+   else {
+      offset = -8.0;
+      base = obs[0] + (8.0 - fmod(obs[0], 8.0));
+   }
+
+   glPushMatrix();
+   glTranslatef(base - offset / 2.0, 0.0, 0.0);
+   for (i = 0; i < NUMBLOC; i++) {
+      glTranslatef(offset, 0.0, 0.0);
+      glBindTexture(GL_TEXTURE_2D, t1id);
+      drawobjs(striplength_skin_11, stripdata_skin_11);
+      glBindTexture(GL_TEXTURE_2D, t2id);
+      drawobjs(striplength_skin_12, stripdata_skin_12);
+      drawobjs(striplength_skin_9, stripdata_skin_9);
+      drawobjs(striplength_skin_13, stripdata_skin_13);
+   }
+   glPopMatrix();
+   glPopMatrix();
+
+   if ((count % FRAME) == 0) {
+      fr = gettime();
+      sprintf(frbuf, "Frame rate: %f", FRAME / fr);
+   }
+
+   glDisable(GL_TEXTURE_2D);
+   glDisable(GL_FOG);
+   glShadeModel(GL_FLAT);
+
+   glMatrixMode(GL_PROJECTION);
+   glPushMatrix();
+   glLoadIdentity();
+   glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
+
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+
+   glColor3f(1.0, 0.0, 0.0);
+   glRasterPos2i(10, 10);
+   printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
+   glRasterPos2i(350, 470);
+   printstring(GLUT_BITMAP_HELVETICA_10,
+              "Tunnel V1.5 Written by David Bucciarelli (tech.hmw@plus.it)");
+
+   if (help)
+      printhelp();
+
+   glMatrixMode(GL_PROJECTION);
+   glPopMatrix();
+   glMatrixMode(GL_MODELVIEW);
+
+   glutSwapBuffers();
+
+   count++;
+}
+
+int
+main(int ac, char **av)
+{
+   float fogcolor[4] = { 0.7, 0.7, 0.7, 1.0 };
+
+   fprintf(stderr,
+          "Tunnel V1.5\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
+
+   glutInitWindowPosition(0, 0);
+   glutInitWindowSize(WIDTH, HEIGHT);
+   glutInit(&ac, av);
+
+   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+
+   if (!(win = glutCreateWindow("Tunnel"))) {
+      fprintf(stderr, "Error, couldn't open window\n");
+      return -1;
+   }
+
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   gluPerspective(80.0, WIDTH / (float) HEIGHT, 1.0, 50.0);
+
+   glMatrixMode(GL_MODELVIEW);
+
+   glShadeModel(GL_SMOOTH);
+   glDisable(GL_DEPTH_TEST);
+   glEnable(GL_CULL_FACE);
+   glEnable(GL_TEXTURE_2D);
+
+   glEnable(GL_FOG);
+   glFogi(GL_FOG_MODE, GL_EXP2);
+   glFogfv(GL_FOG_COLOR, fogcolor);
+
+   glFogf(GL_FOG_DENSITY, 0.06);
+   glHint(GL_FOG_HINT, GL_NICEST);
+
+   inittextures();
+
+   glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
+   glClear(GL_COLOR_BUFFER_BIT);
+
+   calcposobs();
+
+   glutReshapeFunc(reshape);
+   glutDisplayFunc(draw);
+   glutKeyboardFunc(key);
+   glutSpecialFunc(special);
+   glutIdleFunc(draw);
+
+   glEnable(GL_BLEND);
+   /*glBlendFunc(GL_SRC_ALPHA_SATURATE,GL_ONE); */
+   /*glEnable(GL_POLYGON_SMOOTH); */
+
+   glutMainLoop();
+
+   return 0;
+}
diff --git a/progs/demos/tunnel2.c b/progs/demos/tunnel2.c
new file mode 100644 (file)
index 0000000..b8cea41
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * This program is under the GNU GPL.
+ * Use at your own risk.
+ *
+ * You need TWO Voodoo Graphics boards in order to run
+ * this demo !
+ *
+ * written by David Bucciarelli (tech.hmw@plus.it)
+ *            Humanware s.r.l.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <GL/glut.h>
+#include "../util/readtex.c"
+#include "tunneldat.c"
+
+#ifdef FX
+#endif
+
+#ifdef XMESA
+#include "GL/xmesa.h"
+static int fullscreen = 1;
+#endif
+
+#ifdef FX
+GLboolean fxMesaSelectCurrentBoard(int);
+#endif
+
+static int WIDTHC0 = 640;
+static int HEIGHTC0 = 480;
+
+static int WIDTHC1 = 640;
+static int HEIGHTC1 = 480;
+
+#define FRAME 50
+
+#define NUMBLOC 5
+
+#ifndef M_PI
+#define M_PI 3.1415926535
+#endif
+
+extern int striplength_skin_13[];
+extern float stripdata_skin_13[];
+
+extern int striplength_skin_12[];
+extern float stripdata_skin_12[];
+
+extern int striplength_skin_11[];
+extern float stripdata_skin_11[];
+
+extern int striplength_skin_9[];
+extern float stripdata_skin_9[];
+
+
+static float obs[3] = { 1000.0, 0.0, 2.0 };
+static float dir[3];
+static float v = 0.5;
+static float alpha = 90.0;
+static float beta = 90.0;
+
+static int fog = 0;
+static int bfcull = 1;
+static int usetex = 1;
+static int cstrip = 0;
+static int help = 1;
+static int joyavailable = 0;
+static int joyactive = 0;
+
+static int channel[2];
+
+static GLuint t1id, t2id;
+
+static void
+inittextures(void)
+{
+   GLenum gluerr;
+
+   glGenTextures(1, &t1id);
+   glBindTexture(GL_TEXTURE_2D, t1id);
+
+   if (!LoadRGBMipmaps("../images/tile.rgb", GL_RGB)) {
+      fprintf(stderr, "Error reading a texture.\n");
+      exit(-1);
+   }
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glGenTextures(1, &t2id);
+   glBindTexture(GL_TEXTURE_2D, t2id);
+
+   if (!LoadRGBMipmaps("../images/bw.rgb", GL_RGB)) {
+      fprintf(stderr, "Error reading a texture.\n");
+      exit(-1);
+   }
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+                  GL_LINEAR_MIPMAP_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+static void
+drawobjs(int *l, float *f)
+{
+   int mend, j;
+
+   if (cstrip) {
+      float r = 0.33, g = 0.33, b = 0.33;
+
+      for (; (*l) != 0;) {
+        mend = *l++;
+
+        r += 0.33;
+        if (r > 1.0) {
+           r = 0.33;
+           g += 0.33;
+           if (g > 1.0) {
+              g = 0.33;
+              b += 0.33;
+              if (b > 1.0)
+                 b = 0.33;
+           }
+        }
+
+        glColor3f(r, g, b);
+        glBegin(GL_TRIANGLE_STRIP);
+        for (j = 0; j < mend; j++) {
+           f += 4;
+           glTexCoord2fv(f);
+           f += 2;
+           glVertex3fv(f);
+           f += 3;
+        }
+        glEnd();
+      }
+   }
+   else
+      for (; (*l) != 0;) {
+        mend = *l++;
+
+        glBegin(GL_TRIANGLE_STRIP);
+        for (j = 0; j < mend; j++) {
+           glColor4fv(f);
+           f += 4;
+           glTexCoord2fv(f);
+           f += 2;
+           glVertex3fv(f);
+           f += 3;
+        }
+        glEnd();
+      }
+}
+
+static float
+gettime(void)
+{
+   static clock_t told = 0;
+   clock_t tnew, ris;
+
+   tnew = clock();
+
+   ris = tnew - told;
+
+   told = tnew;
+
+   return (ris / (float) CLOCKS_PER_SEC);
+}
+
+static void
+calcposobs(void)
+{
+   dir[0] = sin(alpha * M_PI / 180.0);
+   dir[1] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
+   dir[2] = cos(beta * M_PI / 180.0);
+
+   obs[0] += v * dir[0];
+   obs[1] += v * dir[1];
+   obs[2] += v * dir[2];
+}
+
+static void
+special(int k, int x, int y)
+{
+   switch (k) {
+   case GLUT_KEY_LEFT:
+      alpha -= 2.0;
+      break;
+   case GLUT_KEY_RIGHT:
+      alpha += 2.0;
+      break;
+   case GLUT_KEY_DOWN:
+      beta -= 2.0;
+      break;
+   case GLUT_KEY_UP:
+      beta += 2.0;
+      break;
+   }
+}
+
+static void
+key(unsigned char k, int x, int y)
+{
+   switch (k) {
+   case 27:
+      exit(0);
+      break;
+
+   case 'a':
+      v += 0.01;
+      break;
+   case 'z':
+      v -= 0.01;
+      break;
+
+#ifdef XMESA
+   case ' ':
+      fullscreen = (!fullscreen);
+
+      glutSetWindow(channel[0]);
+      XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
+
+      glutSetWindow(channel[1]);
+      XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
+      break;
+#endif
+
+   case 'j':
+      joyactive = (!joyactive);
+      break;
+   case 'h':
+      help = (!help);
+      break;
+   case 'f':
+      fog = (!fog);
+      break;
+   case 't':
+      usetex = (!usetex);
+      break;
+   case 'b':
+      if (bfcull) {
+        glDisable(GL_CULL_FACE);
+        bfcull = 0;
+      }
+      else {
+        glEnable(GL_CULL_FACE);
+        bfcull = 1;
+      }
+      break;
+   case 'm':
+      cstrip = (!cstrip);
+      break;
+
+   case 'd':
+      fprintf(stderr, "Deleting textures...\n");
+      glDeleteTextures(1, &t1id);
+      glDeleteTextures(1, &t2id);
+      fprintf(stderr, "Loading textures...\n");
+      inittextures();
+      fprintf(stderr, "Done.\n");
+      break;
+   }
+}
+
+static void
+reshapechannel0(int w, int h)
+{
+   float ratio;
+
+   WIDTHC0 = w;
+   HEIGHTC0 = h;
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+
+   ratio = 0.5f * w / (float) h;
+
+   glFrustum(-2.0, 0.0, -1.0 * ratio, 1.0 * ratio, 1.0, 60.0);
+
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glViewport(0, 0, w, h);
+}
+
+static void
+reshapechannel1(int w, int h)
+{
+   float ratio;
+
+   WIDTHC1 = w;
+   HEIGHTC1 = h;
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+
+   ratio = 0.5f * w / (float) h;
+
+   glFrustum(0.0, 2.0, -1.0 * ratio, 1.0 * ratio, 1.0, 60.0);
+
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glViewport(0, 0, w, h);
+}
+
+static void
+printstring(void *font, char *string)
+{
+   int len, i;
+
+   len = (int) strlen(string);
+   for (i = 0; i < len; i++)
+      glutBitmapCharacter(font, string[i]);
+}
+
+static void
+printhelp(void)
+{
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+   glColor4f(0.0, 0.0, 0.0, 0.5);
+   glRecti(40, 40, 600, 440);
+
+   glColor3f(1.0, 0.0, 0.0);
+   glRasterPos2i(300, 420);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help");
+
+   glRasterPos2i(60, 390);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Togle Help");
+   glRasterPos2i(60, 360);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Togle Textures");
+   glRasterPos2i(60, 330);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Togle Fog");
+   glRasterPos2i(60, 300);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "m - Togle strips");
+   glRasterPos2i(60, 270);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "b - Togle Back face culling");
+   glRasterPos2i(60, 240);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate");
+   glRasterPos2i(60, 210);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity");
+   glRasterPos2i(60, 180);
+   printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity");
+
+   glRasterPos2i(60, 150);
+   if (joyavailable)
+      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+                 "j - Togle jostick control (Joystick control available)");
+   else
+      printstring(GLUT_BITMAP_TIMES_ROMAN_24,
+                 "(No Joystick control available)");
+}
+
+static void
+dojoy(void)
+{
+#ifdef WIN32
+   static UINT max[2] = { 0, 0 };
+   static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
+   MMRESULT res;
+   JOYINFO joy;
+
+   res = joyGetPos(JOYSTICKID1, &joy);
+
+   if (res == JOYERR_NOERROR) {
+      joyavailable = 1;
+
+      if (max[0] < joy.wXpos)
+        max[0] = joy.wXpos;
+      if (min[0] > joy.wXpos)
+        min[0] = joy.wXpos;
+      center[0] = (max[0] + min[0]) / 2;
+
+      if (max[1] < joy.wYpos)
+        max[1] = joy.wYpos;
+      if (min[1] > joy.wYpos)
+        min[1] = joy.wYpos;
+      center[1] = (max[1] + min[1]) / 2;
+
+      if (joyactive) {
+        if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
+           alpha -=
+              2.0 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
+        if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
+           beta += 2.0 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
+
+        if (joy.wButtons & JOY_BUTTON1)
+           v += 0.01;
+        if (joy.wButtons & JOY_BUTTON2)
+           v -= 0.01;
+      }
+   }
+   else
+      joyavailable = 0;
+#endif
+}
+
+static void
+draw(void)
+{
+   static int count = 0;
+   static char frbuf[80];
+   int i;
+   float fr, base, offset;
+
+   dojoy();
+
+   glClear(GL_COLOR_BUFFER_BIT);
+
+   glClear(GL_COLOR_BUFFER_BIT);
+
+   if (usetex)
+      glEnable(GL_TEXTURE_2D);
+   else
+      glDisable(GL_TEXTURE_2D);
+
+   if (fog)
+      glEnable(GL_FOG);
+   else
+      glDisable(GL_FOG);
+
+   glShadeModel(GL_SMOOTH);
+
+   glPushMatrix();
+   calcposobs();
+   gluLookAt(obs[0], obs[1], obs[2],
+            obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
+            0.0, 0.0, 1.0);
+
+   if (dir[0] > 0) {
+      offset = 8.0;
+      base = obs[0] - fmod(obs[0], 8.0);
+   }
+   else {
+      offset = -8.0;
+      base = obs[0] + (8.0 - fmod(obs[0], 8.0));
+   }
+
+   glPushMatrix();
+   glTranslatef(base - offset / 2.0, 0.0, 0.0);
+   for (i = 0; i < NUMBLOC; i++) {
+      glTranslatef(offset, 0.0, 0.0);
+      glBindTexture(GL_TEXTURE_2D, t1id);
+      drawobjs(striplength_skin_11, stripdata_skin_11);
+      glBindTexture(GL_TEXTURE_2D, t2id);
+      drawobjs(striplength_skin_12, stripdata_skin_12);
+      drawobjs(striplength_skin_9, stripdata_skin_9);
+      drawobjs(striplength_skin_13, stripdata_skin_13);
+   }
+   glPopMatrix();
+   glPopMatrix();
+
+   if ((count % FRAME) == 0) {
+      fr = gettime();
+      sprintf(frbuf, "Frame rate: %f", FRAME / fr);
+   }
+
+   glDisable(GL_TEXTURE_2D);
+   glDisable(GL_FOG);
+   glShadeModel(GL_FLAT);
+
+   glMatrixMode(GL_PROJECTION);
+   glPushMatrix();
+   glLoadIdentity();
+   glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
+
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+
+   glColor3f(1.0, 0.0, 0.0);
+   glRasterPos2i(10, 10);
+   printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
+   glRasterPos2i(350, 470);
+   printstring(GLUT_BITMAP_HELVETICA_10,
+              "Tunnel2 V1.0 Written by David Bucciarelli (tech.hmw@plus.it)");
+
+   if (help)
+      printhelp();
+
+   glMatrixMode(GL_PROJECTION);
+   glPopMatrix();
+   glMatrixMode(GL_MODELVIEW);
+
+   count++;
+}
+
+static void
+drawchannel0(void)
+{
+   glutSetWindow(channel[0]);
+   draw();
+   glutSwapBuffers();
+}
+
+static void
+drawchannel1(void)
+{
+   glutSetWindow(channel[1]);
+   draw();
+   glutSwapBuffers();
+}
+
+static void
+drawall(void)
+{
+   glutSetWindow(channel[0]);
+   draw();
+   glutSetWindow(channel[1]);
+   draw();
+
+   glutSetWindow(channel[0]);
+   glutSwapBuffers();
+   glutSetWindow(channel[1]);
+   glutSwapBuffers();
+}
+
+static void
+init(void)
+{
+   float fogcolor[4] = { 0.7, 0.7, 0.7, 1.0 };
+
+   glShadeModel(GL_SMOOTH);
+   glDisable(GL_DEPTH_TEST);
+   glEnable(GL_CULL_FACE);
+   glEnable(GL_TEXTURE_2D);
+
+   glEnable(GL_FOG);
+   glFogi(GL_FOG_MODE, GL_EXP2);
+   glFogfv(GL_FOG_COLOR, fogcolor);
+
+   glFogf(GL_FOG_DENSITY, 0.06);
+   glHint(GL_FOG_HINT, GL_NICEST);
+
+   glEnable(GL_BLEND);
+   /*
+   glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
+   glEnable(GL_POLYGON_SMOOTH);
+   */
+
+   glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], fogcolor[3]);
+   glClear(GL_COLOR_BUFFER_BIT);
+}
+
+int
+main(int ac, char **av)
+{
+   fprintf(stderr,
+          "Tunnel2 V1.0\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
+   fprintf(stderr,
+          "You need TWO Voodoo Graphics boards in order to run this demo !\n");
+
+   glutInitWindowPosition(0, 0);
+   glutInitWindowSize(WIDTHC0, HEIGHTC0);
+   glutInit(&ac, av);
+
+   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_ALPHA);
+
+#ifdef FX
+   if (!fxMesaSelectCurrentBoard(0)) {
+      fprintf(stderr, "The first Voodoo Graphics board is missing !?!?\n");
+      return -1;
+   }
+#endif
+   if (!(channel[0] = glutCreateWindow("Channel 0"))) {
+      fprintf(stderr, "Error, couldn't open window\n");
+      return -1;
+   }
+
+   reshapechannel0(WIDTHC0, HEIGHTC0);
+   init();
+   inittextures();
+   glutDisplayFunc(drawchannel0);
+   glutReshapeFunc(reshapechannel0);
+   glutKeyboardFunc(key);
+   glutSpecialFunc(special);
+
+#ifdef FX
+   if (!fxMesaSelectCurrentBoard(1)) {
+      fprintf(stderr, "The second Voodoo Graphics board is missing !\n");
+      exit(-1);
+   }
+#endif
+   glutInitWindowPosition(WIDTHC0, 0);
+   glutInitWindowSize(WIDTHC1, HEIGHTC1);
+   if (!(channel[1] = glutCreateWindow("Channel 1"))) {
+      fprintf(stderr, "Error, couldn't open window\n");
+      exit(-1);
+   }
+
+   reshapechannel1(WIDTHC1, HEIGHTC1);
+   init();
+   inittextures();
+   glutDisplayFunc(drawchannel1);
+   glutReshapeFunc(reshapechannel1);
+   glutKeyboardFunc(key);
+   glutSpecialFunc(special);
+
+   glutIdleFunc(drawall);
+
+   calcposobs();
+
+   glutMainLoop();
+
+   return 0;
+}
diff --git a/progs/demos/tunneldat.c b/progs/demos/tunneldat.c
new file mode 100644 (file)
index 0000000..a450669
--- /dev/null
@@ -0,0 +1,83 @@
+/* Object: skin_13 */
+
+#if defined(_MSC_VER) && defined(_WIN32)
+#pragma warning( disable : 4305 ) /* 'initializing' : truncation from 'const double' to 'float' */
+#endif
+
+int striplength_skin_13[]={
+10,7,3,5,5,4,4,4,4,5,3,4,5,4,4,4,4,4,4,6,
+6,3,6,3,3,3,3,0};
+
+float stripdata_skin_13[]={
+0.415686,0.415686,0.415686,1.000000,0.000000,1.500000,2.000000,4.000000,0.000000,0.341176,0.341176,0.341176,1.000000,-0.500000,1.500000,4.000000,4.000000,0.000000,0.545098,0.545098,0.545098,1.000000,0.000000,1.000000,2.000000,4.000000,2.000000,0.435294,0.435294,0.435294,1.000000,-0.500000,1.000000,4.000000,4.000000,2.000000,0.517647,0.517647,0.517647,1.000000,0.000000,0.500000,2.000000,4.000000,4.000000,0.450980,0.450980,0.450980,1.000000,-0.500000,0.500000,4.000000,4.000000,4.000000,0.427451,0.427451,0.427451,1.000000,0.000000,0.000000,2.000000,4.000000,6.000000,0.388235,0.388235,0.388235,1.000000,-0.500000,0.000000,4.000000,4.000000,6.000000,0.356863,0.356863,0.356863,1.000000,0.000000,-0.500000,2.000000,4.000000,8.000000,0.333333,0.333333,0.333333,1.000000,-0.500000,-0.500000,4.000000,4.000000,8.000000,
+0.435294,0.435294,0.435294,1.000000,1.500000,1.000000,-4.000000,4.000000,2.000000,0.415686,0.415686,0.415686,1.000000,1.000000,1.500000,-2.000000,4.000000,0.000000,0.545098,0.545098,0.545098,1.000000,1.000000,1.000000,-2.000000,4.000000,2.000000,0.450980,0.450980,0.450980,1.000000,0.500000,1.500000,0.000000,4.000000,0.000000,0.600000,0.600000,0.600000,1.000000,0.500000,1.000000,0.000000,4.000000,2.000000,0.415686,0.415686,0.415686,1.000000,0.000000,1.500000,2.000000,4.000000,0.000000,0.545098,0.545098,0.545098,1.000000,0.000000,1.000000,2.000000,4.000000,2.000000,
+0.435294,0.435294,0.435294,1.000000,1.500000,1.000000,-4.000000,4.000000,2.000000,0.341176,0.341176,0.341176,1.000000,1.500000,1.500000,-4.000000,4.000000,0.000000,0.415686,0.415686,0.415686,1.000000,1.000000,1.500000,-2.000000,4.000000,0.000000,
+0.356863,0.356863,0.356863,1.000000,0.000000,-0.500000,2.000000,4.000000,8.000000,0.364706,0.364706,0.364706,1.000000,0.500000,-0.500000,0.000000,4.000000,8.000000,0.427451,0.427451,0.427451,1.000000,0.000000,0.000000,2.000000,4.000000,6.000000,0.415686,0.415686,0.415686,1.000000,0.395020,-0.133318,0.420032,4.000000,6.533272,0.423529,0.423529,0.423529,1.000000,0.388550,-0.103582,0.445932,4.000000,6.414327,
+0.423529,0.423529,0.423529,1.000000,0.388550,-0.103582,0.445932,4.000000,6.414327,0.427451,0.427451,0.427451,1.000000,0.383423,-0.069344,0.466541,4.000000,6.277375,0.427451,0.427451,0.427451,1.000000,0.000000,0.000000,2.000000,4.000000,6.000000,0.435294,0.435294,0.435294,1.000000,0.380371,-0.034595,0.478689,4.000000,6.138380,0.439216,0.439216,0.439216,1.000000,0.379272,0.000000,0.482673,4.000000,6.000000,
+0.407843,0.407843,0.407843,1.000000,0.414673,-0.191394,0.341301,4.000000,6.765576,0.411765,0.411765,0.411765,1.000000,0.403687,-0.162957,0.385368,4.000000,6.651829,0.364706,0.364706,0.364706,1.000000,0.500000,-0.500000,0.000000,4.000000,8.000000,0.415686,0.415686,0.415686,1.000000,0.395020,-0.133318,0.420032,4.000000,6.533272,
+0.400000,0.400000,0.400000,1.000000,0.438232,-0.232438,0.247284,4.000000,6.929754,0.403922,0.403922,0.403922,1.000000,0.425171,-0.212276,0.299425,4.000000,6.849104,0.364706,0.364706,0.364706,1.000000,0.500000,-0.500000,0.000000,4.000000,8.000000,0.407843,0.407843,0.407843,1.000000,0.414673,-0.191394,0.341301,4.000000,6.765576,
+0.396078,0.396078,0.396078,1.000000,0.467285,-0.260554,0.130636,4.000000,7.042214,0.400000,0.400000,0.400000,1.000000,0.453857,-0.250068,0.184711,4.000000,7.000273,0.364706,0.364706,0.364706,1.000000,0.500000,-0.500000,0.000000,4.000000,8.000000,0.400000,0.400000,0.400000,1.000000,0.438232,-0.232438,0.247284,4.000000,6.929754,
+0.396078,0.396078,0.396078,1.000000,0.500000,-0.270672,0.000000,4.000000,7.082688,0.396078,0.396078,0.396078,1.000000,0.482788,-0.267902,0.068730,4.000000,7.071609,0.364706,0.364706,0.364706,1.000000,0.500000,-0.500000,0.000000,4.000000,8.000000,0.396078,0.396078,0.396078,1.000000,0.467285,-0.260554,0.130636,4.000000,7.042214,
+0.439216,0.439216,0.439216,1.000000,0.379272,0.000000,0.482673,4.000000,6.000000,0.474510,0.474510,0.474510,1.000000,0.379272,0.180448,0.482673,4.000000,5.278208,0.517647,0.517647,0.517647,1.000000,0.000000,0.500000,2.000000,4.000000,4.000000,0.513726,0.513726,0.513726,1.000000,0.379272,0.360896,0.482673,4.000000,4.556417,0.545098,0.545098,0.545098,1.000000,0.379272,0.500000,0.482673,4.000000,4.000000,
+0.545098,0.545098,0.545098,1.000000,0.379272,0.500000,0.482673,4.000000,4.000000,0.545098,0.545098,0.545098,1.000000,0.000000,1.000000,2.000000,4.000000,2.000000,0.517647,0.517647,0.517647,1.000000,0.000000,0.500000,2.000000,4.000000,4.000000,
+0.600000,0.600000,0.600000,1.000000,0.500000,1.000000,0.000000,4.000000,2.000000,0.545098,0.545098,0.545098,1.000000,0.000000,1.000000,2.000000,4.000000,2.000000,0.552941,0.552941,0.552941,1.000000,0.379272,0.541344,0.482673,4.000000,3.834625,0.545098,0.545098,0.545098,1.000000,0.379272,0.500000,0.482673,4.000000,4.000000,
+0.552941,0.552941,0.552941,1.000000,0.379272,0.541344,0.482673,4.000000,3.834625,0.556863,0.556863,0.556863,1.000000,0.459717,0.541344,0.160891,4.000000,3.834625,0.600000,0.600000,0.600000,1.000000,0.500000,1.000000,0.000000,4.000000,2.000000,0.556863,0.556863,0.556863,1.000000,0.500000,0.541344,0.000000,4.000000,3.834625,0.556863,0.556863,0.556863,1.000000,0.540283,0.541344,-0.160891,4.000000,3.834625,
+0.396078,0.396078,0.396078,1.000000,0.517212,-0.267902,-0.068730,4.000000,7.071609,0.396078,0.396078,0.396078,1.000000,0.500000,-0.270672,0.000000,4.000000,7.082688,0.356863,0.356863,0.356863,1.000000,1.000000,-0.500000,-2.000000,4.000000,8.000000,0.364706,0.364706,0.364706,1.000000,0.500000,-0.500000,0.000000,4.000000,8.000000,
+0.400000,0.400000,0.400000,1.000000,0.546143,-0.250068,-0.184711,4.000000,7.000273,0.396078,0.396078,0.396078,1.000000,0.532715,-0.260554,-0.130636,4.000000,7.042214,0.356863,0.356863,0.356863,1.000000,1.000000,-0.500000,-2.000000,4.000000,8.000000,0.396078,0.396078,0.396078,1.000000,0.517212,-0.267902,-0.068730,4.000000,7.071609,
+0.403922,0.403922,0.403922,1.000000,0.574829,-0.212276,-0.299425,4.000000,6.849104,0.400000,0.400000,0.400000,1.000000,0.561768,-0.232438,-0.247284,4.000000,6.929754,0.356863,0.356863,0.356863,1.000000,1.000000,-0.500000,-2.000000,4.000000,8.000000,0.400000,0.400000,0.400000,1.000000,0.546143,-0.250068,-0.184711,4.000000,7.000273,
+0.411765,0.411765,0.411765,1.000000,0.596313,-0.162957,-0.385368,4.000000,6.651829,0.407843,0.407843,0.407843,1.000000,0.585327,-0.191394,-0.341301,4.000000,6.765576,0.356863,0.356863,0.356863,1.000000,1.000000,-0.500000,-2.000000,4.000000,8.000000,0.403922,0.403922,0.403922,1.000000,0.574829,-0.212276,-0.299425,4.000000,6.849104,
+0.423529,0.423529,0.423529,1.000000,0.611450,-0.103582,-0.445931,4.000000,6.414327,0.415686,0.415686,0.415686,1.000000,0.604980,-0.133318,-0.420033,4.000000,6.533272,0.356863,0.356863,0.356863,1.000000,1.000000,-0.500000,-2.000000,4.000000,8.000000,0.411765,0.411765,0.411765,1.000000,0.596313,-0.162957,-0.385368,4.000000,6.651829,
+0.435294,0.435294,0.435294,1.000000,0.619629,-0.034595,-0.478689,4.000000,6.138380,0.427451,0.427451,0.427451,1.000000,0.616577,-0.069344,-0.466541,4.000000,6.277375,0.356863,0.356863,0.356863,1.000000,1.000000,-0.500000,-2.000000,4.000000,8.000000,0.423529,0.423529,0.423529,1.000000,0.611450,-0.103582,-0.445931,4.000000,6.414327,
+0.513726,0.513726,0.513726,1.000000,0.620728,0.360896,-0.482673,4.000000,4.556417,0.474510,0.474510,0.474510,1.000000,0.620728,0.180448,-0.482673,4.000000,5.278208,0.427451,0.427451,0.427451,1.000000,1.000000,0.000000,-2.000000,4.000000,6.000000,0.439216,0.439216,0.439216,1.000000,0.620728,0.000000,-0.482673,4.000000,6.000000,0.356863,0.356863,0.356863,1.000000,1.000000,-0.500000,-2.000000,4.000000,8.000000,0.435294,0.435294,0.435294,1.000000,0.619629,-0.034595,-0.478689,4.000000,6.138380,
+0.333333,0.333333,0.333333,1.000000,1.500000,-0.500000,-4.000000,4.000000,8.000000,0.388235,0.388235,0.388235,1.000000,1.500000,0.000000,-4.000000,4.000000,6.000000,0.427451,0.427451,0.427451,1.000000,1.000000,0.000000,-2.000000,4.000000,6.000000,0.517647,0.517647,0.517647,1.000000,1.000000,0.500000,-2.000000,4.000000,4.000000,0.513726,0.513726,0.513726,1.000000,0.620728,0.360896,-0.482673,4.000000,4.556417,0.545098,0.545098,0.545098,1.000000,0.620728,0.500000,-0.482673,4.000000,4.000000,
+0.333333,0.333333,0.333333,1.000000,1.500000,-0.500000,-4.000000,4.000000,8.000000,0.427451,0.427451,0.427451,1.000000,1.000000,0.000000,-2.000000,4.000000,6.000000,0.356863,0.356863,0.356863,1.000000,1.000000,-0.500000,-2.000000,4.000000,8.000000,
+0.556863,0.556863,0.556863,1.000000,0.540283,0.541344,-0.160891,4.000000,3.834625,0.552941,0.552941,0.552941,1.000000,0.620728,0.541344,-0.482673,4.000000,3.834625,0.545098,0.545098,0.545098,1.000000,1.000000,1.000000,-2.000000,4.000000,2.000000,0.517647,0.517647,0.517647,1.000000,1.000000,0.500000,-2.000000,4.000000,4.000000,0.450980,0.450980,0.450980,1.000000,1.500000,0.500000,-4.000000,4.000000,4.000000,0.388235,0.388235,0.388235,1.000000,1.500000,0.000000,-4.000000,4.000000,6.000000,
+0.517647,0.517647,0.517647,1.000000,1.000000,0.500000,-2.000000,4.000000,4.000000,0.552941,0.552941,0.552941,1.000000,0.620728,0.541344,-0.482673,4.000000,3.834625,0.545098,0.545098,0.545098,1.000000,0.620728,0.500000,-0.482673,4.000000,4.000000,
+0.450980,0.450980,0.450980,1.000000,1.500000,0.500000,-4.000000,4.000000,4.000000,0.435294,0.435294,0.435294,1.000000,1.500000,1.000000,-4.000000,4.000000,2.000000,0.545098,0.545098,0.545098,1.000000,1.000000,1.000000,-2.000000,4.000000,2.000000,
+0.439216,0.439216,0.439216,1.000000,0.379272,0.000000,0.482673,4.000000,6.000000,0.517647,0.517647,0.517647,1.000000,0.000000,0.500000,2.000000,4.000000,4.000000,0.427451,0.427451,0.427451,1.000000,0.000000,0.000000,2.000000,4.000000,6.000000,
+0.556863,0.556863,0.556863,1.000000,0.540283,0.541344,-0.160891,4.000000,3.834625,0.545098,0.545098,0.545098,1.000000,1.000000,1.000000,-2.000000,4.000000,2.000000,0.600000,0.600000,0.600000,1.000000,0.500000,1.000000,0.000000,4.000000,2.000000
+
+};
+
+
+/* Object: skin_12 */
+
+int striplength_skin_12[]={
+12,12,12,12,12,0};
+
+float stripdata_skin_12[]={
+0.498039,0.498039,0.498039,1.000000,-0.099976,1.500000,-2.400000,-4.000000,-0.000002,0.337255,0.337255,0.337255,1.000000,-0.500000,1.500000,-4.000000,-4.000000,-0.000002,0.568627,0.568627,0.568627,1.000000,-0.099976,1.100000,-2.400000,-4.000000,1.599999,0.341176,0.341176,0.341176,1.000000,-0.500000,1.100000,-4.000000,-4.000000,1.599999,0.498039,0.498039,0.498039,1.000000,-0.099976,0.700000,-2.400000,-4.000000,3.200000,0.325490,0.325490,0.325490,1.000000,-0.500000,0.700000,-4.000000,-4.000000,3.199999,0.352941,0.352941,0.352941,1.000000,-0.099976,0.300000,-2.400000,-4.000000,4.800000,0.282353,0.282353,0.282353,1.000000,-0.500000,0.300000,-4.000000,-4.000000,4.800000,0.282353,0.282353,0.282353,1.000000,-0.099976,-0.100000,-2.400000,-4.000000,6.400001,0.254902,0.254902,0.254902,1.000000,-0.500000,-0.100000,-4.000000,-4.000000,6.400000,0.239216,0.239216,0.239216,1.000000,-0.099976,-0.500000,-2.400000,-4.000000,8.000000,0.227451,0.227451,0.227451,1.000000,-0.500000,-0.500000,-4.000000,-4.000000,8.000000,
+0.239216,0.239216,0.239216,1.000000,1.099976,-0.500000,2.400001,-4.000000,8.000000,0.227451,0.227451,0.227451,1.000000,1.500000,-0.500000,4.000002,-4.000000,8.000000,0.282353,0.282353,0.282353,1.000000,1.099976,-0.100000,2.400001,-4.000000,6.400001,0.254902,0.254902,0.254902,1.000000,1.500000,-0.100000,4.000002,-4.000000,6.400001,0.352941,0.352941,0.352941,1.000000,1.099976,0.300000,2.400002,-4.000000,4.800001,0.282353,0.282353,0.282353,1.000000,1.500000,0.300000,4.000002,-4.000000,4.800001,0.498039,0.498039,0.498039,1.000000,1.099976,0.700000,2.400002,-4.000000,3.200000,0.321569,0.321569,0.321569,1.000000,1.500000,0.700000,4.000003,-4.000000,3.200000,0.568627,0.568627,0.568627,1.000000,1.099976,1.100000,2.400002,-4.000000,1.599999,0.341176,0.341176,0.341176,1.000000,1.500000,1.100000,4.000003,-4.000000,1.599999,0.494118,0.494118,0.494118,1.000000,1.099976,1.500000,2.400003,-4.000000,-0.000002,0.337255,0.337255,0.337255,1.000000,1.500000,1.500000,4.000004,-4.000000,-0.000002,
+0.639216,0.639216,0.639216,1.000000,0.300049,1.500000,-0.799999,-4.000000,-0.000002,0.498039,0.498039,0.498039,1.000000,-0.099976,1.500000,-2.400000,-4.000000,-0.000002,0.858824,0.858824,0.858824,1.000000,0.300049,1.100000,-0.799999,-4.000000,1.599999,0.568627,0.568627,0.568627,1.000000,-0.099976,1.100000,-2.400000,-4.000000,1.599999,0.686275,0.686275,0.686275,1.000000,0.300049,0.700000,-0.799999,-4.000000,3.200000,0.498039,0.498039,0.498039,1.000000,-0.099976,0.700000,-2.400000,-4.000000,3.200000,0.419608,0.419608,0.419608,1.000000,0.300049,0.300000,-0.800000,-4.000000,4.800000,0.352941,0.352941,0.352941,1.000000,-0.099976,0.300000,-2.400000,-4.000000,4.800000,0.298039,0.298039,0.298039,1.000000,0.300049,-0.100000,-0.800000,-4.000000,6.400001,0.282353,0.282353,0.282353,1.000000,-0.099976,-0.100000,-2.400000,-4.000000,6.400001,0.247059,0.247059,0.247059,1.000000,0.300049,-0.500000,-0.800000,-4.000000,8.000000,0.239216,0.239216,0.239216,1.000000,-0.099976,-0.500000,-2.400000,-4.000000,8.000000,
+0.639216,0.639216,0.639216,1.000000,0.699951,1.500000,0.800002,-4.000000,-0.000002,0.639216,0.639216,0.639216,1.000000,0.300049,1.500000,-0.799999,-4.000000,-0.000002,0.858824,0.858824,0.858824,1.000000,0.699951,1.100000,0.800001,-4.000000,1.599999,0.858824,0.858824,0.858824,1.000000,0.300049,1.100000,-0.799999,-4.000000,1.599999,0.686275,0.686275,0.686275,1.000000,0.699951,0.700000,0.800001,-4.000000,3.200000,0.686275,0.686275,0.686275,1.000000,0.300049,0.700000,-0.799999,-4.000000,3.200000,0.419608,0.419608,0.419608,1.000000,0.699951,0.300000,0.800001,-4.000000,4.800001,0.419608,0.419608,0.419608,1.000000,0.300049,0.300000,-0.800000,-4.000000,4.800000,0.298039,0.298039,0.298039,1.000000,0.699951,-0.100000,0.800001,-4.000000,6.400001,0.298039,0.298039,0.298039,1.000000,0.300049,-0.100000,-0.800000,-4.000000,6.400001,0.247059,0.247059,0.247059,1.000000,0.699951,-0.500000,0.800000,-4.000000,8.000000,0.247059,0.247059,0.247059,1.000000,0.300049,-0.500000,-0.800000,-4.000000,8.000000,
+0.494118,0.494118,0.494118,1.000000,1.099976,1.500000,2.400003,-4.000000,-0.000002,0.639216,0.639216,0.639216,1.000000,0.699951,1.500000,0.800002,-4.000000,-0.000002,0.568627,0.568627,0.568627,1.000000,1.099976,1.100000,2.400002,-4.000000,1.599999,0.858824,0.858824,0.858824,1.000000,0.699951,1.100000,0.800001,-4.000000,1.599999,0.498039,0.498039,0.498039,1.000000,1.099976,0.700000,2.400002,-4.000000,3.200000,0.686275,0.686275,0.686275,1.000000,0.699951,0.700000,0.800001,-4.000000,3.200000,0.352941,0.352941,0.352941,1.000000,1.099976,0.300000,2.400002,-4.000000,4.800001,0.419608,0.419608,0.419608,1.000000,0.699951,0.300000,0.800001,-4.000000,4.800001,0.282353,0.282353,0.282353,1.000000,1.099976,-0.100000,2.400001,-4.000000,6.400001,0.298039,0.298039,0.298039,1.000000,0.699951,-0.100000,0.800001,-4.000000,6.400001,0.239216,0.239216,0.239216,1.000000,1.099976,-0.500000,2.400001,-4.000000,8.000000,0.247059,0.247059,0.247059,1.000000,0.699951,-0.500000,0.800000,-4.000000,8.000000
+
+};
+
+
+/* Object: skin_11 */
+
+int striplength_skin_11[]={
+12,12,12,12,12,0};
+
+float stripdata_skin_11[]={
+0.145098,0.145098,0.145098,1.000000,-0.099976,1.500000,-2.400000,4.000002,0.000000,0.141176,0.141176,0.141176,1.000000,-0.500000,1.500000,-4.000000,4.000002,0.000000,0.176471,0.176471,0.176471,1.000000,-0.099976,1.100000,-2.400000,2.400001,0.000000,0.145098,0.145098,0.145098,1.000000,-0.500000,1.100000,-4.000000,2.400001,0.000000,0.341176,0.341176,0.341176,1.000000,-0.099976,0.700000,-2.400000,0.800000,0.000000,0.188235,0.188235,0.188235,1.000000,-0.500000,0.700000,-4.000000,0.800000,0.000000,0.450980,0.450980,0.450980,1.000000,-0.099976,0.300000,-2.400000,-0.800000,0.000000,0.247059,0.247059,0.247059,1.000000,-0.500000,0.300000,-4.000000,-0.800000,0.000000,0.439216,0.439216,0.439216,1.000000,-0.099976,-0.100000,-2.400000,-2.400000,0.000000,0.270588,0.270588,0.270588,1.000000,-0.500000,-0.100000,-4.000000,-2.400000,0.000000,0.364706,0.364706,0.364706,1.000000,-0.099976,-0.500000,-2.400000,-4.000000,0.000000,0.258824,0.258824,0.258824,1.000000,-0.500000,-0.500000,-4.000000,-4.000000,0.000000,
+0.364706,0.364706,0.364706,1.000000,1.099976,-0.500000,2.400001,-4.000000,0.000000,0.258824,0.258824,0.258824,1.000000,1.500000,-0.500000,4.000002,-4.000000,0.000000,0.439216,0.439216,0.439216,1.000000,1.099976,-0.100000,2.400001,-2.400001,0.000000,0.270588,0.270588,0.270588,1.000000,1.500000,-0.100000,4.000002,-2.400001,0.000000,0.454902,0.454902,0.454902,1.000000,1.099976,0.300000,2.400002,-0.800000,0.000000,0.247059,0.247059,0.247059,1.000000,1.500000,0.300000,4.000002,-0.800000,0.000000,0.341176,0.341176,0.341176,1.000000,1.099976,0.700000,2.400002,0.800000,0.000000,0.184314,0.184314,0.184314,1.000000,1.500000,0.700000,4.000003,0.800000,0.000000,0.176471,0.176471,0.176471,1.000000,1.099976,1.100000,2.400002,2.400001,0.000000,0.145098,0.145098,0.145098,1.000000,1.500000,1.100000,4.000003,2.400001,0.000000,0.145098,0.145098,0.145098,1.000000,1.099976,1.500000,2.400003,4.000003,0.000000,0.141176,0.141176,0.141176,1.000000,1.500000,1.500000,4.000004,4.000002,0.000000,
+0.145098,0.145098,0.145098,1.000000,0.300049,1.500000,-0.799999,4.000002,0.000000,0.145098,0.145098,0.145098,1.000000,-0.099976,1.500000,-2.400000,4.000002,0.000000,0.262745,0.262745,0.262745,1.000000,0.300049,1.100000,-0.799999,2.400001,0.000000,0.176471,0.176471,0.176471,1.000000,-0.099976,1.100000,-2.400000,2.400001,0.000000,0.580392,0.580392,0.580392,1.000000,0.300049,0.700000,-0.799999,0.800000,0.000000,0.341176,0.341176,0.341176,1.000000,-0.099976,0.700000,-2.400000,0.800000,0.000000,0.709804,0.709804,0.709804,1.000000,0.300049,0.300000,-0.800000,-0.800000,0.000000,0.450980,0.450980,0.450980,1.000000,-0.099976,0.300000,-2.400000,-0.800000,0.000000,0.627451,0.627451,0.627451,1.000000,0.300049,-0.100000,-0.800000,-2.400001,0.000000,0.439216,0.439216,0.439216,1.000000,-0.099976,-0.100000,-2.400000,-2.400000,0.000000,0.458824,0.458824,0.458824,1.000000,0.300049,-0.500000,-0.800000,-4.000000,0.000000,0.364706,0.364706,0.364706,1.000000,-0.099976,-0.500000,-2.400000,-4.000000,0.000000,
+0.145098,0.145098,0.145098,1.000000,0.699951,1.500000,0.800002,4.000002,0.000000,0.145098,0.145098,0.145098,1.000000,0.300049,1.500000,-0.799999,4.000002,0.000000,0.262745,0.262745,0.262745,1.000000,0.699951,1.100000,0.800001,2.400001,0.000000,0.262745,0.262745,0.262745,1.000000,0.300049,1.100000,-0.799999,2.400001,0.000000,0.580392,0.580392,0.580392,1.000000,0.699951,0.700000,0.800001,0.800000,0.000000,0.580392,0.580392,0.580392,1.000000,0.300049,0.700000,-0.799999,0.800000,0.000000,0.713726,0.713726,0.713726,1.000000,0.699951,0.300000,0.800001,-0.800000,0.000000,0.709804,0.709804,0.709804,1.000000,0.300049,0.300000,-0.800000,-0.800000,0.000000,0.631373,0.631373,0.631373,1.000000,0.699951,-0.100000,0.800001,-2.400001,0.000000,0.627451,0.627451,0.627451,1.000000,0.300049,-0.100000,-0.800000,-2.400001,0.000000,0.458824,0.458824,0.458824,1.000000,0.699951,-0.500000,0.800000,-4.000000,0.000000,0.458824,0.458824,0.458824,1.000000,0.300049,-0.500000,-0.800000,-4.000000,0.000000,
+0.145098,0.145098,0.145098,1.000000,1.099976,1.500000,2.400003,4.000003,0.000000,0.145098,0.145098,0.145098,1.000000,0.699951,1.500000,0.800002,4.000002,0.000000,0.176471,0.176471,0.176471,1.000000,1.099976,1.100000,2.400002,2.400001,0.000000,0.262745,0.262745,0.262745,1.000000,0.699951,1.100000,0.800001,2.400001,0.000000,0.341176,0.341176,0.341176,1.000000,1.099976,0.700000,2.400002,0.800000,0.000000,0.580392,0.580392,0.580392,1.000000,0.699951,0.700000,0.800001,0.800000,0.000000,0.454902,0.454902,0.454902,1.000000,1.099976,0.300000,2.400002,-0.800000,0.000000,0.713726,0.713726,0.713726,1.000000,0.699951,0.300000,0.800001,-0.800000,0.000000,0.439216,0.439216,0.439216,1.000000,1.099976,-0.100000,2.400001,-2.400001,0.000000,0.631373,0.631373,0.631373,1.000000,0.699951,-0.100000,0.800001,-2.400001,0.000000,0.364706,0.364706,0.364706,1.000000,1.099976,-0.500000,2.400001,-4.000000,0.000000,0.458824,0.458824,0.458824,1.000000,0.699951,-0.500000,0.800000,-4.000000,0.000000
+
+};
+
+
+/* Object: skin_9 */
+
+int striplength_skin_9[]={
+18,0};
+
+float stripdata_skin_9[]={
+0.384314,0.384314,0.384314,1.000000,-0.500000,1.500000,-4.000000,4.000000,8.000000,0.384314,0.384314,0.384314,1.000000,1.500000,1.500000,4.000000,4.000000,8.000000,0.376471,0.376471,0.376471,1.000000,-0.500000,1.250000,-4.000000,3.695518,9.530733,0.403922,0.403922,0.403922,1.000000,1.500000,1.250000,4.000000,3.695518,9.530733,0.415686,0.415686,0.415686,1.000000,-0.500000,1.000000,-4.000000,2.828427,10.828427,0.431373,0.431373,0.431373,1.000000,1.500000,1.000000,4.000000,2.828427,10.828427,0.435294,0.435294,0.435294,1.000000,-0.500000,0.750000,-4.000000,1.530734,11.695518,0.443137,0.443137,0.443137,1.000000,1.500000,0.750000,4.000000,1.530734,11.695518,0.439216,0.439216,0.439216,1.000000,-0.500000,0.500000,-4.000000,0.000000,12.000000,0.435294,0.435294,0.435294,1.000000,1.500000,0.500000,4.000000,0.000000,12.000000,0.427451,0.427451,0.427451,1.000000,-0.500000,0.250000,-4.000000,-1.530734,11.695518,0.411765,0.411765,0.411765,1.000000,1.500000,0.250000,4.000000,-1.530734,11.695518,0.396078,0.396078,0.396078,1.000000,-0.500000,0.000000,-4.000000,-2.828427,10.828427,0.368627,0.368627,0.368627,1.000000,1.500000,0.000000,4.000000,-2.828427,10.828427,0.341176,0.341176,0.341176,1.000000,-0.500000,-0.250000,-4.000000,-3.695518,9.530733,0.301961,0.301961,0.301961,1.000000,1.500000,-0.250000,4.000000,-3.695518,9.530733,0.294118,0.294118,0.294118,1.000000,-0.500000,-0.500000,-4.000000,-4.000000,8.000000,0.294118,0.294118,0.294118,1.000000,1.500000,-0.500000,4.000000,-4.000000,8.000000
+
+};
+
+