/*****************************************************************
  anim-falls.cpp
  by Dave Pape
  16 March 2003

 This program demonstrates creating a texture animation by
 constantly re-defining a single texture, rather than pre-loading
 a whole sequence of textures.  It loads a series of 60 images
 into memory, and then assigns a different one to the texture
 object on each frame, and tells the texture to define itself
 again (which will cause the new image data to be downloaded to
 the graphics card).  The images are 512x512, which means that
 the entire sequence requires 60 megabytes of memory - too much
 for most of our graphics cards to hold at one time, but an amount
 that can fit into the PC's main memory.

*****************************************************************/
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <stdio.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <dms/dms.h>
#include "Square.h"

using namespace dms;

void createScene(Object& root);
void drawEverything(void);
void updateTexture(dms::Object& object,void *data);

void key(unsigned char k, int x, int y);
void specialkey(int k, int x, int y);
void idle(void);

/*************** CODE OF INTEREST ******************************/
/* Declare an array of images for the animation, and just one  */
/* texture object.                                             */
/*                                                             */
#define NUM_TEXTURES 60
FileImage * images[NUM_TEXTURES];
Texture2D texture;

int frameNumber=0;
float lastTime=0;


PerspCamera camera;
Object root;

int main(int argc, char *argv[])
    {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(512,512);
    glutCreateWindow(argv[0]);
    
    glutDisplayFunc(drawEverything);
    glutKeyboardFunc(key);
    glutSpecialFunc(specialkey);
    glutIdleFunc(idle);
    
    camera.setPosition(0, 0, 3);
    createScene(root);
    
    glutMainLoop();
    return 0;
    }


/*************** CODE OF INTEREST ******************************/
/* Load all of the images into the array of FileImage objects, */
/* and initialize the texture object with the first image.     */
/*                                                             */
void createScene(Object& root)
    {
    Square *square = new Square;
    int i;
    int *textureNum = new int(0);
    for (i=0; i < NUM_TEXTURES; i++)
        {
        char filename[256];
        sprintf(filename,"falls/%03d.sgi",i);
        images[i] = new FileImage(filename);
        }
    texture.setImage(*images[0]);
//    texture.setMinFilter(GL_LINEAR_MIPMAP_LINEAR);
    square->setTexture(texture);
    square->setUpdateCallback(updateTexture, textureNum);
    root.attach(*square);
    }


/*************** CODE OF INTEREST ******************************/
/* Determine the next image to apply, assign it to the texture,*/
/* and have the texture re-define itself.                      */
/*                                                             */
void updateTexture(dms::Object& object,void *data)
    {
    int * textureNum = (int *)data;
    *textureNum = (int)(fmod(currentTime(),1.0) * NUM_TEXTURES);
    texture.setImage(*images[*textureNum]);
    texture.define();
    }


void drawEverything(void)
    {
    glClearColor(0.5, 0.7, 1.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    
    camera.apply();
    
    Color::White.apply();
    root.drawAll();

    glutSwapBuffers();

    checkGLError("end-of-frame");
/*************** CODE OF INTEREST ******************************/
/* This code prints the current frame rate, so that we can see */
/* how fast the hardware is capable of defining textures on    */
/* the fly.                                                    */
/*                                                             */
    frameNumber++;
    if (frameNumber == 100)
        {
        printf("%f frames/second\n",100.0/(currentTime()-lastTime));
        lastTime = currentTime();
        frameNumber = 0;
        }
    }


void key(unsigned char k, int x, int y)
    {
    if (k == 27)
        exit(0);
    }


void specialkey(int k, int x, int y)
    {
    if (k == GLUT_KEY_LEFT)
        camera.turn(3);
    else if (k == GLUT_KEY_RIGHT)
        camera.turn(-3);
    else if (k == GLUT_KEY_UP)
        camera.pitch(2);
    else if (k == GLUT_KEY_DOWN)
        camera.pitch(-2);
    else if (k == GLUT_KEY_HOME)
        camera.moveForward(0.25);
    else if (k == GLUT_KEY_END)
        camera.moveForward(-0.25);
    else if (k == GLUT_KEY_PAGE_UP)
        camera.zoom(-1);
    else if (k == GLUT_KEY_PAGE_DOWN)
        camera.zoom(1);
    }


void idle(void)
    {
    root.updateAll();
    glutPostRedisplay();
    }
