/*
**	$VER: tex_test2.c 1.1 (12.03.1998)
**
**	This is an example program for CyberGL
**
**      Written by Frank Gerberding
**
**	Copyright © 1996-1998 by phase5 digital products
**      All Rights reserved.
**
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.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/cybergl.h>
#include <proto/cybergl.h>

#ifdef SHARED
LONG __oslibversion   = 39L;
LONG __CGLlibversion = CYBERGLVERSION;
#endif



#define WIDTH    640
#define HEIGHT   480





void loadMipmaps (char *baseName, int maxLevel)
{
  FILE    *file;
  GLubyte *texture = NULL;
  int      level, size;
  char     name [100];

  if (texture = malloc ((1 << maxLevel) * (1 << maxLevel) * 3))
  {
    for (level = 0; level <= maxLevel; level++)
    {
      size = 1 << (maxLevel - level);
      sprintf (name, "PROGDIR:mipmaps/%s%c", baseName, (char) level + '0');
      printf ("%s\n", name);

      if (file = fopen (name, "r"))
      {
        fread (texture, size * size * 3, 1, file);
        glTexImage2D (GL_TEXTURE_2D, level, 3, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
        fclose (file);
      }
    }
    free (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;
  GLfloat  color [4] = {1.0f, 1.0f, 1.0f, 0.0f};
  GLdouble factor = 1.0;
  GLint    minFilter = 1, magFilter = 1;

  if (argc < 2) return;

  if (!(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))) return;

  glPixelStorei    (GL_UNPACK_ALIGNMENT, 1);
  loadMipmaps (argv [1], atoi (argv [2]));

  if (argc > 3)
  {
    sscanf (argv [3], "%lf", &factor);
  }
  if (argc > 4)
  {
    minFilter = atoi (argv [4]);
  }
  if (argc > 5)
  {
    magFilter = atoi (argv [5]);
  }
  printf ("factor = %lf, minFilter = %d, magFilter = %d\n", factor, minFilter, magFilter);

  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    = 1.0;
     lookat.eyey    = 2.0;
     lookat.eyez    = 10.0;
     lookat.centerx = 0.0;
     lookat.centery = 0.0;
     lookat.centerz = 5.0;
     lookat.upx     = 0.0;
     lookat.upy     = 1.0;
     lookat.upz     = 0.0;
     glLookAt (&lookat);
    }
#else
  glLookAt         (1.0, 2.0, 10.0,   0.0, 0.0, 5.0,  0.0, 1.0, 0.0);
#endif

  glEnable         (GL_TEXTURE_2D);
  glTexParameterfv (GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);

  switch (minFilter)
  {
    case 1: glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); break;
    case 2: glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); break;
    case 3: glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); break;
    case 4: glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); break;
    case 5: glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); break;
    case 6: glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); break;
  }
  switch (magFilter)
  {
    case 1: glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break;
    case 2: glTexParameteri  (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break;
  }
  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,   2.0, 2.0, 2.0,  1.0, 0.0, 0.0,  30.0, 50.0, GL_LIGHT0);
  drawFloor  (20, 0.0, factor);

  handle_window_events (getWindow (window));

  closeGLWindow (window);
}
