/*****************************************************************
  subload.cpp
  by Dave Pape
  16 March 2003

 This program uses texture subloading (glTexSubImage2D) to animate
 a texture.  It re-defines a portion of the texture each frame,
 rather than the full image.  The images that are loaded are
 320x240 resolution, so if they were loaded as the full texture
 image, then we would have to resize them to powers-of-2 every
 time, which would be much slower.
 (Note - some of this code assumes that the images are 320x240;
 if the size happened to change, the program would either break
 or at least not look quite right.  A better program would check
 the size of the images and adapt.)

*****************************************************************/
#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);

#define NUM_TEXTURES 80
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;
    }


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,"falls2/%03d.sgi",i);
        images[i] = new FileImage(filename);
        }
/*************** CODE OF INTEREST ******************************/
/* Here we pre-load the texture with a blank image whose size  */
/* is slightly bigger than that of the images we're using, so  */
/* that there will be room to subload them into.               */
/* define() must be called once, before subload() can be used. */
/*                                                             */
    Image * blankImage = new Image(512,256);
    texture.setImage(*blankImage);
    texture.define();
    square->setTexture(texture);
/*************** CODE OF INTEREST ******************************/
/* The upper-right texture coordinates of (0.625, 0.9375) are  */
/* based on subloading a 320x240 image into a 512x256 base     */
/* texture.  320 / 512 = 0.625,  240 / 256 = 0.9375.           */
/*                                                             */
//    square->setTexCoords(0,0, 0.625, 0.9375);
    square->setUpdateCallback(updateTexture, textureNum);
    root.attach(*square);
    }


/*************** CODE OF INTEREST ******************************/
/* Assign the next image to the texture, and have it subload   */
/* the new image data.                                         */
/*                                                             */
void updateTexture(dms::Object& object,void *data)
    {
    int * textureNum = (int *)data;
    *textureNum = (int)(fmod(currentTime(),1.0) * NUM_TEXTURES);
    texture.setImage(*images[*textureNum]);
    texture.subload();
    }


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");
    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();
    }
