/*
**	$VER: tex_test.c 1.0 (20.03.1997)
**
**	This is an example program for CyberGL
**
**      Written by Frank Gerberding
**
**	Copyright © 1996-1997 by phase5 digital products
**      All Rights reserved.
**
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <clib/exec_protos.h>

#define CYBERGLNAME             "cybergl.library"
#define CYBERGLVERSION          39L


#define SHARED                  /* we use the cybergl shared library */
#define GL_APICOMPATIBLE        /* we use stubs from cybergl.lib */


#include "cybergl.h"
#include "cybergl_protos.h"
#include "cybergl_display.h"

#ifdef SHARED
LONG __oslibversion   = 39L;
LONG __CGLlibversion = CYBERGLVERSION;
#include "cybergl_pragmas.h"
extern  struct  Library *CyberGLBase;
#endif


#define WIDTH    640
#define HEIGHT   480





GLushort rMap256 [256] = {
  0x0000, 0x0000, 0x0CCC, 0x0CCC, 0x1444, 0x1000, 0x1000, 0x1888,
  0x2444, 0x2444, 0x2444, 0x2000, 0x2444, 0x2000, 0x3111, 0x3111,
  0x2000, 0x3111, 0x2888, 0x3555, 0x3111, 0x3111, 0x2888, 0x3999,
  0x3111, 0x4111, 0x3999, 0x3555, 0x3111, 0x4555, 0x4555, 0x4555,
  0x3999, 0x4111, 0x4DDD, 0x3999, 0x5111, 0x4999, 0x4DDD, 0x4555,
  0x4555, 0x5555, 0x3999, 0x5555, 0x5111, 0x4111, 0x5111, 0x4999,
  0x5555, 0x5555, 0x5555, 0x4999, 0x4999, 0x5111, 0x6555, 0x5999,
  0x6555, 0x4111, 0x5999, 0x6111, 0x5555, 0x4DDD, 0x6999, 0x6111,
  0x6999, 0x5111, 0x6111, 0x6999, 0x6111, 0x6555, 0x7555, 0x5111,
  0x6555, 0x4DDD, 0x6555, 0x6111, 0x7555, 0x5DDD, 0x6999, 0x7999,
  0x4DDD, 0x6555, 0x6555, 0x5999, 0x7555, 0x7999, 0x7111, 0x5DDD,
  0x6999, 0x7555, 0x6999, 0x7111, 0x7111, 0x8666, 0x7DDD, 0x6555,
  0x5111, 0x7555, 0x7111, 0x5999, 0x8666, 0x6111, 0x8AAA, 0x7111,
  0x7999, 0x7555, 0x7111, 0x6999, 0x8666, 0x6DDD, 0x5DDD, 0x8222,
  0x6999, 0x8EEE, 0x7999, 0x8666, 0x8222, 0x9222, 0x7111, 0x7999,
  0x9666, 0x6DDD, 0x6111, 0x8666, 0x8666, 0x6111, 0x6999, 0x8222,
  0x7111, 0x9AAA, 0x8666, 0x8222, 0x6DDD, 0x9EEE, 0x7111, 0x8EEE,
  0x7DDD, 0x7111, 0x8EEE, 0x9EEE, 0x6999, 0xA666, 0x8EEE, 0x8AAA,
  0x8AAA, 0x8AAA, 0x7999, 0xA666, 0x7111, 0x8AAA, 0x9EEE, 0x8666,
  0x9666, 0x6DDD, 0x8AAA, 0x9222, 0x7999, 0x9666, 0x8666, 0x9AAA,
  0x9666, 0x8666, 0x9AAA, 0x9666, 0x9AAA, 0x8AAA, 0x8666, 0x9666,
  0x7999, 0x8AAA, 0x9EEE, 0x9AAA, 0x8AAA, 0x8666, 0x9666, 0xA666,
  0x9AAA, 0xA666, 0x9AAA, 0xA222, 0xA666, 0xAEEE, 0x9666, 0x9666,
  0x9EEE, 0x9222, 0xAEEE, 0x9EEE, 0x9EEE, 0x9AAA, 0xAEEE, 0xAEEE,
  0x9EEE, 0xBAAA, 0xA666, 0x8EEE, 0xB666, 0xAEEE, 0xB666, 0xA666,
  0xA222, 0xAEEE, 0xB666, 0xB222, 0xAAAA, 0xAEEE, 0xAEEE, 0xBEEE,
  0xB222, 0xC222, 0xAAAA, 0xB222, 0xB666, 0xBAAA, 0xBAAA, 0xB666,
  0xCAAA, 0xB666, 0xC666, 0xC666, 0xC666, 0xBEEE, 0xC666, 0xB666,
  0xC666, 0xCEEE, 0xCEEE, 0xCEEE, 0xD666, 0xCEEE, 0xD666, 0xD666,
  0xB666, 0xDFFF, 0xDFFF, 0xDBBB, 0xE333, 0xDFFF, 0xE333, 0xE777,
  0xE777, 0xEFFF, 0xEFFF, 0xEFFF, 0xF777, 0xF777, 0xF777, 0xFBBB,
  0xFBBB, 0xFBBB, 0xF777, 0xF333, 0xFBBB, 0xF333, 0xF777, 0xF333
};

