/* 
   Project: coevolutionary GP moto driving
   Dana Vrajitoru
   scenery.cc
   
   Functions to draw the scenery around the motorcycle.  
*/

#include <GL/glut.h>
#include <cmath>
#include <stdlib.h>
#include <iostream>

#include <GL/gl.h>	// Header File For The OpenGL32 Library
#include <GL/glu.h>	// Header File For The GLu32 Library
#include <stdio.h>      // Header file for standard file i/o.

#include <unistd.h>     // needed to sleep.

#include "gl_draw.h"
#include "scenery.h"
#include "point3f.h"

// Identity of the display list for the scenery part of the
// application.
GLuint scenery_id;
/* The number of our GLUT window */
int window; 

/* floats for x rotation, y rotation, z rotation */
float xrot, yrot, zrot;

/* storage for one texture  */
int texture[5];

/* Image type - contains height, width, and data */
struct Image {
    unsigned long sizeX;
    unsigned long sizeY;
    char *data;
};
typedef struct Image Image;

int ImageLoad(char *filename, Image *image);
void ReSizeGLScene(int Width, int Height);
void LoadGLTextures();
void InitGL(int Width, int Height);
void DrawGLScene();


// Creates the display list for the scenery.
void scenery_draw()
{
  scenery_id = glGenLists(1);
  LoadGLTextures();    
  //glEnable(GL_TEXTURE_2D);
  glNewList(scenery_id, GL_COMPILE);

  // Add all of the fix elements of the application here.
  //ground();
  //simple_road();
  start_mark();  
  DrawGLScene();   
  glEndList();
}

// Calls the display list for the scenery.
void scenery_display()
{
  glCallList(scenery_id);
  //DrawGLScene();
}

// Draws a red square for reference.
void ground()
{
  const GLfloat ground_r = 0.2, ground_g = 1.0, ground_b = 0.2;
  vector3f square_coord;
  square_coord.push_back(Point3f(-10, -0.01, -10)); 
  square_coord.push_back(Point3f(-10, -0.01, 10)); 
  square_coord.push_back(Point3f(10, -0.01, 10)); 
  square_coord.push_back(Point3f(10, -0.01, -10));
  Point3f normal(1, 0, 0);

  glColor3f(ground_r, ground_g, ground_b);
  gl_polygon(square_coord, normal);
}

// A very simple road for the motorcycle to be on.
void simple_road()
{
  const GLfloat road_r = 0.3, road_g = 0.3, road_b = 0.3;
  vector3f road_coord;
  road_coord.push_back(Point3f(-10, 0, -2.5)); 
  road_coord.push_back(Point3f(-10, 0, 2.5)); 
  road_coord.push_back(Point3f(10, 0, 2.5)); 
  road_coord.push_back(Point3f(10, 0, -2.5));
  Point3f normal(1, 0, 0);

  glColor3f(road_r, road_g, road_b);
  gl_polygon(road_coord, normal);
  
}

// Some mark for the begining of the circuit.
void start_mark()
{
  float lateral1=-12, lateral2=8.5, height = 8, radius=0.1;
  int prec=2;
  vector3f coords(2);
  glColor3f(0.7, 0.7, 0.9);
  coords[0][2] = lateral1;
  coords[1][2] = lateral1;
  coords[1][1] = height;
  Point3f top=coords[1];
  gl_cylinder_strip(coords, radius, prec);
  gl_sphere(coords[1][0], coords[1][1], coords[1][2], radius, prec);
  coords[0][2] = lateral2;
  coords[1][2] = lateral2;
  gl_cylinder_strip(coords, radius, 1);
  gl_sphere(coords[1][0], coords[1][1], coords[1][2], radius, prec);
  coords[0] = top;
  gl_cylinder_strip(coords, radius, 1);
  
 
}

