//Oscar Gendrop Espinosa
// RenderWorld.c
// This file actually renders the world

#include <windows.h> // Normal Windows stuff
#include <math.h>
#include <gl/gl.h>  // Core OpenGL functions
#include <gl/glu.h>  // OpenGL Utility functions
#include <gl/glaux.h>

#include "externs.h" // Data shared between files
#include "glutils.h" // Utilities for this application
 

// Prevent anoying compiler warnings - only used locally
#define fsin(x) (float)sin(x)
#define fcos(x) (float)cos(x)

// Useful structure for storing coordinates of objects. We declare
// an array of these to hold the positions of the various types of objects
struct COORD
 {
 float x;
 float z;
 };
 

// Maximum number of each type of object
#define MAX_EACH 15

// Arrays of objects
struct COORD Pyramids[MAX_EACH];
struct COORD Trees[MAX_EACH];
struct COORD Slabs[MAX_EACH];
struct COORD Pillers[MAX_EACH];
struct COORD Fly[MAX_EACH];
 
 

void RandomizePositions(void);
float RandomPos(void);
void PlaceTress(void);
void PlacePyramids(void);
void PlaceSlabs(void);
void PlacePillers(void);
//void PlaceBoxes(void);
void DrawGround(void);
//void DrawBox(void);

///////////////////////////////////////////////////////////////////////////////
// Pick a random value between -1000.0 and 1000.0
float RandomPos(void)
 {
 double dRet = 0.0f;

 dRet = (double)rand();   // between 0 and RAND_MAX
 dRet = dRet/(double)RAND_MAX; // between 0 and 1.0
 dRet *= 2000.0f;    // between 0 and 2000
 dRet -= 1000.0f;    // between -1000 and 1000

 return (float)dRet;
 }
 
 

///////////////////////////////////////////////////////////////////////////////
// Position the objects in the scene
void RandomizePositions()
 {
 int i;

 // Pick two random values for x and z coordinates
 for(i = 0; i < MAX_EACH; i++)
  {
  Pyramids[i].x = RandomPos();
  Pyramids[i].z = RandomPos();

  Slabs[i].x = RandomPos();
  Slabs[i].z = RandomPos();

  Pillers[i].x = RandomPos();
  Pillers[i].z = RandomPos();

  Fly[i].x = RandomPos();
  Fly[i].z = RandomPos();

  Trees[i].x = RandomPos();
  Trees[i].z = RandomPos();
  }
 
 }
 

////////////////////////////////////////////////////////////////////////////////
// Put the Pyramids in place Draws each one individually
void PlacePyramids(void)
 {
 int i;

 for(i = 0; i < MAX_EACH; i++)
  {
  glPushMatrix();
   glTranslatef(Pyramids[i].x, 0.0f, Pyramids[i].z);
   DrawPyramid();
 
  glPopMatrix();
  }
 }
////////////////////////////////////////////////////////////////////////////////
// Put the tress in place Draws each one individually
void PlaceTrees(void)
 {
 int i;

 for(i = 0; i < 45; i++)
  {
  glPushMatrix();
   glTranslatef(Trees[i].x, 0.0f, Trees[i].z);
   DrawTree();
  glPopMatrix();
  }
 }
 
 
 

///////////////////////////////////////////////////////////////////////////////
// Put the slabs in place
void PlaceSlabs(void)
 {
 int i;

 // Loop through, and place each one
 for(i = 0; i < MAX_EACH; i++)
  {
  glPushMatrix();
   glTranslatef(Slabs[i].x, 21.0f, Slabs[i].z);
   DrawSlab();
  glPopMatrix();
  }
 }
 
 

////////////////////////////////////////////////////////////////////////////////
// Put the Pillers in place
void PlacePillers(void)
 {
 int i;
 // Place each Piller
 for(i = 0; i < MAX_EACH; i++)
  {
  glPushMatrix();
   glTranslatef(Pillers[i].x, 23.5f, Pillers[i].z);
   DrawPiller();
  glPopMatrix();
  }
 }

