/*****************************************************************
  multitex3b.cpp
  by Dave Pape
  3 April 2003

  An additional example of texgen + multitexturing + lightmapping.
  In this case most of the scene is lit, and the texture represents
  the shadow of the tree rather than the light coming through a
  window.  In implementation this is exactly the same as in
  multitexture3.cpp, the only important factor is the texels at
  the edges of the lightmap image - since the lightmap is clamped,
  the edge texels are the ones that will be applied to all areas
  of the scene outside of the small region that gets the main part
  of the texture.

  This program also points out the results of using texgen
  coefficients that apply the lightmap texture in the X/Z direction,
  with no effect from the Y coordinate of objects - when the
  shadow is cast on the vertical sides of the pillar, the shadow
  will be smeared down it improperly.  By changing the texgen
  coefficients to also shear the texture in Y - to modify the
  T texture coordinate by the Y geometric coordinate - we
  get a better result.

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

Square tree(-2, -0.1, 2, 6, DMS_Z);
Square grass(-10, -10, 10, 10, DMS_Y);
Texture2D treeTex("tree.tiff", GL_CLAMP);
Texture2D shadowTex("treeShadow.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, -10);
    camera.setYRotation(180);
    
    tree.setTexture(treeTex);
    tree.setTransparency(Transparency::AlphaTestZero);

    grass.setTexture(*(new Texture2D("grass.tiff", GL_REPEAT, GL_LINEAR_MIPMAP_LINEAR)));
    QuadricObject pillar;
    pillar.makeCylinder(0.75, 0.75, 3, 24, 1, DMS_Y);
    pillar.setTexture(*(new Texture2D("rock.tiff")));
    pillar.setUseTexture(GL_TRUE);
    SimpleTransform *xform = new SimpleTransform;
    xform->setTranslation(-2, 0, 3);
    pillar.setTransform(*xform);
    grass.attach(pillar);
    
    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();

    tree.drawAll();

    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] = { .25, 0, 0.125 * currentTime()/10 - 0.25, 0.5 };
/*************** CODE OF INTEREST ******************************/
/* Shear the texture generation by adding a bit of Y to the    */
/* T coordinate.  Without the shearing, the texture is applied */
/* 'straight down'.                                            */
/*                                                             */
#if 1
    GLfloat TplaneCoefficients[4] = { 0, 0, .2, -0.01 };
#else
    GLfloat TplaneCoefficients[4] = { 0, 0.2, .2, -0.01 };
#endif
    glTexGenfv(GL_S, GL_EYE_PLANE, SplaneCoefficients);
    glTexGenfv(GL_T, GL_EYE_PLANE, TplaneCoefficients);
    shadowTex.apply();
    glActiveTextureARB(GL_TEXTURE0_ARB);
    
    glColor3f(1,1,1);
    grass.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)
    {
    root.updateAll();
    glutPostRedisplay();
    }