GLushort gMap256 [256] = {
  0x0000, 0x0000, 0x0888, 0x1000, 0x0444, 0x1000, 0x1000, 0x1888,
  0x0000, 0x0444, 0x0CCC, 0x1444, 0x1888, 0x2000, 0x0CCC, 0x0000,
  0x2000, 0x1888, 0x2444, 0x0CCC, 0x2000, 0x2000, 0x2444, 0x2000,
  0x2888, 0x0CCC, 0x2888, 0x2DDD, 0x3111, 0x1000, 0x1CCC, 0x2888,
  0x3555, 0x3111, 0x2888, 0x3999, 0x1000, 0x3111, 0x2888, 0x2DDD,
  0x3555, 0x1888, 0x3999, 0x1000, 0x1CCC, 0x3999, 0x3111, 0x3999,
  0x3555, 0x2DDD, 0x3999, 0x4111, 0x4111, 0x3999, 0x1444, 0x3999,
  0x1444, 0x3DDD, 0x4111, 0x3555, 0x4555, 0x4999, 0x1888, 0x3999,
  0x2444, 0x4DDD, 0x4111, 0x2888, 0x4111, 0x3555, 0x1888, 0x5111,
  0x4111, 0x4DDD, 0x4999, 0x4999, 0x1888, 0x4DDD, 0x4555, 0x2444,
  0x4DDD, 0x4999, 0x4111, 0x5111, 0x1CCC, 0x2444, 0x4555, 0x5555,
  0x4999, 0x3111, 0x5111, 0x4DDD, 0x4999, 0x1444, 0x2DDD, 0x5555,
  0x5111, 0x3DDD, 0x5111, 0x5111, 0x2000, 0x5999, 0x1CCC, 0x5555,
  0x5111, 0x5555, 0x5999, 0x6111, 0x3555, 0x5999, 0x5999, 0x4555,
  0x6111, 0x2888, 0x5999, 0x5555, 0x4999, 0x2000, 0x6555, 0x5999,
  0x2DDD, 0x6555, 0x6111, 0x5999, 0x5999, 0x5999, 0x6111, 0x6111,
  0x6999, 0x2444, 0x5555, 0x6111, 0x6555, 0x2888, 0x6999, 0x6111,
  0x6999, 0x6DDD, 0x6111, 0x3DDD, 0x6111, 0x2888, 0x6111, 0x6111,
  0x6999, 0x6999, 0x7111, 0x2888, 0x7111, 0x6999, 0x5111, 0x7111,
  0x6999, 0x6DDD, 0x7555, 0x6111, 0x7555, 0x6999, 0x7999, 0x6DDD,
  0x7111, 0x7999, 0x6111, 0x7111, 0x7555, 0x7999, 0x7DDD, 0x7555,
  0x7999, 0x8666, 0x7999, 0x7999, 0x8666, 0x8222, 0x8222, 0x7999,
  0x8666, 0x7999, 0x8AAA, 0x7999, 0x8666, 0x7555, 0x8EEE, 0x7DDD,
  0x8EEE, 0x8AAA, 0x8666, 0x8AAA, 0x9666, 0x8EEE, 0x8AAA, 0x8AAA,
  0x9222, 0x7999, 0x9666, 0x8EEE, 0x8AAA, 0x9222, 0x9222, 0x9AAA,
  0x9666, 0x9AAA, 0x9666, 0x9AAA, 0x9AAA, 0xA666, 0xA666, 0x9AAA,
  0xAAAA, 0x9AAA, 0xA666, 0xAAAA, 0xAAAA, 0xAEEE, 0xAEEE, 0xAEEE,
  0xA222, 0xAAAA, 0xB222, 0xB222, 0xBAAA, 0xB666, 0xBAAA, 0xAEEE,
  0xBAAA, 0xBEEE, 0xBEEE, 0xC666, 0xC222, 0xC666, 0xC666, 0xC666,
  0xB666, 0xCEEE, 0xC666, 0xCEEE, 0xD666, 0xD666, 0xCEEE, 0xD666,
  0xDBBB, 0xDFFF, 0xD666, 0xDFFF, 0xE777, 0xE777, 0xEFFF, 0xF333,
  0xF777, 0xF777, 0xFFFF, 0xF333, 0xFBBB, 0xF333, 0xFBBB, 0xF333
};

