/*                               */
/* Sample Program for CDS301 2013 project  */
/* On creating a Gaussian function and the grid plane */
/*===============================*/

/*----------*/
/* includes */
/*----------*/
#include <math.h>
#include <stdlib.h>
/* opengl and glut includes */
#if defined(_CYGWIN_)    /* CYGWIN */

#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>

#elif defined(_LINUX_)   /* LINUX */

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#endif

/* prototypes */
void init(void);
void display(void);

float f(float a, float b);
float nx(float a, float b);
float ny(float a, float b);

/*---------------*/
/* main function */
/*---------------*/
int main(int argc,char **argv)
{
   /* GLUT management */
   glutInit(&argc,argv);
   glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
   glutInitWindowSize(500,500);
   glutInitWindowPosition(100,100);
   glutCreateWindow("CDS301 - Project 1");
   /* call the initialization function */
   init();

   /* drawing function */
   glutDisplayFunc(display);

   /* get in the infinite loop */
   glutMainLoop();

   return 0;
}

/*-------------------------*/
/* initialization function */
/*-------------------------*/
void init(void)
{
   /* set backgroung color RGB plus alpha */
   glClearColor(0.9,0.9,0.9,0.0);

   /* selects the projection matrix to work */
   glMatrixMode(GL_PROJECTION);
   /* loads the identity */
   glLoadIdentity();

   GLfloat pos[4] = {5.0,30.0, 15.0,30.0};  // 5 25 15 20

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_SMOOTH);
   glShadeModel(GL_SMOOTH);
   GLfloat color[4] = {1.0,0.0,0.0};
   glLightfv(GL_LIGHT0,GL_POSITION,pos);
   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
   GLfloat global_ambient[4] = { 0.0f, 1.0f, 0.0f, 0.5f };
   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
   glLightfv(GL_LIGHT0,GL_AMBIENT, color);
   glLightfv(GL_LIGHT0,GL_DIFFUSE, color);
   GLfloat spec[4] = {1.0,1.0,1.0,1.0};
   glLightfv(GL_LIGHT0,GL_SPECULAR,spec);

   glEnable(GL_DEPTH_TEST);

   /* specifies the projection type => ortho */
   /*      left right bottom  top  near  far */
   glOrtho( -1.5,  1.5, -1.5, 1.5, -3.0, 3.0);
   return;
}

/*------*/
/* draw */
/*------*/
void display(void)
{
   /* clean all pixels */
   glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);

   /* rotate in 30 deg in x and 20 def in y */ 
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glRotatef(-90.0,1.0,0.0,0.0);
   glRotatef(15.0,0.0,0.0,1.0);
   glRotatef(15.0,1.0,0.0,0.0);

   /* set color for polygon */
   glColor3f(0.0,0.0,0.0);

   /* draw function */
   float X_min,X_max,Y_min,Y_max,dx,dy,x,y;
   X_min = -1.0;
   X_max = 1.0;
   Y_min = -1.0;
   Y_max = 1.0;
   dx = 0.02;
   dy = 0.02;
   for(x = X_min;x<=X_max-dx;x+=dx)
   {
       for(y = Y_min;y<=Y_max-dy;y+=dy)
       {
	   glBegin(GL_QUADS);
           glNormal3f(nx(x,y),ny(x,y),1.0);
	   glVertex3f(x,y,f(x,y));
           glNormal3f(nx(x+dx,y),ny(x+dx,y),1.0);
	   glVertex3f(x+dx,y,f(x+dx,y));
           glNormal3f(nx(x+dx,y+dy),ny(x+dx,y+dy),1.0);
	   glVertex3f(x+dx,y+dy,f(x+dx,y+dy));
           glNormal3f(nx(x,y+dy),ny(x,y+dy),1.0);
	   glVertex3f(x,y+dy,f(x,y+dy));
	   glEnd();
       }
   }

   glFlush();

   return;
}
/*Function exp(-(x^2 + y^2))*/
float f(float a, float b)
{
   return exp(-1.0*((pow(a,2.0) + pow(b,2.0))));
}
/*calculating normal of f*/
float nx(float a, float b)
{
   int value;
   value = (-2.0*a*f(a,b))/sqrt(4.0*pow(a,2)*pow(f(a,b),2)+4.0*pow(b,2)*pow(f(a,b),2)+1);
   return value;
}
float ny(float a, float b)
{
   int value;
   value = (-2.0*b*f(a,b))/sqrt(4.0*pow(a,2)*pow(f(a,b),2)+4.0*pow(b,2)*pow(f(a,b),2)+1);
   return value;
}