//===============================================================================
// @ Player.cpp
// ------------------------------------------------------------------------------
// Player
//
// Copyright (C) 2004 by Elsevier, Inc. All rights reserved.
//
//
//
// This example demonstrates texture filtering.  The transform keys allow the
// textured quad to be rotated and scaled.  The default (Euro) texture shows the
// artifacts of magnifying a small texture (blurring or blockiness), while the
// checkerboard texture shows the artifacts of minifying a large, high-frequency
// texture (moire patterns).  The filter mode may be changed between nearest and
// bilinear 
//
// The key commands are:
//
// u, o - rotate quad around its normal axis
// ;, p - scale quad larger and smaller
// Space - reset transforms
// f - switch filtering between nearest and bilinear
// t - switch between low-resolution texture and high-resolution texture
//
//===============================================================================

//-------------------------------------------------------------------------------
//-- Dependencies ---------------------------------------------------------------
//-------------------------------------------------------------------------------

#include <IvEventHandler.h>
#include <IvGLHelp.h>
#include <IvImage.h>
#include <IvMath.h>
#include <IvMatrix44.h>

#include "Player.h"
#include "Game.h"

//-------------------------------------------------------------------------------
//-- Static Members -------------------------------------------------------------
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
//-- Methods --------------------------------------------------------------------
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
// @ Player::Player()
//-------------------------------------------------------------------------------
// Constructor
//-------------------------------------------------------------------------------
Player::Player()
{
    mRotate.Identity();
    mScale = 1.0f;

    mTextureID = 0;

    glEnable( GL_TEXTURE_2D );

    // create a texture "name" to reference later
    glGenTextures( 1, &mTextureID );

    glBindTexture( GL_TEXTURE_2D, mTextureID );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

    // Load the Frankfurt Euro image into this texture
    IvImage* image = IvImage::CreateFromFile("euro.tga");
    if (image)
    {
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 
            image->GetWidth(), image->GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, 
            image->GetPixels() );
        delete image;
        image = 0;
    }

    // create a texture "name" to reference later
    glGenTextures( 1, &mCheckerboardTextureID );

    glBindTexture( GL_TEXTURE_2D, mCheckerboardTextureID );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );

    // create checkerboard texture
    const unsigned int size = 128;
    unsigned char pixels[3 * size * size]; // RGB per texel

    unsigned char* tempPixels = pixels;

    unsigned int i, j;
    for (i = 0; i < size; i++)
    {
        for (j = 0; j < size; j++)
        {
            // 1x1 texel squares of black and white
            unsigned char color;
            if ((j + i) % 2)
                color = 255;
            else
                color = 0;

            // set all three components to the same value
            tempPixels[0] = tempPixels[1] = tempPixels[2] = color;
            
            tempPixels += 3;
        }
    }

    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, 
        GL_UNSIGNED_BYTE, pixels );

    glDisable( GL_TEXTURE_2D );

    CreateQuadVertexArrays();

    mBilerp = false;
    mCheckerboard = false;

}   // End of Player::Player()


//-------------------------------------------------------------------------------
// @ Player::~Player()
//-------------------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------------------
Player::~Player()
{
    glDeleteTextures(1, &mTextureID); 
    glDeleteTextures(1, &mCheckerboardTextureID); 
}   // End of Player::~Player()


