/*      This is the template of a CAVE program
 *           using the "CAVE TooLs" calls
 *
 *                         written by
 *                      Jim Costigan
 *    Electronic Visualization Laboratory,
 *     University of Illinois at Chicago
 *               costigan@evl.uic.edu
 *
 *              Last modified 7/09/97
 *
 *      Notations are included within the code
 */
 
 
//stock includes
 
#include <cave_ogl.h>
#include <malloc.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <iostream.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>

//includes necessary for CAVE TooLs

#include "slider.h"
#include "knob.h"
#include "button.h"

// Global Variables and #defines

#define SPEED 5.0f  // Max navigation speed in feet per second

//create pointers to the classes Slider, Knob and Button

Slider *Green;
Slider *Red;
Slider *Blue;
Slider *Size;
Knob *Detail;
Button *Shading;

GLuint shiny_material=11;

// Fuinction definitions
void navigate(void);
void init_gl(void);
void draw_it (void);
void calculate(void);
void floor (void);
void Sphere (void);
void lighting (void);
void Lables (void);
void Dot (void);

//main stolen from the one ane only Dave Pape's example program

 main(int argc, char **argv)
{
// Initialize the CAVE
 CAVEConfigure(&argc,argv,NULL);
 
 // You can create sliders anywhere,
 // Arguments are ( X position, Y position, Z position, Trigger distance)
 // or ( X position, Y position, Z position )
 // Trigger distance is how far away the trigger function will work in feet
 // the default is 15 feet
 
        Red = new Slider (2.0,  2.0,  -2.0);
        Green = new Slider (2.5,  2.0,  -2.0);
        Blue = new Slider (3.0, 2.0,  -2.0);
        Size = new Slider (3.5,  2.0,  -2.0);
        Detail= new Knob (4.0,  2.0,  -2.0,  9.0);
        Shading= new Button (4.0,  1.6,  -1.7,  9.0);
 
        // Rotation is called and this is the only rotoation
        // that the intersection look up knows about
 
 
        Green->SliderRotate (45,  0 , 0);
        Red->SliderRotate (45,  0 , 0);
        Blue->SliderRotate (45,  0, 0);
        Size->SliderRotate (45,  0 , 0);
        Detail->KnobRotate (45,  0 , 0);
        Shading->ButtonRotate (45,  0 , 0);
 
        //You can change the button that activates the object
        // by calling selection button.  The numbers called correspond
        //  to the CAVEBUTTONS 2 is the default and 1 - 4 is valid
 
        Red->selection_button (1);
        Blue->selection_button (3);

       // You can set the initial starting position to
       // be any value betweeen 0 and 1
 
       Blue->set_start(.75);
       Detail->set_start(.50);
 

     //  You can preset the value of a button to be 1
 
       Shading->set_value (1);

 
 
 CAVEInit();
 CAVEInitApplication(lighting, 0);
 CAVEDisplay(draw_it,0);
 while (!CAVEgetbutton(CAVE_ESCKEY))
        {
        navigate();
        calculate();
        sginap(1);
        }
        cout << " \n Wasn't that fun!!! \n \n";
 
 
        CAVEExit();
}

 
 //  Standard Navigation
 void navigate(void)
{
 float jx=CAVE_JOYSTICK_X,jy=CAVE_JOYSTICK_Y,dt,t;
 static float prevtime = 0;
 t = CAVEGetTime();
 dt = t - prevtime;
 prevtime = t;
 if (fabs(jy)>0.2)
        {
        float wandFront[3];
        CAVEGetVector(CAVE_WAND_FRONT,wandFront);
        CAVENavTranslate(wandFront[0]*jy*SPEED*dt, wandFront[1]*jy*SPEED*dt,
                        wandFront[2]*jy*SPEED*dt);
        }
 if (fabs(jx)>0.2)
        CAVENavRot(-jx*90.0f*dt,'y');
}

