/*****************************************************************
  multitex3.cpp
  by Dave Pape
  2 April 2003

  This program demonstrates the use of texgen, in combination
  with lightmapping & multitexturing, to produce a moving lightmap
  on an object.  The first texture (the color data) remains
  static.  This shows how other texture state, such as the texgen
  function, is also affected by glActiveTextureARB - the texgen
  is only used by one unit, rather than being a global function
  for all units.
  One difference to note between this program and multitex2.cpp
  is that the floor is now drawn using a Square object, rather
  than explicit GL code.  We can do this now because we're using
  texgen to generate the second texture unit's coordinates, so
  we don't need to add glMultiTexCoord2fARB calls to the code
  that draws the floor - the lightmap texture can be applied
  'externally'.

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

using namespace dms;

void drawEverything(void);

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


PerspCamera camera;

Square wall(-10, -0.5, 10, 10, DMS_Z);
Square room(-10, 0, 10, 10, DMS_Y);
Texture2D wallTex("wall.tiff");
Texture2D floorTex("carpet.tif");
Texture2D shadowTex("shadow.tif", GL_CLAMP_TO_EDGE);

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, 3, 15);
    
    wall.setTexture(wallTex);
    wall.setTransparency(Transparency::AlphaTestZero);
    room.setTexture(floorTex);
    room.setTexCoords(0,0, 20,10);
    
    glutMainLoop();
    return 0;
    }


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();
    
    wall.drawAll();

/*************** CODE OF INTEREST ******************************/
/* Enable texgen on texture unit 1.                            */
/* Define texgen coefficients that will apply the texture in   */
/* the X/Z plane, but sheared by a factor that changes with    */
/* time.  The shearing is done in just the S component, by     */
/* adding a varying amount of the Z coordinate.                */
/*                                                             */
    glActiveTextureARB(GL_TEXTURE1_ARB);
    glEnable(GL_TEXTURE_GEN_S);
    glEnable(GL_TEXTURE_GEN_T);
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    GLfloat SplaneCoefficients[4] = { .05, 0, 0.05 * currentTime()/10 - 0.1, 0.5 };
    GLfloat TplaneCoefficients[4] = { 0, 0, .1, 0 };
    glTexGenfv(GL_S, GL_EYE_PLANE, SplaneCoefficients);
    glTexGenfv(GL_T, GL_EYE_PLANE, TplaneCoefficients);
    shadowTex.apply();
    glActiveTextureARB(GL_TEXTURE0_ARB);
    
    room.drawAll();

    glActiveTextureARB(GL_TEXTURE1_ARB);
    shadowTex.disable();
    glActiveTextureARB(GL_TEXTURE0_ARB);

    glutSwapBuffers();

    checkGLError("end-of-frame");
    }


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