//-------------------------------------------------------------------------------
// @ Player::Update()
//-------------------------------------------------------------------------------
// Main update loop
//-------------------------------------------------------------------------------
void
Player::Update( float dt )
{
    // get scale, rotate, translate for this frame
    float s = 1.0f;
    float r = 0.0f;
    
    // set up scaling
    if (IvGame::mGame->mEventHandler->IsKeyDown(';'))
    {
        s -= 0.25f*dt;
    }
    if (IvGame::mGame->mEventHandler->IsKeyDown('p'))
    {
        s += 0.25f*dt;
    }
    mScale *= s;
    
    // set up rotate
    if (IvGame::mGame->mEventHandler->IsKeyDown('o'))
    {
        r -= kPI*0.25f*dt;
    }
    if (IvGame::mGame->mEventHandler->IsKeyDown('u'))
    {
        r += kPI*0.25f*dt;
    }
    IvMatrix33 rotate;
    rotate.RotationY(r);
    mRotate = rotate*mRotate;
    
    // clear transform
    if (IvGame::mGame->mEventHandler->IsKeyDown(' '))
    {
        mRotate.Identity();
        mScale = 1.0f;
    }

    // switch filtering mode
    if (IvGame::mGame->mEventHandler->IsKeyDown('f'))
    {
        mBilerp = !mBilerp;

        IvGame::mGame->mEventHandler->KeyUp('f');
    }

    // switch texture
    if (IvGame::mGame->mEventHandler->IsKeyDown('t'))
    {
        mCheckerboard = !mCheckerboard;

        IvGame::mGame->mEventHandler->KeyUp('t');
    }

}   // End of Player::Update()


//-------------------------------------------------------------------------------
// @ Player::Render()
//-------------------------------------------------------------------------------
// Render stuff
//-------------------------------------------------------------------------------
void 
Player::Render()                                    
{   
    // build 4x4 matrix
    IvMatrix44 transform(mRotate);

    transform(0,0) *= mScale;
    transform(1,0) *= mScale;
    transform(2,0) *= mScale;
    transform(0,1) *= mScale;
    transform(1,1) *= mScale;
    transform(2,1) *= mScale;
    transform(0,2) *= mScale;
    transform(1,2) *= mScale;
    transform(2,2) *= mScale;
    transform(0,3) = 0.0f;
    transform(1,3) = 0.0f;
    transform(2,3) = 0.0f;
    
    // store current matrix
    glPushMatrix();

    // multiply by transform
    glMultMatrixf(transform);

    // turn off the lights
    glDisable( GL_LIGHTING );

    glEnable( GL_TEXTURE_2D );

    // Set the desired texture
    if (mCheckerboard)
        glBindTexture( GL_TEXTURE_2D, mCheckerboardTextureID );
    else
        glBindTexture( GL_TEXTURE_2D, mTextureID );

    // Set the desired filtering mode
    if (mBilerp)
    {
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    }
    else
    {
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    }

    // draw geometry
    DrawQuadVertexArrays();

    glDisable( GL_TEXTURE_2D );

}   // End of Player::Render()


//-------------------------------------------------------------------------------
// @ Player::DrawQuadVertexArrays()
//-------------------------------------------------------------------------------
// Draw vertex arrays for a quad centered around the origin
//-------------------------------------------------------------------------------
void
Player::DrawQuadVertexArrays()
{
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glVertexPointer(3, GL_FLOAT, 0, mQuadVerts); 
    glTexCoordPointer(2, GL_FLOAT, 0, mQuadUVs); 
    
    glColor3f(1.0f, 1.0f, 1.0f);

    glDrawElements(GL_TRIANGLE_STRIP, QUAD_INDEX_COUNT, GL_UNSIGNED_SHORT, 
        mQuadIndices);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
} // End of Player::DrawQuadVertexArrays()
    
//-------------------------------------------------------------------------------
// @ Player::CreateQuadVertexArrays()
//-------------------------------------------------------------------------------
// Create vertex arrays for a quad centered around the origin
//-------------------------------------------------------------------------------
void 
Player::CreateQuadVertexArrays()                                    
{
    const float size = 3.0f;

    mQuadVerts[0] = IvVector3(-size, 0, -size);
    mQuadUVs[0] = IvVector2(0.0f, 0.0f);

    mQuadVerts[1] = IvVector3(size, 0, -size);
    mQuadUVs[1] = IvVector2(1.0f, 0.0f);

    mQuadVerts[2] = IvVector3(-size, 0, size);
    mQuadUVs[2] = IvVector2(0.0f, 1.0f);

    mQuadVerts[3] = IvVector3(size, 0, size);
    mQuadUVs[3] = IvVector2(1.0f, 1.0f);
    
    mQuadIndices[0] = 0;
    mQuadIndices[1] = 1;
    mQuadIndices[2] = 2;
    mQuadIndices[3] = 3;
}   // End of Player::CreateQuadVertexArrays()