////////////////////////////////////////////////////////////////////////////////
// Put the Boxess in place
/*void PlaceBoxes(void)
 {
 int i;
 // Place each Box
 for(i = 0; i < MAX_EACH; i++)
  {
  glPushMatrix();
   glTranslatef(Fly[i].x, 0.00f, Fly[i].z);
   DrawBox();
  glPopMatrix();
  }
 }
*/

////////////////////////////////////////////////////////////////////////////////
// Render the entire scene
void RenderWorld(void)
 {

 glCallList(nWorldList);

 // Pillers not place in display list because of auxSolidBox problems
 PlacePillers();
// PlaceBoxes();
 PlaceTrees();
 DrawGround();

 }
 

/////////////////////////////////////////////////////////////////////////////
/// Objects contained in the scene
 

/////////////////////////////////////////////////////////////////////////////////
 

// Draw the ground just as a grid of lines. No transformation to take place
void DrawGround(void)
 {
 int r,c;
 int nStep = 1;

 // Draw Ground in Green
 glRGB(0,255,0);

 // The ground has a normal too
 
 // Just draw a bunch of horizontal and vertical lines
 glColor3f(0,255,0);
 glBegin(GL_LINES);

 for(r = -1000; r  <= 1000; r += nStep)
  {
  glVertex3f((float)r, 0.0f, -1000.0f);
  glVertex3f((float)r, 0.0f, 1000.0f);
  }

 for(c = -1000; c <= 1000; c += nStep)
  {
  glVertex3f(1000.0f, 0.0f, (float)c);
  glVertex3f(-1000.0f, 0.0f, (float)c);
  }
 
 

 glEnd();

 
 }
////////////////////////////////////////////////////////////////////////////
// A Tree
void DrawTree()
 {
 GLfloat vNormal[3];

 GLfloat x,z,angle;  // Storage for coordinates and angles
 GLfloat fStep = (float)PI/4.0f;

 GLfloat fHeight = 20.0f;
 GLfloat fRadius = 4.0f;
 glTranslatef(0, 6.0f, 0);

 //brown
 glRGB(139,101,8);

 // Normals are easy for cylinders
 glBegin(GL_QUAD_STRIP);
  vNormal[0] = fRadius;
  vNormal[1] = fHeight;
  vNormal[2] = 0.0f;
  ReduceToUnit(vNormal);

  glNormal3fv(vNormal);
  glVertex3f(fRadius, fHeight/3, 0.0f);
  glVertex3f(fRadius, -fHeight/3, 0.0f);

 for(angle = fStep; angle < 3.0f*PI; angle += fStep)
  {
  x = fRadius*fsin(angle);
  z = fRadius*fcos(angle);

  vNormal[0] = x;
  vNormal[1] = fHeight;
  vNormal[2] = z;
  ReduceToUnit(vNormal);

  glNormal3fv(vNormal);
  glVertex3f(x, fHeight/3, z );
  glVertex3f(x, -fHeight/3, z);

  }

 glEnd();
 // Draw the cone s
 glPushMatrix();
 glTranslatef(0.0f, 2.0, 0.0f);
 glRotatef(-90.0f,1.0f,0.0f,0.0f);
 glRGB(0,230,0);
 auxSolidCone(12.0f,16.0f);
     glTranslatef(0.0f, 0.0, 12.0f);
 auxSolidCone(6.0f,8.0f);
 glPopMatrix();

 
 
 

}
/////////////////////////////////////////////////////////////////////////////////////
// A Piller or column
void DrawPiller()
 {
 GLfloat vNormal[3];

 GLfloat x,z,angle;  // Storage for coordinates and angles
 GLfloat fStep = (float)PI/4.0f;

 GLfloat fHeight = 20.0f;
 GLfloat fRadius = 7.0f;

 // Grey
 glRGB(128,128,128);

 // Normals are easy for cylinders
 glBegin(GL_QUAD_STRIP);
  vNormal[0] = fRadius;
  vNormal[1] = fHeight;
  vNormal[2] = 0.0f;
  ReduceToUnit(vNormal);

  glNormal3fv(vNormal);
  glVertex3f(fRadius, fHeight, 0.0f);
  glVertex3f(fRadius, -fHeight, 0.0f);

 for(angle = fStep; angle < 3.0f*PI; angle += fStep)
  {
  x = fRadius*fsin(angle);
  z = fRadius*fcos(angle);

  vNormal[0] = x;
  vNormal[1] = fHeight;
  vNormal[2] = z;
  ReduceToUnit(vNormal);

  glNormal3fv(vNormal);
  glVertex3f(x, fHeight, z );
  glVertex3f(x, -fHeight, z);
  }

 glEnd();

 // Draw the box at both ends
 glPushMatrix();
 glTranslatef(0.0f, -fHeight-(fRadius/4), 0.0f);
 auxSolidBox(fRadius*2.5, fRadius/2, fRadius*2.5);
 glTranslatef(0.0f, (fHeight+(fRadius/4))*2, 0.0f);
 auxSolidBox(fRadius*2.5, fRadius/2, fRadius*2.5);
 glPopMatrix();
 }
 

