/**************************************************
 *   File:     ImageMap.cpp
 *   Author:   Dr. Dalton R. Hunkins     
 *   Date:     December 2008
 *  
 *  User Interaction
 *    Right-Triggered Menu
 *    with two submenus and  
 *    two other items.
 *    One of the latter items
 *    is "Show Source Code" but 
 *    is not included in this 
 *    code listing.
**************************************************/

#include <GL/Gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/Utils/imageMap.h>
#include <GL/Utils/MathFunctions.h>

#include <iostream>
using std::cout;
using std::endl;

#include <cmath>

// Menu Constants 
static const int menuScene     = 900;
static const int menuFishes    = 901;

static const int menuFullImage = 910;
static const int menuSquare1   = 911;
static const int menuSquare2   = 912;
static const int menuHexagon   = 913;
static const int menuOctagon   = 914;

static const int menuClose     = 922;

int displayChoice = menuFullImage;
int textureChoice = menuScene;

class ProgramExit {};

// Image Map Declarations
ImageMap *scene;
ImageMap *fishes;

string parentDirectory = "OpenGLTutorials";
string imageMapPath;

string sceneName    = "Scene.bmp";
string fishesName   = "Fishes.bmp";

static GLuint textureName[2];

void setPath(string pathName) {
     if (pathName[0] == '/') {
         pathName = pathName.substr(10, pathName.length());
         imageMapPath = pathName.substr(0,1) + ":/";
	     pathName = pathName.substr(2, pathName.length());
     }   
     int position = pathName.find(parentDirectory, 0);
     pathName = pathName.substr(0, position+parentDirectory.length());
     imageMapPath += pathName + "/Resources/ImageMaps/";
}

void init() {   
   glClearColor(0.0, 0.0, 0.0, 1.0);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluOrtho2D(-1.0, 1.0, -1.0, 1.0);

   // Establish  Image Maps
   scene  = new ImageMap(imageMapPath, sceneName);
   fishes = new ImageMap(imageMapPath, fishesName);
   
   // Generate Texture Names
   glGenTextures(2, textureName);

   // Create Texture Objects with Properties  
   glBindTexture(GL_TEXTURE_2D, textureName[0]);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);  
   scene->setTexture();

   glBindTexture(GL_TEXTURE_2D, textureName[1]);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);  
   fishes->setTexture();
   
   glEnable(GL_TEXTURE_2D);
}

void drawFullImage() {
    glBegin(GL_POLYGON);
      glTexCoord2f(0.0, 0.0);
      glVertex2d(-1.0, -1.0);
      glTexCoord2f(1.0, 0.0);
      glVertex2d(1.0, -1.0);
      glTexCoord2f(1.0, 1.0);
      glVertex2d(1.0, 1.0);
      glTexCoord2f(0.0, 1.0);
      glVertex2d(-1.0, 1.0);
    glEnd();
}

void drawSquare1() {
    glBegin(GL_POLYGON);
      glTexCoord2f(0.0, 0.0);
      glVertex2d(-0.0, -0.95);
      glTexCoord2f(1.0, 0.0);
      glVertex2d(0.95, 0.0);
      glTexCoord2f(1.0, 1.0);
      glVertex2d(0.0, 0.95);
      glTexCoord2f(0.0, 1.0);
      glVertex2d(-0.95, 0.0);
    glEnd();
}

void drawSquare2() {
    glMatrixMode(GL_TEXTURE);
    glPushMatrix();
    glTranslated(-0.5, -0.5, 0.0);
    glScaled(0.5, 0.5, 1.0);
    
    glBegin(GL_POLYGON);
       glTexCoord2f(cos(0*PI/4.0), sin(0*PI/4.0));
       glVertex2d(  cos(0*PI/4.0), sin(0*PI/4.0));
       glTexCoord2f(cos(2*PI/4.0), sin(2*PI/4.0));
       glVertex2d(  cos(2*PI/4.0), sin(2*PI/4.0));
       glTexCoord2f(cos(4*PI/4.0), sin(4*PI/4.0));
       glVertex2d(  cos(4*PI/4.0), sin(4*PI/4.0));
       glTexCoord2f(cos(6*PI/4.0), sin(6*PI/4.0));
       glVertex2d(  cos(6*PI/4.0), sin(6*PI/4.0));
    glEnd();
    glPopMatrix();
}               

void drawHexagon() {
    glMatrixMode(GL_TEXTURE);
    glPushMatrix();
    glTranslated(-0.5, -0.5, 0.0);
    glScaled(0.5, 0.5, 1.0);
    
    glBegin(GL_POLYGON);
       glTexCoord2f(cos(0*PI/3.0), sin(0*PI/3.0));
       glVertex2d(  cos(0*PI/3.0), sin(0*PI/3.0));
       glTexCoord2f(cos(1*PI/3.0), sin(1*PI/3.0));
       glVertex2d(  cos(1*PI/3.0), sin(1*PI/3.0));
       glTexCoord2f(cos(2*PI/3.0), sin(2*PI/3.0));
       glVertex2d(  cos(2*PI/3.0), sin(2*PI/3.0));
       glTexCoord2f(cos(3*PI/3.0), sin(3*PI/3.0));
       glVertex2d(  cos(3*PI/3.0), sin(3*PI/3.0));
       glTexCoord2f(cos(4*PI/3.0), sin(4*PI/3.0));
       glVertex2d(  cos(4*PI/3.0), sin(4*PI/3.0));
       glTexCoord2f(cos(5*PI/3.0), sin(5*PI/3.0));
       glVertex2d(  cos(5*PI/3.0), sin(5*PI/3.0));
    glEnd();
    glPopMatrix();
}               

