#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#if defined(__APPLE__) && defined(__MACH__)
#include <GLUT/glut.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#endif

#include "readBMP.h"

/* pointer to image for grid texture */
Image* image;

/* place to store OpenGL-created names of texture objects */
static GLuint gridTex;

/* cursor position */ 
static int oldx;
static int oldy;

/* camera x-y position */
static GLfloat cameraPosition[3] = {0.0, 0.0, 5.0};

/* x-y direction camera is pointing */
static GLfloat cameraDirection[2] = {0.0, 1.0};

/* angle between the camera and the y axis */
static double angle = 0.0;


/********************************************************************************/

/* draw the sea floor as a texture-mapped square */
void seaFloor(void) {
  GLfloat X = 0.0;
  GLfloat Y = 0.0;     /* center of group of tiles drawn */ 
  
  /* turn on texture mapping and use the texture object created at initialization */
  glEnable(GL_TEXTURE_2D);
  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
  glBindTexture(GL_TEXTURE_2D,gridTex);

  /* texture coordinates place 5x5 copies of the texture on the rectangle */

  glBegin(GL_QUADS);
   glTexCoord2f(-7.0,-7.0);
   glVertex3f(X-35.0, Y-35.0, 0.0);
   glTexCoord2f(-7.0,7.0);
   glVertex3f(X-35.0, Y+35.0, 0.0);
   glTexCoord2f(7.0,7.0);
   glVertex3f(X+35.0, Y+35.0, 0.0);
   glTexCoord2f(7.0,-7.0);
   glVertex3f(X+35.0, Y-35.0, 0.0);
  glEnd();
  glDisable(GL_TEXTURE_2D);
}

void initLighting(void)
{
    static float light1_ambient[] = {0.05, 0.05, 0.05, 1.0};
    static float light1_diffuse[] = {1.0, 1.0, 1.0, 1.0};
    static float light1_specular[] = {2.0, 2.0, 2.0, 1.0};

    glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
    glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
    glEnable(GL_LIGHT1);
    glEnable(GL_LIGHTING);
}

void placeLight(void)
{
    static float light1_position[] = {-0.5, 1.0, 0.5, 0.0};
    glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
}


void getImage() {
  size_t size;

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

    if (!ImageLoad("./grid.bmp", image)) {
	exit(1);
    }    
}

void initTextures(void) {
  /* read in image for texture */ 
  getImage();
  /* create a texture object */
  glGenTextures(1,&gridTex);
  /* make it the current texture */
  glBindTexture(GL_TEXTURE_2D,gridTex);
  /* make it wrap around */
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
  /* make it filter nicely */
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  /* and put the image data into the texure object */
  glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,128,128,0,
	       GL_RGB,GL_UNSIGNED_BYTE,image->data);
}


/* Should put viewing parameters into Modelview matrix which produce
   transformation required by cameraPosition and cameraAngle parameters */
void placeCamera() {
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glRotatef(-90.0,1.0,0.0,0.0); /* rotate to point forward */  
  glTranslatef(0.0, 0.0, -5.0); /* raise camera above floor */
}

void init(void) {
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glShadeModel(GL_SMOOTH);
  glEnable(GL_DEPTH_TEST);
  initLighting();	
  initTextures();

  /* initialize projection matrix */
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum(-.5,.5,-.5,.5,1.0,35.0);
}

void background(void) {

  /* place camera in current position */
  placeCamera();

  /* draw sea floor */
  seaFloor();
}


void foreground(void) {

  /* postion camera */
  placeCamera();

  /* position lights after camera transformation */
  placeLight();	

  /* draw objects after positioning light */

}

void display(void) {

  /* erase the frame buffer and the depth buffer */
  glClearColor(0.0,0.0,0.0,1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  /* draw background */
  background();

  /* draw foreground */
  foreground();

  glutSwapBuffers();
}

void reshape (int w, int h) {
  glViewport(0, 0, (GLsizei) w, (GLsizei) h);
  glutPostRedisplay();
}

int main(int argc, char** argv) {
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(500,500);
  glutInitWindowPosition(100,100);
  glutCreateWindow(argv[0]);

  /* initialize background, objects, camera, etc. */
  init();

  /* callback functions */
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);

  glutMainLoop();
  return(0);
}


