#include <stdio.h>
#include <stdlib.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_opengl.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <math.h>
#include <time.h>
#include <GL/glu.h>

#define PI  3.14159



const float BOX_SIZE = 4.0f;  //The length of each side of the cube
float angle = 0;               //The rotation of the cube
GLuint texture[6];
bool done = false;
int i;
int screen_width = 1280;
int screen_height = 800;

ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_BITMAP  *bmp   = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer;

void initRendering(void)
 {
	glEnable(GL_DEPTH_TEST);
//	glEnable(GL_LIGHTING);
//	glEnable(GL_LIGHT0);
	glEnable(GL_NORMALIZE);
	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_TEXTURE_2D);
	glDepthFunc(GL_LEQUAL);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);

    //load textures from bitmap files
    bmp = al_load_bitmap("orange.jpg"); // 256 x 256 pixels
	texture[0] = al_get_opengl_texture(bmp);

	bmp = al_load_bitmap("red.jpg"); // 256 x 256 pixels
	texture[1] = al_get_opengl_texture(bmp);

	bmp = al_load_bitmap("green.jpg"); // 256 x 256 pixels
	texture[2] = al_get_opengl_texture(bmp);

	bmp = al_load_bitmap("blue.jpg"); // 256 x 256 pixels  //
	texture[3] = al_get_opengl_texture(bmp);

	bmp = al_load_bitmap("white.jpg"); // 256 x 256 pixels
	texture[4] = al_get_opengl_texture(bmp);

	bmp = al_load_bitmap("yellow.jpg"); // 256 x 256 pixels   //
	texture[5] = al_get_opengl_texture(bmp);
 }

void handleResize(int w, int h)
 {
 	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0, (float)w / (float)h, 1.0, 200.0);
 }

