/*
**	$VER: cubes.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 <clib/exec_protos.h>

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


#define SHARED                  /* we use the cyber glshared 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    200
#define HEIGHT   150


GLubyte black;
GLubyte whiteA, whiteD, whiteS;
GLubyte blueA,  blueD,  blueS;
GLubyte cyanA,  cyanD,  cyanS;





GLvoid setIndexMat (GLint amb, GLint diff, GLint spec, GLint shine)
{
  GLint indices [3];

  indices [0] = amb;
  indices [1] = diff;
  indices [2] = spec;

  glMateriali  (GL_FRONT_AND_BACK, GL_SHININESS, shine);
  glMaterialiv (GL_FRONT_AND_BACK, GL_COLOR_INDEXES, indices);
}






void drawCube (void)
{
  glBegin (GL_QUADS);
    setIndexMat (whiteA, whiteD, whiteS, 100);
    glColor3d   ( 1.0,  1.0,  1.0);
    glNormal3d  ( 0.0,  0.0,  1.0);
    glEdgeFlag  (GL_TRUE);
    glVertex3d  (-0.5, -0.5,  0.5);
    glVertex3d  ( 0.5, -0.5,  0.5);
    glVertex3d  ( 0.5,  0.5,  0.5);
    glVertex3d  (-0.5,  0.5,  0.5);

    setIndexMat (blueA, blueD, blueS, 100);
    glColor3d   ( 0.0,  0.0,  1.0);
    glNormal3d  ( 1.0,  0.0,  0.0);
    glEdgeFlag  (GL_TRUE);
    glVertex3d  ( 0.5, -0.5,  0.5);
    glEdgeFlag  (GL_FALSE);
    glVertex3d  ( 0.5, -0.5, -0.5);
    glEdgeFlag  (GL_TRUE);
    glVertex3d  ( 0.5,  0.5, -0.5);
    glEdgeFlag  (GL_FALSE);
    glVertex3d  ( 0.5,  0.5,  0.5);

    setIndexMat (whiteA, whiteD, whiteS, 100);
    glColor3d   ( 1.0,  1.0,  1.0);
    glNormal3d  ( 0.0,  0.0, -1.0);
    glEdgeFlag  (GL_TRUE);
    glVertex3d  ( 0.5, -0.5, -0.5);
    glVertex3d  (-0.5, -0.5, -0.5);
    glVertex3d  (-0.5,  0.5, -0.5);
    glVertex3d  ( 0.5,  0.5, -0.5);

    setIndexMat (blueA, blueD, blueS, 100);
    glColor3d   ( 0.0,  0.0,  1.0);
    glNormal3d  (-1.0,  0.0,  0.0);
    glEdgeFlag  (GL_TRUE);
    glVertex3d  (-0.5, -0.5, -0.5);
    glEdgeFlag  (GL_FALSE);
    glVertex3d  (-0.5, -0.5,  0.5);
    glEdgeFlag  (GL_TRUE);
    glVertex3d  (-0.5,  0.5,  0.5);
    glEdgeFlag  (GL_FALSE);
    glVertex3d  (-0.5,  0.5, -0.5);

    setIndexMat (cyanA, cyanD, cyanS, 100);
    glColor3d   ( 0.0,  1.0,  1.0);
    glNormal3d  ( 0.0,  1.0,  0.0);
    glVertex3d  (-0.5,  0.5,  0.5);
    glVertex3d  ( 0.5,  0.5,  0.5);
    glVertex3d  ( 0.5,  0.5, -0.5);
    glVertex3d  (-0.5,  0.5, -0.5);

    setIndexMat (cyanA, cyanD, cyanS, 100);
    glColor3d   ( 0.0,  1.0,  1.0);
    glNormal3d  ( 0.0, -1.0,  0.0);
    glVertex3d  (-0.5, -0.5, -0.5);
    glVertex3d  ( 0.5, -0.5, -0.5);
    glVertex3d  ( 0.5, -0.5,  0.5);
    glVertex3d  (-0.5, -0.5,  0.5);
  glEnd ();
}





void drawCubeRing (void)
{
  int count;

  for (count = 0; count < 18; count++)
  {
    glPushMatrix ();
    glRotated (20.0 * count, 0.0, 1.0, 0.0);
    glTranslated (0.0, 0.0, -4.0);
    drawCube ();
    glPopMatrix ();
  }
}





void drawFloor (int patches, GLdouble height)
{
  GLdouble x, z;
  GLdouble dx, dz;

  dx = 20.0 / ((GLdouble) patches);
  dz = 20.0 / ((GLdouble) patches);

  for (z = -10.0; z < 10.0; z += dz)
  {
    glBegin (GL_QUAD_STRIP);
      setIndexMat (blueA, blueD, blueS, 50);
      glColor3d   (0.0, 0.0, 1.0);
      glNormal3d  (0.0, 1.0, 0.0);
      for (x = -10.0; x <= 10.0; x += dx)
      {
        glEdgeFlag (GL_TRUE);
        glVertex3d (x, height, z);
        glEdgeFlag (GL_FALSE);
        glVertex3d (x, height, z + dz);
      }
    glEnd ();
  }
}





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 drawScene (void)
{
  GLint count;

  glPushMatrix ();
  glTranslated (0.0, 2.4, 0.0);
  for (count = 0; count < 4; count++)
  {
    drawCubeRing ();
    glTranslated (0.0, -1.2, 0.0);
  }
  glPopMatrix ();

  drawFloor (20, 0.0);
}





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

  window=getWindow(win);

  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;
        case IDCMP_NEWSIZE:
          resizeGLWindow   (win, window->GZZWidth, window->GZZHeight);
          glClear          (GL_COLOR_BUFFER_BIT);
          drawScene();
          break;
      }
      ReplyMsg ((struct Message *) msg);
    }
  }
}





void main (int argc, char *argv[])
{
  void      *window;
  GLboolean  RGBA  = GL_TRUE;

  if (argc > 1)
  {
    RGBA = (GLboolean) atoi (argv [1]);
  }

  printf ("Opening window in %smode.\n", RGBA ? "RGBA-" : "Color-Index-");

  window  = openGLWindowTags (WIDTH, HEIGHT,    GLWA_Title, "Cubes",
                                                GLWA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_NEWSIZE,
                                                GLWA_CloseGadget, TRUE,
                                                GLWA_DepthGadget, TRUE,
                                                GLWA_DragBar,     TRUE,
                                                GLWA_Activate, TRUE,
                                                GLWA_RGBAMode, RGBA,
                                                GLWA_SizeGadget, TRUE,
                                                GLWA_MaxWidth, 1280,
                                                GLWA_MaxHeight, 1024,
                                                TAG_DONE);
  if (window)
  {
    if (!RGBA)
    {
      black  = allocColor (window,   0,   0,   0);

      whiteA  = allocColorRange (window, 40, 40, 40,  255, 255, 255, 20);
      whiteD  = allocColorRange (window, 255, 255, 255,  255, 255, 255, 10);
      whiteS  = whiteD + 9;

      blueA  = allocColorRange (window, 40, 40, 40,  0, 0, 255, 20);
      blueD  = allocColorRange (window, 0, 0, 255,  255, 255, 255, 10);
      blueS  = blueD + 9;

      cyanA  = allocColorRange (window, 40, 40, 40,  0, 255, 255, 20);
      cyanD  = allocColorRange (window, 0, 255, 255,  255, 255, 255, 10);
      cyanS  = cyanD + 9;
    }
    glColorMaterial  (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glEnable         (GL_COLOR_MATERIAL);
    glCullFace       (GL_BACK);
    glEnable         (GL_CULL_FACE);
    glShadeModel     (GL_SMOOTH);
    glEnable         (GL_DEPTH_TEST);
    glMaterialf      (GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat) 50.0);
    glLightModeli    (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
    glClearIndex     ((GLfloat) black);
    glClear          (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    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    = 6.0;
    lookat.eyez    = 15.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, 6.0, 15.0,   0.0, 0.0, 0.0,   0.0, 1.0, 0.0);
#endif
    spotLight (15.0, 15.0, 15.0,   -1.0, -1.0, -1.0,   1.0, 1.0, 1.0,   1.0, 0.0, 0.0,   50.0, 90.0, GL_LIGHT0);

    drawScene ();

    handle_window_events (window);

    closeGLWindow (window);
  }

}