///////////////////////////////////////////////////////////////////////////////
// Draw a pyramid
void DrawPyramid(void)
 {
 GLfloat vNormal[3];
 GLfloat vvVertices[3][3];

 GLfloat fWidth = 15.0f;
 GLfloat fHeight = 30.0f;
 

 // Red Pyramids
 glRGB(255,0,0);
 

 // Simple, build with four triangles.
 glBegin(GL_TRIANGLES);
  vvVertices[0][0] = fWidth;
  vvVertices[0][1] = 0.0f;
  vvVertices[0][2] = fWidth;

  vvVertices[1][0] = fWidth;
  vvVertices[1][1] = 0.0f;
  vvVertices[1][2] = -fWidth;

  vvVertices[0][0] = 0.0f;
  vvVertices[0][1] = fHeight;
  vvVertices[0][2] = 0.0f;
  calcNormal(vvVertices, vNormal);
 
  glNormal3fv(vNormal);
  glVertex3f(fWidth, 0.0f, fWidth);
  glVertex3f(fWidth, 0.0f, -fWidth);
  glVertex3f(0.0f, fHeight, 0.0f);
 

  vvVertices[0][0] = fWidth;
  vvVertices[0][1] = 0.0f;
  vvVertices[0][2] = fWidth;

  vvVertices[1][0] = 0.0f;
  vvVertices[1][1] = fHeight;
  vvVertices[1][2] = 0.0f;

  vvVertices[0][0] = -fWidth;
  vvVertices[0][1] = 0.0f;
  vvVertices[0][2] = fWidth;
  calcNormal(vvVertices, vNormal);

  glNormal3fv(vNormal);
  glVertex3f(fWidth, 0.0f, fWidth);
  glVertex3f(0.0f, fHeight, 0.0f);
  glVertex3f(-fWidth, 0.0f, fWidth);

  vvVertices[0][0] = -fWidth;
  vvVertices[0][1] = 0.0f;
  vvVertices[0][2] = fWidth;

  vvVertices[1][0] = 0.0f;
  vvVertices[1][1] = fHeight;
  vvVertices[1][2] = 0.0f;

  vvVertices[0][0] = -fWidth;
  vvVertices[0][1] = 0.0f;
  vvVertices[0][2] = -fWidth;
  calcNormal(vvVertices, vNormal);

  glNormal3fv(vNormal);
  glVertex3f(-fWidth, 0.0f, fWidth);
  glVertex3f(0.0f, fHeight, 0.0f);
  glVertex3f(-fWidth, 0.0f, -fWidth);
 

  vvVertices[0][0] = -fWidth;
  vvVertices[0][1] = 0.0f;
  vvVertices[0][2] = -fWidth;

  vvVertices[1][0] = 0.0f;
  vvVertices[1][1] = fHeight;
  vvVertices[1][2] = 0.0f;

  vvVertices[0][0] = fWidth;
  vvVertices[0][1] = 0.0f;
  vvVertices[0][2] = -fWidth;
  calcNormal(vvVertices, vNormal);

  glNormal3fv(vNormal);
  glVertex3f(-fWidth, 0.0f, -fWidth);
  glVertex3f(0.0f, fHeight, 0.0f);
  glVertex3f(fWidth, 0.0f, -fWidth);
 glEnd();
 }
 