// quick and dirty bitmap loader...for 24 bit bitmaps with 1 plane only.  
// See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/BMP.txt for more info.
int ImageLoad(char *filename, Image *image) {
    FILE *file;
    unsigned long size;                 // size of the image in bytes.
    unsigned long i;                    // standard counter.
    unsigned short int planes;          // number of planes in image (must be 1) 
    unsigned short int bpp;             // number of bits per pixel (must be 24)
    char temp;                          // temporary color storage for bgr-rgb conversion.

    // make sure the file is there.
    if ((file = fopen(filename, "rb"))==NULL)
    {
	printf("File Not Found : %s\n",filename);
	return 0;
    }
    
    // seek through the bmp header, up to the width/height:
    fseek(file, 18, SEEK_CUR);

    // read the width
    if ((i = fread(&image->sizeX, 4, 1, file)) != 1) {
	printf("Error reading width from %s.\n", filename);
	return 0;
    }
    //printf("Width of %s: %lu\n", filename, image->sizeX);
    
    // read the height 
    if ((i = fread(&image->sizeY, 4, 1, file)) != 1) {
	printf("Error reading height from %s.\n", filename);
	return 0;
    }
    //printf("Height of %s: %lu\n", filename, image->sizeY);
    
    // calculate the size (assuming 24 bits or 3 bytes per pixel).
    size = image->sizeX * image->sizeY * 3;

    // read the planes
    if ((fread(&planes, 2, 1, file)) != 1) {
	printf("Error reading planes from %s.\n", filename);
	return 0;
    }
    if (planes != 1) {
	printf("Planes from %s is not 1: %u\n", filename, planes);
	return 0;
    }

    // read the bpp
    if ((i = fread(&bpp, 2, 1, file)) != 1) {
	printf("Error reading bpp from %s.\n", filename);
	return 0;
    }
    if (bpp != 24) {
	printf("Bpp from %s is not 24: %u\n", filename, bpp);
	return 0;
    }
	
    // seek past the rest of the bitmap header.
    fseek(file, 24, SEEK_CUR);

    // read the data. 
    image->data = (char *) malloc(size);
    if (image->data == NULL) {
	printf("Error allocating memory for color-corrected image data");
	return 0;	
    }

    if ((i = fread(image->data, size, 1, file)) != 1) {
	printf("Error reading image data from %s.\n", filename);
	return 0;
    }

    for (i=0;i<size;i+=3) { // reverse all of the colors. (bgr -> rgb)
	temp = image->data[i];
	image->data[i] = image->data[i+2];
	image->data[i+2] = temp;
    }
    
    // we're done.
    return 1;
}
  
/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
void ReSizeGLScene(int Width, int Height)
{
    if (Height==0)				// Prevent A Divide By Zero If The Window Is Too Small
	Height=1;

    glViewport(0, 0, Width, Height);		// Reset The Current Viewport And Perspective Transformation

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
    glMatrixMode(GL_MODELVIEW);
}  
// Load Bitmaps And Convert To Textures
void LoadGLTextures() {	
    // Load Texture
    Image *image1,*image2,*image3,*image4,*image5;
    
    image1 = (Image *) malloc(sizeof(Image));
    if (image1 == NULL) {
	printf("Error allocating space for image");
	exit(0);
    }

    if (!ImageLoad("./road/admin.bmp", image1)) {
	exit(1);
    }        
    glGenTextures(1, (GLuint *)&texture[0]);
    glBindTexture(GL_TEXTURE_2D, texture[0]);   // 2d texture (x and y size)
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture
    glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);


    image2 = (Image *) malloc(sizeof(Image));
    if (image2 == NULL) {
	printf("Error allocating space for image");
	exit(0);
    }

    if (!ImageLoad("./road/library.bmp", image2)) {
	exit(1);
    }

    glGenTextures(1, (GLuint *)&texture[1]);
    glBindTexture(GL_TEXTURE_2D, texture[1]);   // 2d texture (x and y size)
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture
    glTexImage2D(GL_TEXTURE_2D, 0, 3, image2->sizeX, image2->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image2->data);


    image3 = (Image *) malloc(sizeof(Image));
    if (image3 == NULL) {
	printf("Error allocating space for image");
	exit(0);
    }

    if (!ImageLoad("./road/grass.bmp", image3)) {
	exit(1);
    }  
    
    glGenTextures(1, (GLuint *)&texture[2]);
    glBindTexture(GL_TEXTURE_2D, texture[2]);   // 2d texture (x and y size)
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture
    glTexImage2D(GL_TEXTURE_2D, 0, 3, image3->sizeX, image3->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image3->data);

    image4 = (Image *) malloc(sizeof(Image));
    if (image4 == NULL) {
	printf("Error allocating space for image");
	exit(0);
    }

    if (!ImageLoad("./road/cs.bmp", image4)) {
	exit(1);
    }  
    
    glGenTextures(1, (GLuint *)&texture[3]);
    glBindTexture(GL_TEXTURE_2D, texture[3]);   // 2d texture (x and y size)
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture
    glTexImage2D(GL_TEXTURE_2D, 0, 3, image4->sizeX, image4->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image4->data);


     image5 = (Image *) malloc(sizeof(Image));
    if (image5 == NULL) {
	printf("Error allocating space for image");
	exit(0);
    }

    if (!ImageLoad("./road/activity.bmp", image5)) {
	exit(1);
    }  
    
    glGenTextures(1, (GLuint *)&texture[4]);
    glBindTexture(GL_TEXTURE_2D, texture[4]);   // 2d texture (x and y size)
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture
    glTexImage2D(GL_TEXTURE_2D, 0, 3, image5->sizeX, image5->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image5->data);

    
};