void draw_it()
 {
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
        // The only part of the class that should NOT be drawn
        //       in world coordinates is the pointer,
        //          which is attached to the wand
 
 
         glPushMatrix();
           Red->Pointer();
        glPopMatrix();
 
 
        // All of the button's knobs and sliders should be drawn in
        // world coordinates, (inside the CAVENavTransform)
    
        glPushMatrix();
        CAVENavTransform();
        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);
 
 
 
         glPushMatrix();
            Green->draw();
            Red->draw();
            Blue->draw();
            Size->draw();
            Detail->face_plate();
            Detail->draw();
           Shading->draw();
          glPopMatrix();
 
         // The value's of knob's and sliders are from 0 to 1
         // and can be called anywhere.  If value()  is not called
         //  the object will not be checked for intersection &
         // no bounding sphere will be drawn
 
                glPushMatrix();
                        //glEnable(GL_LIGHTING);
                        glTranslatef (0,  2,  -8 );
                        glColor3f (Red->value(), Green->value(),Blue->value());
 
                        if (Shading->value()){
                                                glEnable(GL_LIGHTING);
                                             glCallList(shiny_material);
                                             }
 
                        Sphere();
 
                         Lables (); //makes the lables for the sliders
                glPopMatrix();
 
                glPushMatrix();
                                glDisable(GL_LIGHTING);
                                floor ();
                                glEnable(GL_LIGHTING);
                glPopMatrix();
glPopMatrix();

        glDisable(GL_LIGHTING);
 
 }

void calculate ()
        {
 
 
 
                                }
 
 
//
//  The rest of this code creates the sphere and dot's that are used in the environment
//  environment.  No slider, knob or button calls happen below.
//
 
 
 

void Sphere (void)
        {
        float surface;
         GLUquadricObj* qobj = gluNewQuadric();
        gluQuadricNormals(qobj,  GLU_SMOOTH);
        surface = Detail->value()*200 + 10;
        glPushMatrix();
                gluSphere(qobj, ( Size->value()* 4 +1),  surface , surface);
                glPopMatrix();
        glPopMatrix();
        }
 
void Lables (void){

 
                glPushMatrix();
                        glDisable(GL_LIGHTING);
                        glColor3f(0.9,  0.0,  0.0);
                        glTranslatef(2,  2.73333,  -2.6);
                        Dot();
                glPopMatrix();
                glPushMatrix();
                        glColor3f(0.0,  1.0,  0.0);
                        glTranslatef(2.5,  2.73333,  -2.6);
                        Dot();
                glPopMatrix();
                glPushMatrix();
                        glColor3f(0.0,  0.0,  0.9);
                        glTranslatef(3.0,  2.73333,  -2.6);
                        Dot();
                glPopMatrix();
                glPushMatrix();
                        glColor3f(0.25,  0.25,  0.25);
                        glTranslatef(3.4,  2.73333,  -2.6);
                        glScalef(0.75, 0.75, 0.75);
                        Dot();
                glPopMatrix();
                glPushMatrix();
                        glColor3f(0.26,  0.26,  0.26);
                        glTranslatef(3.55, 2.73333,  -2.6);
                        glScalef(1.5, 1.5, 1.5);
                        Dot();
                glPopMatrix();
                glEnable(GL_LIGHTING);
}
 
 
void Dot (void)
        {
         GLUquadricObj* qobj = gluNewQuadric();
                gluSphere(qobj, 0.05,  6,  6);
   }
 
void floor (void)
        {
        glPushMatrix();
                        glDisable(GL_LIGHTING);
                        glColor3f(0.4,  0.4,  0.4);
                        glTranslatef (0,  -13,  0 );
                        glRotatef(90,  1.0,  0.0,  0.0);
                                glRectf(-100,-100,  100, 100);
                           glEnable(GL_LIGHTING);
        glPopMatrix();
        }

void lighting (void)
        {
                GLfloat matnomat[]={0.0, 0.0, 0.0, 1.0};
                GLfloat matspec[]={1.0, 1.0, 1.0, 1.};
 
                //shiny lighting
           glNewList(shiny_material,GL_COMPILE);
 
                        glMaterialfv(GL_FRONT, GL_AMBIENT, matnomat);
                        glMaterialfv(GL_FRONT, GL_SPECULAR, matspec);
                        glMaterialf(GL_FRONT, GL_SHININESS,  100.);
                        glMaterialfv(GL_FRONT, GL_EMISSION, matnomat);
                        glColorMaterial(GL_FRONT, GL_DIFFUSE);
                        glEnable(GL_COLOR_MATERIAL);
                glEndList();
 
}