///////////////////////////////////////////////////////////////////////////////
// Draw the Slabs
void DrawSlab()
 {
 GLfloat fWidth = 12.0f;
 GLfloat fHeight = 20.0f;
 GLfloat fDepth = 7.0f;
 GLfloat fEdge = 1.0f;
 GLfloat vNormal[3];
 GLfloat vvVertices[3][3];

 // Blue Slabs
 glRGB(0,0, 255);

 // Simple, build with four triangles.
 glBegin(GL_QUADS);
  // Front
  glNormal3f(0.0f, 0.0f, -1.0f);
  glVertex3f(fWidth, fHeight, -fDepth);
  glVertex3f(fWidth, -fHeight, -fDepth);
  glVertex3f(-fWidth, -fHeight, -fDepth);
  glVertex3f(-fWidth, fHeight, -fDepth);

  // Back
  glNormal3f(0.0f, 0.0f, 1.0f);
  glVertex3f(-fWidth, fHeight, fDepth);
  glVertex3f(-fWidth, -fHeight, fDepth);
  glVertex3f(fWidth, -fHeight, fDepth);
  glVertex3f(fWidth, fHeight, fDepth);

  // Top
  glNormal3f(0.0f, 1.0f, 0.0f);
  glVertex3f(fWidth-fEdge, fHeight+fEdge, fDepth-fEdge);
  glVertex3f(fWidth-fEdge, fHeight+fEdge, -(fDepth-fEdge));
  glVertex3f(-(fWidth-fEdge), fHeight+fEdge, -(fDepth-fEdge));
  glVertex3f(-(fWidth-fEdge), fHeight+fEdge, fDepth-fEdge);

  // Bottom
  glNormal3f(0.0f, -1.0f, 0.0f);
  glVertex3f(-(fWidth-fEdge), -(fHeight+fEdge), fDepth-fEdge);
  glVertex3f(-(fWidth-fEdge), -(fHeight+fEdge), -(fDepth-fEdge));
  glVertex3f(fWidth-fEdge, -(fHeight+fEdge), -(fDepth-fEdge));
  glVertex3f(fWidth-fEdge, -(fHeight+fEdge), fDepth-fEdge);

  // Left
  glNormal3f(1.0f, 0.0f, 0.0f);
  glVertex3f(fWidth, fHeight, fDepth);
  glVertex3f(fWidth, -fHeight, fDepth);
  glVertex3f(fWidth, -fHeight, -fDepth);
  glVertex3f(fWidth, fHeight, -fDepth);

  // Right
  glNormal3f(-1.0f, 0.0f, 0.0f);
  glVertex3f(-fWidth, fHeight, fDepth);
  glVertex3f(-fWidth, fHeight, -fDepth);
  glVertex3f(-fWidth, -fHeight, -fDepth);
  glVertex3f(-fWidth, -fHeight, fDepth);

  // Top Bevels
  vvVertices[0][0] = fWidth-fEdge;
  vvVertices[0][1] = fHeight+fEdge;
  vvVertices[0][2] = fDepth-fEdge;

  vvVertices[1][0] = -(fWidth-fEdge);
  vvVertices[1][1] = fHeight+fEdge;
  vvVertices[1][2] = fDepth-fEdge;

  vvVertices[2][0] = -fWidth;
  vvVertices[2][1] = fHeight;
  vvVertices[2][2] = fDepth;
  calcNormal(vvVertices,vNormal);

  glNormal3fv(vNormal);
  glVertex3f(fWidth-fEdge, fHeight+fEdge, fDepth-fEdge);
  glVertex3f(-(fWidth-fEdge), fHeight+fEdge, fDepth-fEdge);
  glVertex3f(-fWidth, fHeight, fDepth);
  glVertex3f(fWidth, fHeight, fDepth);
 

  vvVertices[0][0] = fWidth;
  vvVertices[0][1] = fHeight;
  vvVertices[0][2] = -fDepth;

  vvVertices[1][0] = fWidth-fEdge;
  vvVertices[1][1] = fHeight+fEdge;
  vvVertices[1][2] = -(fDepth-fEdge);

  vvVertices[2][0] = fWidth-fEdge;
  vvVertices[2][1] = fHeight+fEdge;
  vvVertices[2][2] = fDepth-fEdge;
  calcNormal(vvVertices,vNormal);

  glNormal3fv(vNormal);
  glVertex3f(fWidth, fHeight, -fDepth);
  glVertex3f(fWidth-fEdge, fHeight+fEdge, -(fDepth-fEdge));
  glVertex3f(fWidth-fEdge, fHeight+fEdge, fDepth-fEdge);
  glVertex3f(fWidth, fHeight, fDepth);

  vvVertices[0][0] = fWidth;
  vvVertices[0][1] = fHeight;
  vvVertices[0][2] = -fDepth;

  vvVertices[1][0] = -fWidth;
  vvVertices[1][1] = fHeight;
  vvVertices[1][2] = -fDepth;

  vvVertices[2][0] = -(fWidth-fEdge);
  vvVertices[2][1] = fHeight+fEdge;
  vvVertices[2][2] = -(fDepth-fEdge);
  calcNormal(vvVertices,vNormal);

  glNormal3fv(vNormal);
  glVertex3f(fWidth, fHeight, -fDepth);
  glVertex3f(-fWidth, fHeight, -fDepth);
  glVertex3f(-(fWidth-fEdge), fHeight+fEdge, -(fDepth-fEdge));
  glVertex3f(fWidth-fEdge, fHeight+fEdge, -(fDepth-fEdge));
 

  vvVertices[0][0] = -fWidth;
  vvVertices[0][1] = fHeight;
  vvVertices[0][2] = fDepth;

  vvVertices[1][0] = -(fWidth-fEdge);
  vvVertices[1][1] = fHeight+fEdge;
  vvVertices[1][2] = fDepth-fEdge;

  vvVertices[2][0] = -(fWidth-fEdge);
  vvVertices[2][1] = fHeight+fEdge;
  vvVertices[2][2] = -(fDepth-fEdge);
  calcNormal(vvVertices,vNormal);

  glNormal3fv(vNormal);
  glVertex3f(-fWidth, fHeight, fDepth);
  glVertex3f(-(fWidth-fEdge), fHeight+fEdge, fDepth-fEdge);
  glVertex3f(-(fWidth-fEdge), fHeight+fEdge, -(fDepth-fEdge));
  glVertex3f(-fWidth, fHeight, -fDepth);
 

  // Bottom Bevels
  vvVertices[0][0] = fWidth;
  vvVertices[0][1] = -fHeight;
  vvVertices[0][2] = fDepth;

  vvVertices[1][0] = -fWidth;
  vvVertices[1][1] = -fHeight;
  vvVertices[1][2] = fDepth;

  vvVertices[2][0] = -(fWidth-fEdge);
  vvVertices[2][1] = -(fHeight+fEdge);
  vvVertices[2][2] = fDepth-fEdge;
  calcNormal(vvVertices,vNormal);

  glNormal3fv(vNormal);
  glVertex3f(fWidth, -fHeight, fDepth);
  glVertex3f(-fWidth, -fHeight, fDepth);
  glVertex3f(-(fWidth-fEdge), -(fHeight+fEdge), fDepth-fEdge);
  glVertex3f(fWidth-fEdge, -(fHeight+fEdge), fDepth-fEdge);
 

  vvVertices[0][0] = fWidth;
  vvVertices[0][1] = -fHeight;
  vvVertices[0][2] = fDepth;

  vvVertices[1][0] = fWidth-fEdge;
  vvVertices[1][1] = -(fHeight+fEdge);
  vvVertices[1][2] = fDepth-fEdge;

  vvVertices[2][0] = fWidth-fEdge;
  vvVertices[2][1] = -(fHeight+fEdge);
  vvVertices[2][2] = -(fDepth-fEdge);
  calcNormal(vvVertices,vNormal);

  glNormal3fv(vNormal);
  glVertex3f(fWidth, -fHeight, fDepth);
  glVertex3f(fWidth-fEdge, -(fHeight+fEdge), fDepth-fEdge);
  glVertex3f(fWidth-fEdge, -(fHeight+fEdge), -(fDepth-fEdge));
  glVertex3f(fWidth, -fHeight, -fDepth);
 

  vvVertices[0][0] = fWidth-fEdge;
  vvVertices[0][1] = -(fHeight+fEdge);
  vvVertices[0][2] = -(fDepth-fEdge);

  vvVertices[1][0] = -(fWidth-fEdge);
  vvVertices[1][1] = -(fHeight+fEdge);
  vvVertices[1][2] = -(fDepth-fEdge);

  vvVertices[2][0] = -fWidth;
  vvVertices[2][1] = -fHeight;
  vvVertices[2][2] = -fDepth;
  calcNormal(vvVertices,vNormal);

  glNormal3fv(vNormal);
  glVertex3f(fWidth-fEdge, -(fHeight+fEdge), -(fDepth-fEdge));
  glVertex3f(-(fWidth-fEdge), -(fHeight+fEdge), -(fDepth-fEdge));
  glVertex3f(-fWidth, -fHeight, -fDepth);
  glVertex3f(fWidth, -fHeight, -fDepth);
 

  vvVertices[0][0] = -fWidth;
  vvVertices[0][1] = -fHeight;
  vvVertices[0][2] = -fDepth;

  vvVertices[1][0] = -(fWidth-fEdge);
  vvVertices[1][1] = -(fHeight+fEdge);
  vvVertices[1][2] = -(fDepth-fEdge);

  vvVertices[2][0] = -(fWidth-fEdge);
  vvVertices[2][1] = -(fHeight+fEdge);
  vvVertices[2][2] = fDepth-fEdge;
  calcNormal(vvVertices,vNormal);

  glNormal3fv(vNormal);
  glVertex3f(-fWidth, -fHeight, -fDepth);
  glVertex3f(-(fWidth-fEdge), -(fHeight+fEdge), -(fDepth-fEdge));
  glVertex3f(-(fWidth-fEdge), -(fHeight+fEdge), fDepth-fEdge);
  glVertex3f(-fWidth, -fHeight, fDepth);
 glEnd();
 }
 

///////////////////////////////////////////////////////////////////////////////
// This consists of just a box
/*void DrawBox(void)
 {
 // Position the box
 glPushMatrix();
 
  // Place and orient box
  glTranslatef(flyPos.xPos, 5.0f, flyPos.zPos);
  glRotatef(dRadToDeg(flyPos.radsFromEast+((float)PI/2.0f)), 0.0f, 1.0f, 0.0f);

  // Draw box
  glRGB(255,125,150);
  glPushMatrix();
   auxSolidBox(25.0f, 11.0f, 40.0f);
  glPopMatrix();

 glPopMatrix();
 }
 

*/