void drawCube()
   {
	   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	   glMatrixMode(GL_MODELVIEW);
	   glLoadIdentity();
	   glTranslatef(0, 1.0, -25);
	   GLfloat ambientLight[] = {0.3f, 0.3f, 0.3f, 1.0f};
	   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
	   GLfloat lightColor[] = {0.7f, 0.7f, 0.7f, 1.0f};
	   GLfloat lightPos[] = {-8, 4, 16, 1.0f};
	   glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
	   glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

       glRotatef(-angle, 1, 1, 1);

	   //Top face
	   glEnable(GL_TEXTURE_2D);  //orange
	   glBindTexture(GL_TEXTURE_2D, texture[0]);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       glColor3f(1.0f, 1.0f, 1.0f);
	   glBegin(GL_QUADS);
	   glNormal3f(0.0, 1.0f, 0.0f);
	   glTexCoord2f(0.0f, 0.0f);
	   glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2);
	   glTexCoord2f(1.0f, 0.0f);
	   glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2);
	   glTexCoord2f(1.0f, 1.0f);
	   glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2);
	   glTexCoord2f(0.0f, 1.0f);
	   glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2);
       glEnd();

	   //Bottom face  green
	   glEnable(GL_TEXTURE_2D);
	   glBindTexture(GL_TEXTURE_2D, texture[1]);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       glColor3f(1.0f, 1.0f, 1.0f);
	   glBegin(GL_QUADS);
	   glNormal3f(0.0, -1.0f, 0.0f);
       glTexCoord2f(0.0f, 0.0f);
	   glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2);
	   glTexCoord2f(1.0f, 0.0f);
	   glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2);
	   glTexCoord2f(1.0f, 1.0f);
	   glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2);
	   glTexCoord2f(0.0f, 1.0f);
	   glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2);
	   glEnd();

	   //Left face   //red
	   glEnable(GL_TEXTURE_2D);
	   glBindTexture(GL_TEXTURE_2D, texture[2]);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	   glColor3f(1.0f, 1.0f, 1.0f);
       glBegin(GL_QUADS);
	   glNormal3f(-1.0, 0.0f, 0.0f);

       glTexCoord2f(0.0f, 0.0f);
	   glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2);
       glTexCoord2f(1.0f, 0.0f);
	   glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2);
       glTexCoord2f(1.0f, 1.0f);
	   glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2);
       glTexCoord2f(0.0f, 1.0f);
	   glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2);
	   glEnd();

	   //Right face  //white
	   glEnable(GL_TEXTURE_2D);
	   glBindTexture(GL_TEXTURE_2D, texture[3]);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	   glColor3f(1.0f, 1.0f, 1.0f);
       glBegin(GL_QUADS);
	   glNormal3f(1.0, 0.0f, 0.0f);
 	   glColor3f(1.0f, 0.0f, 0.0f);
       glTexCoord2f(0.0f, 0.0f);
	   glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2);
       glTexCoord2f(1.0f, 0.0f);
	   glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2);
       glTexCoord2f(1.0f, 1.0f);
	   glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2);
       glTexCoord2f(0.0f, 1.0f);
	   glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2);
       glEnd();
	   // Front face  //blue
	   glEnable(GL_TEXTURE_2D);
       glBindTexture(GL_TEXTURE_2D, texture[4]);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	   glColor3f(1.0f, 1.0f, 1.0f);
	   glBegin(GL_QUADS);

	   glNormal3f(0.0, 0.0f, 1.0f);
	   glColor3f(1.0f, 0.0f, 0.0f);
	   glTexCoord2f(0.0f, 0.0f);
	   glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2);
	   glTexCoord2f(1.0f, 0.0f);
	   glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2);
	   glTexCoord2f(1.0f, 1.0f);
	   glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2);
	   glTexCoord2f(0.0f, 1.0f);
	   glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2);
       glEnd();

       //Back face  yellow
	   glEnable(GL_TEXTURE_2D);
       glBindTexture(GL_TEXTURE_2D, texture[5]);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       glColor3f(1.0f, 1.0f, 1.0f);
	   glBegin(GL_QUADS);

	   glNormal3f(0.0, 0.0f, -1.0f);
	   glTexCoord2f(0.0f, 0.0f);
	   glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2);
	   glTexCoord2f(1.0f, 0.0f);
	   glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2);
	   glTexCoord2f(1.0f, 1.0f);
	   glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2);
	   glTexCoord2f(0.0f, 1.0f);
	   glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2);

	   glEnd();
	   glDisable(GL_TEXTURE_2D);
       al_flip_display();
     }

//Called every 25 milliseconds
void update(int value)
 {
	angle += 1.0f;
	if ( angle > 360)
	 {
		 angle -= 360;
	 }
 }

int main(void)
  {
     al_init();
     al_init_image_addon();
     al_init_primitives_addon();

     al_init_font_addon();
     al_init_ttf_addon();

     al_install_keyboard();
     al_install_mouse();

     al_set_new_display_flags(ALLEGRO_OPENGL);
     display = al_create_display(1280, 800);
     glClearColor(0.2, 0.2, 0.2, 0.0);
     al_set_target_bitmap(al_get_backbuffer(display));

     event_queue = al_create_event_queue();
	 timer = al_create_timer(1.0 / 60);    // lower value of 60 to slow cube down

	 al_register_event_source(event_queue, al_get_timer_event_source(timer));
	 al_register_event_source(event_queue, al_get_keyboard_event_source());
	 al_register_event_source(event_queue, al_get_mouse_event_source());

	 al_start_timer(timer);

	 handleResize(1280, 800);

	 initRendering();

	 ALLEGRO_EVENT ev;

     while (!done)
       {

          if (al_event_queue_is_empty(event_queue))
           {
              update(25);
              drawCube();
             // al_flip_display();
           }

         al_wait_for_event(event_queue, &ev);

         switch (ev.type)
            {
               case ALLEGRO_EVENT_DISPLAY_CLOSE:
                 done = true;
                 break;

               case ALLEGRO_EVENT_KEY_DOWN:
                 if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                 done = true;
                 break;
            }

       }

for(i = 0; i < 6; i++)
   glDeleteTextures(1, &texture[i]);

al_destroy_event_queue(event_queue);
al_destroy_display(display);
//return 0;
}
