//===============================================================================
// @ Player.cpp
// ------------------------------------------------------------------------------
// Player
//
// Copyright (C) 2004 by Elsevier, Inc. All rights reserved.
//
//
//
// This example demonstrates basic geometry rendering, using the 
// "vertex-at-a-time", or immediate rendering mode.  It also shows how geomety
// can be represented by a set of points, lines, or triangles, with the latter-
// most providing the most realistic, solid appearance.
//
// The key commands are:
//
// i, k - translate in x
// j, l - translate in y
// u, o - rotate around z axis
// p, ; - uniformly scale
// Space - reset transforms
// d - change draw mode (cycles through triangles, points, and lines)
//
//===============================================================================

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

#include <IvEventHandler.h>
#include <IvGLHelp.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;
    mTranslate.Zero();

    mRadius = 3.0f;

    mDrawMode = GL_FILL;

}   // End of Player::Player()


//-------------------------------------------------------------------------------
// @ Player::~Player()
//-------------------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------------------
Player::~Player()
{
}   // 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.RotationZ(r);
    mRotate = rotate*mRotate;
    
    // set up translation
    IvVector3 xlate;
    xlate.Zero();
    if (IvGame::mGame->mEventHandler->IsKeyDown('k'))
    {
        xlate.x -= 3.0f*dt;
    }
    if (IvGame::mGame->mEventHandler->IsKeyDown('i'))
    {
        xlate.x += 3.0f*dt;
    }
    if (IvGame::mGame->mEventHandler->IsKeyDown('l'))
    {
        xlate.y -= 3.0f*dt;
    }
    if (IvGame::mGame->mEventHandler->IsKeyDown('j'))
    {
        xlate.y += 3.0f*dt;
    }
    mTranslate += xlate;
    
    // clear transform
    if (IvGame::mGame->mEventHandler->IsKeyDown(' '))
    {
        mRotate.Identity();
        mScale = 1.0f;
        mTranslate.Zero();
    }

    // change draw mode
    if (IvGame::mGame->mEventHandler->IsKeyDown('d'))
    {
        switch (mDrawMode)
        {
        case GL_FILL:
            mDrawMode = GL_POINT;
            break;
        case GL_POINT:
            mDrawMode = GL_LINE;
            break;
        case GL_LINE:
            mDrawMode = GL_FILL;
            break;
        };

        // clear keystroke
        IvGame::mGame->mEventHandler->KeyUp('d');
    }

}   // 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) = mTranslate.x;
    transform(1,3) = mTranslate.y;
    transform(2,3) = mTranslate.z;
    
    // store current matrix
    glPushMatrix();

    // multiply by transform
    glMultMatrixf(transform);

    // turn on the lights and set the material colors
    glEnable( GL_LIGHTING );
    glEnable( GL_NORMALIZE );
    glDisable(GL_COLOR_MATERIAL);
    IvVector4 red(1.0f, 0.0f, 0.0f, 1.0f);
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, (float*) &red);

    // set the draw mode
    glPolygonMode(GL_FRONT, mDrawMode);

    // draw geometry
    DrawSphere();

    glDisable( GL_LIGHTING );

    // restore original matrix          
    glPopMatrix();
}   // End of Player::Render()



//-------------------------------------------------------------------------------
// @ Player::DrawSphere()
//-------------------------------------------------------------------------------
// Draw sphere centered around the origin
//-------------------------------------------------------------------------------
void 
Player::DrawSphere()                                    
{
    int steps = 32;
    const float phiIncrement = kPI / steps;
    const float thetaIncrement = kTwoPI / steps;

    int i;
    for (i = 0; i < steps; i++)
    {
        float phi = phiIncrement * i - kHalfPI;

        // draw everything after this as a triangle strip
        glBegin(GL_TRIANGLE_STRIP);

        float ringBot, cosPhi;
        IvSinCos(phi, ringBot, cosPhi);

        float ringTop, cosPhiInc;
        IvSinCos(phi + phiIncrement, ringTop, cosPhiInc);

        // Each triangle strip is a ring around the sphere at a fixed latitude
        // Each loop iteration below generates two points, the top and
        // bottom points of the stripe at that longitude
        int j;
        for (j = 0; j <= steps; j++)
        {
            float theta = kTwoPI - thetaIncrement * j;

            float sinTheta, cosTheta;
            IvSinCos(theta, sinTheta, cosTheta);

            IvVector3 xyz;
            IvVector3 normal;
    
            normal.x = cosTheta * cosPhi;
            normal.y = sinTheta * cosPhi;
            normal.z = ringBot;

            // position is just a scaled version of the normal
            xyz = mRadius * normal;

            glNormal3fv(&normal.x);
            glVertex3fv(&xyz.x);

            normal[0] = cosTheta * cosPhiInc;
            normal[1] = sinTheta * cosPhiInc;
            normal[2] = ringTop;

            xyz = mRadius * normal;

            glNormal3fv(&normal.x);
            glVertex3fv(&xyz.x);
        }
    
        // end triangle strip
        glEnd();
    }
}   // End of Player::DrawSphere()




