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

  Yet another example of texgen + multitexturing + lightmapping.
  This program is a multitextured version of lightmap2.cpp.
  The lightmapping method is the same as in lightmap2 - it
  applies a circular lighting texture, with texture coordinates
  generated to place it directly under the moving light source.
  In this case the lightmap uses the second texture unit, so that
  objects can have their own color textures as well.

*****************************************************************/
#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 createScene(Object& root);
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;
Object root;
QuadricObject *lightSource;
SimpleTransform lightPos;

Texture2D lightTex("lightcircle.tif", GL_CLAMP);


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);
    createScene(root);
    
    glutMainLoop();
    return 0;
    }


void createScene(Object& root)
    {
    QuadricObject *ball = new QuadricObject;
    ball->makeSphere(1.0, 32, 16);
    ball->setTexture(*(new Texture2D("rock.tiff")));
    ball->setUseTexture(GL_TRUE);
    SimpleTransform *xform = new SimpleTransform;
    xform->setTranslation(-4, 0, 0);
    ball->setTransform(*xform);
    root.attach(*ball);
    
    Square *square = new Square(-10, -10, 10, 10, DMS_Y);
    square->setTexture(*(new Texture2D("bigpble.tiff", GL_REPEAT, GL_LINEAR_MIPMAP_LINEAR)));
    square->setTexCoords(0,0, 4,4);
    root.attach(*square);
        
    lightSource = new QuadricObject;
    lightSource->makeSphere(0.1, 8, 6);
    lightSource->setMaterial(*(new Material(Color::White)));
    lightSource->material().setEmission(Color::White);
    lightSource->setTransform(lightPos);
    
    glActiveTextureARB(GL_TEXTURE1_ARB);
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glActiveTextureARB(GL_TEXTURE0_ARB);
    }


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

    float x = sin(currentTime())*5;
    float z = cos(currentTime())*2.5;
    lightPos.setTranslation(x, 2, z);

    glActiveTextureARB(GL_TEXTURE1_ARB);
    glEnable(GL_TEXTURE_GEN_S);
    glEnable(GL_TEXTURE_GEN_T);
    GLfloat SplaneCoefficients[4] = { .1, 0, 0, 0 };
    GLfloat TplaneCoefficients[4] = { 0, 0, .1, 0 };
    SplaneCoefficients[3] = -x * 0.1 + 0.5;
    TplaneCoefficients[3] = -z * 0.1 + 0.5;
    glTexGenfv(GL_S, GL_EYE_PLANE, SplaneCoefficients);
    glTexGenfv(GL_T, GL_EYE_PLANE, TplaneCoefficients);
    
    lightTex.apply();
    glActiveTextureARB(GL_TEXTURE0_ARB);
    
    root.drawAll();

    lightTex.disable();
    glDisable(GL_TEXTURE_GEN_S);
    glDisable(GL_TEXTURE_GEN_T);

    lightSource->drawAll();

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