GLushort bMap256 [256] = {
  0x0000, 0x0888, 0x0444, 0x0000, 0x0444, 0x0888, 0x1000, 0x0CCC,
  0x0888, 0x0000, 0x0444, 0x0444, 0x0888, 0x0CCC, 0x0888, 0x0888,
  0x1888, 0x0000, 0x0CCC, 0x1000, 0x0444, 0x1888, 0x2444, 0x0444,
  0x1888, 0x1000, 0x0444, 0x1000, 0x1888, 0x1444, 0x0888, 0x0444,
  0x1888, 0x0CCC, 0x0444, 0x2000, 0x1888, 0x0888, 0x1444, 0x2000,
  0x1888, 0x1444, 0x2DDD, 0x2000, 0x2000, 0x2000, 0x0888, 0x1444,
  0x0444, 0x2000, 0x1000, 0x2888, 0x2444, 0x2444, 0x1CCC, 0x0888,
  0x2000, 0x4111, 0x1444, 0x0000, 0x2000, 0x2888, 0x2000, 0x0CCC,
  0x2000, 0x2888, 0x0888, 0x2444, 0x1444, 0x2888, 0x2000, 0x3555,
  0x2444, 0x3DDD, 0x0CCC, 0x1888, 0x2888, 0x2888, 0x1000, 0x1CCC,
  0x4999, 0x1CCC, 0x3111, 0x3111, 0x3111, 0x2888, 0x0CCC, 0x2DDD,
  0x2DDD, 0x3111, 0x2000, 0x1000, 0x1888, 0x2888, 0x2888, 0x2DDD,
  0x5555, 0x3555, 0x1888, 0x4DDD, 0x2888, 0x3DDD, 0x3111, 0x2888,
  0x1444, 0x2000, 0x3111, 0x3111, 0x3111, 0x3DDD, 0x5111, 0x2DDD,
  0x3999, 0x3111, 0x2888, 0x1444, 0x3999, 0x3555, 0x3111, 0x3555,
  0x2888, 0x3DDD, 0x5111, 0x2000, 0x2888, 0x6111, 0x4DDD, 0x2000,
  0x3DDD, 0x3555, 0x3999, 0x2DDD, 0x5111, 0x3999, 0x4DDD, 0x2000,
  0x3DDD, 0x4999, 0x2888, 0x3555, 0x6555, 0x3555, 0x2DDD, 0x3DDD,
  0x2888, 0x3555, 0x4555, 0x3999, 0x5555, 0x3999, 0x3DDD, 0x4111,
  0x2DDD, 0x6555, 0x3999, 0x4DDD, 0x5555, 0x3999, 0x4111, 0x2888,
  0x3111, 0x4DDD, 0x4DDD, 0x3999, 0x3111, 0x4999, 0x5555, 0x4555,
  0x6DDD, 0x4999, 0x3999, 0x4555, 0x5555, 0x6111, 0x4DDD, 0x3555,
  0x4111, 0x4555, 0x4999, 0x5555, 0x4111, 0x4555, 0x5111, 0x6999,
  0x4999, 0x6555, 0x3DDD, 0x5999, 0x5555, 0x6555, 0x4555, 0x4DDD,
  0x6555, 0x5555, 0x5555, 0x8666, 0x4DDD, 0x5111, 0x4555, 0x5999,
  0x6DDD, 0x5999, 0x5555, 0x5555, 0x6555, 0x5999, 0x6555, 0x5DDD,
  0x6111, 0x6555, 0x7999, 0x6999, 0x6DDD, 0x6111, 0x6999, 0x7999,
  0x6DDD, 0x8666, 0x6555, 0x6DDD, 0x6111, 0x7999, 0x6DDD, 0x9AAA,
  0x7DDD, 0x6DDD, 0x7DDD, 0x7111, 0x6DDD, 0x7DDD, 0x7111, 0x7DDD,
  0xB666, 0x7111, 0x7DDD, 0x7999, 0x7111, 0x7DDD, 0x8222, 0x7DDD,
  0x8EEE, 0x8222, 0x8EEE, 0x8EEE, 0x8222, 0x8EEE, 0x9222, 0x9AAA,
  0x9EEE, 0xAEEE, 0xAAAA, 0xCAAA, 0xB666, 0xD666, 0xCEEE, 0xEFFF
};