void drawOctagon() {
    glMatrixMode(GL_TEXTURE);
    glPushMatrix();
    glTranslated(-0.5, -0.5, 0.0);
    glScaled(0.5, 0.5, 1.0);
    
    glBegin(GL_POLYGON);
       glTexCoord2f(cos(0*PI/4.0), sin(0*PI/4.0));
       glVertex2d(  cos(0*PI/4.0), sin(0*PI/4.0));
       glTexCoord2f(cos(1*PI/4.0), sin(1*PI/4.0));
       glVertex2d(  cos(1*PI/4.0), sin(1*PI/4.0));
       glTexCoord2f(cos(2*PI/4.0), sin(2*PI/4.0));
       glVertex2d(  cos(2*PI/4.0), sin(2*PI/4.0));
       glTexCoord2f(cos(3*PI/4.0), sin(3*PI/4.0));
       glVertex2d(  cos(3*PI/4.0), sin(3*PI/4.0));
       glTexCoord2f(cos(4*PI/4.0), sin(4*PI/4.0));
       glVertex2d(  cos(4*PI/4.0), sin(4*PI/4.0));
       glTexCoord2f(cos(5*PI/4.0), sin(5*PI/4.0));
       glVertex2d(  cos(5*PI/4.0), sin(5*PI/4.0));
       glTexCoord2f(cos(6*PI/4.0), sin(6*PI/4.0));
       glVertex2d(  cos(6*PI/4.0), sin(6*PI/4.0));
       glTexCoord2f(cos(7*PI/4.0), sin(7*PI/4.0));
       glVertex2d(  cos(7*PI/4.0), sin(7*PI/4.0));
    glEnd();
    glPopMatrix();
}               

void display() {
    glClear(GL_COLOR_BUFFER_BIT);
    
    switch(textureChoice) {
       case menuScene :
           glBindTexture(GL_TEXTURE_2D, textureName[0]);
           break;
       case menuFishes :
           glBindTexture(GL_TEXTURE_2D, textureName[1]);
           break;
    }          
    
    switch(displayChoice) {
       case menuFullImage :
          drawFullImage();
          break;                          
       case menuSquare1 :
          drawSquare1();
          break;
       case menuSquare2 :
          drawSquare2();
          break;
       case menuHexagon :
          drawHexagon();
          break;
       case menuOctagon :
          drawOctagon();
          break;
    }                                            
    
    glFlush();
}
   
void menuHandler(int selection) {
    switch (selection) {
       case menuFishes :
       case menuScene :
          textureChoice = selection;
          glutPostRedisplay();
          break;
       case menuFullImage :          
       case menuSquare1   :
       case menuSquare2   :
       case menuHexagon   :
       case menuOctagon   :
          displayChoice = selection;
          glutPostRedisplay();
          break;          
       case menuClose :
          throw ProgramExit();
    }
}

void createMenu() {
    int mainMenuId     = glutCreateMenu(menuHandler);
    int textureMenuId  = glutCreateMenu(menuHandler);
    int displayMenuId  = glutCreateMenu(menuHandler);
    

    glutSetMenu(mainMenuId);
    glutAddSubMenu("Select Image Map",             textureMenuId);
    glutAddSubMenu("Select Geometry and Mapping",  displayMenuId);
    glutAddMenuEntry("", 0);
    glutAddMenuEntry("Show Source Code",     menuShowCode);
    glutAddMenuEntry("Close Source Code",    menuCloseCode);
    glutAddMenuEntry("Close Program",        menuCloseProgram);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    glutSetMenu(textureMenuId);
    glutAddMenuEntry("Mountain ", menuScene);
    glutAddMenuEntry("Fishes   ", menuFishes);

    glutSetMenu(displayMenuId);
    glutAddMenuEntry("Full Mapping    ", menuFullImage);
    glutAddMenuEntry("Square Mapping 1", menuSquare1);
    glutAddMenuEntry("Square Mapping 2", menuSquare2);
    glutAddMenuEntry("Hexagon Mapping ", menuHexagon);
    glutAddMenuEntry("Octagon Mapping ",   menuOctagon);
}


int main(int argc, char **argv) {
    string pathName = argv[0];
    setPaths(pathName);    

    glutInit(&argc, argv);
    glutInitWindowPosition(0, 0);
    glutInitWindowSize(500, 500);
    glutCreateWindow("Two Image Maps");
    createMenu();

    glutDisplayFunc(display);
    
    init();
   
    try {
      glutMainLoop();
    }
    catch (ProgramExit) { 
    	cout << "Closing program" << endl;}
	
    return 0;
}