/* The main drawing function. */
void DrawGLScene()
{
 
  //--------first image-----------------------
    glPushMatrix(); 
    glPushMatrix(); 
    glTranslatef(0.0f,10.0f,-13.0f); 
    glRotatef(90,1.0f,0.0f,0.0f);
    GLUquadricObj *obj;
    obj = gluNewQuadric();
    gluQuadricDrawStyle(obj, GLU_LINE);
    gluCylinder(obj,0.1f,0.1f,10.0f,32,32);	
    glPopMatrix();

    glPushMatrix(); 
    glTranslatef(0.0f,10.0f,9.0f); 
    glRotatef(90,1.0f,0.0f,0.0f);
    gluQuadricDrawStyle(obj, GLU_LINE);
    gluCylinder(obj,0.1f,0.1f,10.0f,32,32);	
    glPopMatrix();
   
    glTranslatef(1.0f,10.0f,-2.0f);             
    glRotatef(270,0.0f,1.0f,0.0f);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texture[0]);  

    
    glBegin(GL_QUADS);		                
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-11.2f, -1.5f,  1.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 11.2f, -1.5f,  1.0f);	
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 11.2f,  1.5f,  1.0f);	
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-11.2f,  1.5f,  1.0f);
    glEnd(); 
    glPopMatrix();

    //----- second image----------------------
    glPushMatrix();

    glPushMatrix(); 
    glTranslatef(-19.9011f, 10.0f, -200.234f);
    glRotatef(90,1.0f,0.0f,0.0f);
    gluQuadricDrawStyle(obj, GLU_LINE);
    gluCylinder(obj,0.1f,0.1f,10.0f,32,32);	
    glPopMatrix();

    glPushMatrix(); 
    glTranslatef(-29.9011f, 10.0f, -220.234f);
    glRotatef(90,1.0f,0.0f,0.0f);
    gluQuadricDrawStyle(obj, GLU_LINE);
    gluCylinder(obj,0.1f,0.1f,10.0f,32,32);	
    glPopMatrix();

    glBindTexture(GL_TEXTURE_2D, texture[1]);  
    glTranslatef(-24.9011f, 10.0f, -210.234f);
    glRotatef(118,0.0f,1.0f,0.0f);

    glBegin(GL_QUADS);		              
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-12.2f, -1.5f,  1.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 12.2f, -1.5f,  1.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 12.2f,  1.5f,  1.0f);	
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-12.2f,  1.5f,  1.0f);	
    glEnd(); 
    glPopMatrix();
  

    //----------Third image-----------------------
    glPushMatrix();
    glBindTexture(GL_TEXTURE_2D, texture[2]);   
    glTranslatef(5.0f, 5.0f, 5.0f);
    glRotatef(90,0.0f,1.0f,0.0f);

    glBegin(GL_QUADS);	     
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1000.0f, -7.0f, -500.0f);	
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1000.0f, -7.0f, -500.0f);
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1000.0f, -7.0f,  500.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1000.0f, -7.0f,  500.0f);	
    glEnd();

    glPopMatrix();
   

    //-------fourth image--------------------------
    glPushMatrix();

    glPushMatrix(); 
    glTranslatef(27.9011f, 36.0f, -194.234f);
    glRotatef(90,1.0f,0.0f,0.0f);
    gluQuadricDrawStyle(obj, GLU_LINE);
    gluCylinder(obj,0.1f,0.1f,10.0f,32,32);	
    glPopMatrix();

    glPushMatrix(); 
    glTranslatef(36.9011f, 36.0f, -209.234f);

     glRotatef(90,1.0f,0.0f,0.0f);
    gluQuadricDrawStyle(obj, GLU_LINE);
    gluCylinder(obj,0.1f,0.1f,10.0f,32,32);	
    glPopMatrix();

    glBindTexture(GL_TEXTURE_2D, texture[3]);  
    glTranslatef(31.9011f, 36.0f, -202.25f);
    glRotatef(58,0.0f,1.0f,0.0f);

    glBegin(GL_QUADS);		              
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-10.2f, -1.5f,  1.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 10.2f, -1.5f,  1.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 10.2f,  1.5f,  1.0f);	
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-10.2f,  1.5f,  1.0f);	
    glEnd(); 
    glPopMatrix();
   
    //-------fifth image----------------------------------------
    glPushMatrix();

    glPushMatrix(); 
    glTranslatef(-32.9653f,10.0f, -795.917f);
    glRotatef(90,1.0f,0.0f,0.0f);
    gluQuadricDrawStyle(obj, GLU_LINE);
    gluCylinder(obj,0.1f,0.1f,10.0f,32,32);	
    glPopMatrix();

    glPushMatrix(); 
    glTranslatef(-40.9653f, 10.0f, -815.917f);

    glRotatef(90,1.0f,0.0f,0.0f);
    gluQuadricDrawStyle(obj, GLU_LINE);
    gluCylinder(obj,0.1f,0.1f,15.0f,32,32);	
    glPopMatrix();

    glBindTexture(GL_TEXTURE_2D, texture[4]);  
    glTranslatef(-36.9653f, 10.0f, -806.917f);

    glRotatef(110,0.0f,1.0f,0.0f);

    glBegin(GL_QUADS);		              
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-12.8f, -1.5f,  1.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 12.8f, -1.5f,  1.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 12.8f,  1.5f,  1.0f);	
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-12.8f,  1.5f,  1.0f);	
    glEnd(); 
    glPopMatrix();
    glDisable(GL_TEXTURE_2D); 
    
}