GLushort rMap4 [4] = {
  52500,
  45900,
  00000,
  00000
};

GLushort gMap4 [4] = {
  52500,
  00000,
  59000,
  00000
};

GLushort bMap4 [4] = {
  52500,
  00000,
  00000,
  32800
};





GLubyte *loadTexture4 (void)
{
  FILE    *file;
  GLubyte *texture = NULL;

  if (file = fopen ("PROGDIR:texture4.raw", "r"))
  {
    if (texture = malloc (16384))
    {
      fread (texture, 16384, 1, file);
    }
    fclose (file);
  }
  return texture;
}





GLubyte *loadTexture256 (void)
{
  FILE    *file;
  GLubyte *texture = NULL;

  if (file = fopen ("PROGDIR:texture256.raw", "r"))
  {
    if (texture = malloc (65536))
    {
      fread (texture, 65536, 1, file);
    }
    fclose (file);
  }
  return texture;
}





void drawFloor (int patches, GLdouble height, GLdouble factor)
{
  GLdouble x, z;
  GLdouble dx, dz, ds, dt;
  GLdouble s, t;

  dx = 20.0 / ((GLdouble) patches);
  dz = 20.0 / ((GLdouble) patches);
  ds = 2.0  / ((GLdouble) patches);
  dt = 2.0  / ((GLdouble) patches);
  t  = 1.0;
  factor *= 2.0;

  glColor3d  (1.0, 1.0, 1.0);
  glNormal3d (0.0, 1.0, 0.0);

  srand (time (NULL));

  for (z = -10.0; z < 10.0; z += dz)
  {
    s = -1.0;
    glBegin (GL_QUAD_STRIP);
      for (x = -10.0; x <= 10.0; x += dx)
      {
        glEdgeFlag   (GL_TRUE);
        glTexCoord2d (s / factor + 0.5, t / factor + 0.5);
        glVertex3d   (x, height, z);

        glEdgeFlag   (GL_FALSE);
        glTexCoord2d (s / factor + 0.5, (t - dt) / factor + 0.5);
        glVertex3d   (x, height, z + dz);

        s += ds;
      }
    glEnd ();
    t -= dt;
  }
}





void spotLight (GLdouble x,    GLdouble y,    GLdouble z,
                GLdouble dx,   GLdouble dy,   GLdouble dz,
                GLdouble r,    GLdouble g,    GLdouble b,
                GLdouble att0, GLdouble att1, GLdouble att2,
                GLdouble exp,  GLdouble cut,  GLenum light)
{
  GLfloat pos   [4];
  GLfloat dir   [3];
  GLfloat color [4];

  pos   [0] = (GLfloat) x;
  pos   [1] = (GLfloat) y;
  pos   [2] = (GLfloat) z;
  pos   [3] = (GLfloat) 1.0;
  dir   [0] = (GLfloat) dx;
  dir   [1] = (GLfloat) dy;
  dir   [2] = (GLfloat) dz;
  color [0] = (GLfloat) r;
  color [1] = (GLfloat) g;
  color [2] = (GLfloat) b;
  color [3] = (GLfloat) 0.0;

  glEnable  (GL_LIGHTING);
  glEnable  (light);
  glLightfv (light, GL_POSITION,              pos);
  glLightfv (light, GL_DIFFUSE,               color);
  glLightfv (light, GL_SPECULAR,              color);
  glLightfv (light, GL_SPOT_DIRECTION,        dir);
  glLightf  (light, GL_SPOT_CUTOFF,           (GLfloat) cut);
  glLightf  (light, GL_SPOT_EXPONENT,         (GLfloat) exp);
  glLightf  (light, GL_CONSTANT_ATTENUATION,  (GLfloat) att0);
  glLightf  (light, GL_LINEAR_ATTENUATION,    (GLfloat) att1);
  glLightf  (light, GL_QUADRATIC_ATTENUATION, (GLfloat) att2);
}





