/*
**	$VER: cubes_flat.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 cyberglshared 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    400
#define HEIGHT   300





void drawCube (void)
{
  glBegin (GL_QUADS);
    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);

    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);

    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);

    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);

    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);

    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);
    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 (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   diff[]   = {  1.0,    0.7,   0.1,   1.0};
  GLfloat   spec[]   = {  1.0,    0.9,   0.4,   1.0};

  window  = openGLWindowTags (WIDTH, HEIGHT, GLWA_Title, "Flat Cubes",
                                             GLWA_IDCMP, IDCMP_CLOSEWINDOW,
                                             GLWA_CloseGadget, TRUE,
                                             GLWA_DepthGadget, TRUE,
                                             GLWA_DragBar,     TRUE,
                                             GLWA_Activate, TRUE,
                                             GLWA_RGBAMode, GL_TRUE,
                                             TAG_DONE);
  if (window)
  {
    glColorMaterial  (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    glEnable         (GL_COLOR_MATERIAL);
    glCullFace       (GL_BACK);
    glEnable         (GL_CULL_FACE);
    glShadeModel     (GL_FLAT);
    glEnable         (GL_DEPTH_TEST);
    glMaterialf      (GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat) 100.0);
    glMaterialfv     (GL_FRONT_AND_BACK, GL_DIFFUSE,  diff);
    glMaterialfv     (GL_FRONT_AND_BACK, GL_SPECULAR, spec);
    glLightModeli    (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
    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 (10.0, 10.0, 10.0,   -1.0, -1.0, -1.0,   1.0, 1.0, 1.0,   1.0, 0.0, 0.0,   60.0, 90.0, GL_LIGHT0);
    drawScene ();

    handle_window_events (getWindow (window));

    closeGLWindow (window);
  }
}