void handle_window_events (struct Window *window)
{
  struct IntuiMessage *msg;
  int                  done = 0;

  while (!done)
  {
    Wait (1L << window->UserPort->mp_SigBit);
    while ((!done) && (msg = (struct IntuiMessage *) GetMsg (window->UserPort)))
    {
      switch (msg->Class)
      {
        case IDCMP_CLOSEWINDOW:
          done = 1;
          break;
      }
      ReplyMsg ((struct Message *) msg);
    }
  }
}





void main (int argc, char *argv [])
{
  void    *window;
  GLubyte *texture;
  GLfloat  color [4] = {1.0f, 1.0f, 1.0f, 0.0f};
  GLdouble factor = 1.0;
  GLint    linear = 0;

  if (argc < 2) return;

  if (atoi (argv [1]) == 1)
  {
    texture = loadTexture4 ();
  }
  else
  {
    texture = loadTexture256 ();
  }
  if (argc > 2)
  {
    sscanf (argv [2], "%lf", &factor);
  }
  if ((argc > 3) && (*argv [3] == 'l'))
  {
    linear = 1;
  }

  window = openGLWindowTags (WIDTH, HEIGHT, GLWA_Title, "tex_test",
                                            GLWA_IDCMP, IDCMP_CLOSEWINDOW,
                                            GLWA_CloseGadget, TRUE,
                                            GLWA_DepthGadget, TRUE,
                                            GLWA_DragBar,     TRUE,
                                            GLWA_Activate, TRUE,
                                            GLWA_RGBAMode, GL_TRUE,
                                            TAG_DONE);

  if (!window) return;

  glEnable         (GL_DITHER);
  glShadeModel     (GL_SMOOTH);
  glLightModeli    (GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
  glDepthFunc      (GL_LESS);
  glEnable         (GL_DEPTH_TEST);

  glClearColor     ((GLfloat) 0.3, (GLfloat) 0.3, (GLfloat) 0.3, (GLfloat) 1.0);
  glClearDepth     (1.0);
  glClear          (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glMatrixMode     (GL_TEXTURE);
  glRotated        (0.0, 0.0, 0.0, 1.0);
  glMatrixMode     (GL_PROJECTION);
  glPerspective    (40.0, 1.333, 0.5, 50.5);
  glMatrixMode     (GL_MODELVIEW);


#ifndef GL_APICOMPATIBLE
    {
     GLlookAt lookat;

     lookat.eyex    = 4.0;
     lookat.eyey    = 12.0;
     lookat.eyez    = 20.0;
     lookat.centerx = 0.0;
     lookat.centery = 0.0;
     lookat.centerz = 0.0;
     lookat.upx     = 0.0;
     lookat.upy     = 1.0;
     lookat.upz     = 0.0;
     glLookAt (&lookat);
    }
#else
  glLookAt         (4.0,  12.0, 20.0,   0.0, 0.0, 0.0,   0.0, 1.0, 0.0);
#endif

  glPixelStorei    (GL_UNPACK_ALIGNMENT, 1);
  if (atoi (argv [1]) == 1)
  {
    glPixelMapusv    (GL_PIXEL_MAP_I_TO_R, 4, rMap4);
    glPixelMapusv    (GL_PIXEL_MAP_I_TO_G, 4, gMap4);
    glPixelMapusv    (GL_PIXEL_MAP_I_TO_B, 4, bMap4);
    glTexImage2D   (GL_TEXTURE_2D, 0, 3, 128, 128, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, texture);
  }
  else
  {
    glPixelMapusv    (GL_PIXEL_MAP_I_TO_R, 256, rMap256);
    glPixelMapusv    (GL_PIXEL_MAP_I_TO_G, 256, gMap256);
    glPixelMapusv    (GL_PIXEL_MAP_I_TO_B, 256, bMap256);
    glTexImage2D   (GL_TEXTURE_2D, 0, 3, 256, 256, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, texture);
  }
  glEnable         (GL_TEXTURE_2D);
  glTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
  if (linear)
  {
    glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  }
  else
  {
    glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  }
  glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexEnvfv       (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
  glTexEnvi        (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

  spotLight  (10.0, 10.0, 10.0,   -1.0, -1.0, -1.0,   1.0, 1.0, 1.0,  1.0, 0.0, 0.0,  15.0, 50.0, GL_LIGHT0);
  drawFloor  (20, 0.0, factor);

  handle_window_events (getWindow (window));

  closeGLWindow (window);

  free (texture);
}
