////////////////////////////////////////////////////////////////////////////
//  Camera.h                                                              //
//    A class that manages the camera by storing orientation in a         //
//    quaternion and position in a vector. The class also implements an   //
//    exponential moving average filtering system so that, when the       //
//    filtering is on, there are no discontinuities in camera movement or //
//    rotation. The penalty is a slight lag.                              //
//                                                                        //
//    Call "Init" before use. Call "Update" each frame. Call              //
//    "PrepareForRender" before rendering objects with the camera's view. //
//                                                                        //
//     Singleton name: CAMERA (Access this class by using calls like      //
//     "CAMERA.Update( );". It is still possible to instantiate instances //
//     of the class as well.)                                             //
//                                                                        //
//  Michael Silverman, 2011                                               //
//     Distributed under the Boost Software Licence, Version 1.0.         //
//     http://www.boost.org/LICENSE_1_0.txt                               //
//     http://silverwaregames.com/LICENSE_1_0.txt                         //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

#ifndef Camera_H
#define Camera_H

#include "../PhoenixMainApp.h"

// You must set your compiler to find these included files. You must also link to the appropriate libs.
#include <d3d9.h>
#include <d3dx9.h>
#include <d3dx9mesh.h> 
#include <d3dx9math.h>

#include <windows.h>
#include <windowsx.h>

class Camera  
{
public:
    Camera( bool bFilter = true );

    void RotYaw( float fTheta );
    void RotPitch( float fTheta );
    
    void SetYawPitchRoll( float fYaw, float fPitch, float fRoll);
    void SetAxis( const D3DXVECTOR3 &v3LookAt, 
                  const D3DXVECTOR3 &v3Up,
                  const D3DXVECTOR3 &v3Right );
    void SetRotation( const D3DXQUATERNION &qRotation );

    void SetFocalPoint( const D3DXVECTOR3 &v3FocalPoint, 
                        const D3DXVECTOR3 &v3Up = D3DXVECTOR3(0,1,0) );
    void SetFocalPointAndPosition( const D3DXVECTOR3 &v3FocalPoint, 
                                   const D3DXVECTOR3 &v3Position, 
                                   const D3DXVECTOR3 &v3Up = D3DXVECTOR3(0,1,0) );
    void SetPosition( const D3DXVECTOR3 &v3Position );
    void MoveCamera( const D3DXVECTOR3 &v3Delta );

    D3DXVECTOR3 GetPosition( );
    D3DXVECTOR3 GetLookAt( );
    D3DXVECTOR3 GetRight( );
    D3DXVECTOR3 GetUp( );
    
    D3DXVECTOR3 GetRayCastDirection( ); // Returns a picking vector based on the current mouse position.
    
    D3DXMATRIX GetViewMatrix( );
    
    void PrepareForRender( ); // Sets the DX device's view matrix to match the camera's.

    void Init( ); // Call this before Update or PrepareForRender.
    void Update( ); // Call this once each game frame.

    void SetFiltering( bool bFilter );
    void SetFilterAlpha( float fAlpha ) { m_fFilterAlpha = fAlpha; };

protected:
    D3DXVECTOR3 m_v3Position;
    D3DXQUATERNION m_qRotation;
    
    bool m_bFilter;
    D3DXQUATERNION m_qFilteredRotation;
    D3DXVECTOR3 m_v3FilteredPosition;
    float m_fFilterAlpha;
};

extern Camera CAMERA; // singleton declaration

inline bool IsKeyDown( char cKey )
{
    return true; // TODO: implement this in your own application. You may want to wrap I/O functions in a singleton.
};

inline float GetMouseX( )
{
    return 0; // TODO: implement this in your own application. You may want to wrap I/O functions in a singleton.
};

inline float GetMouseY( )
{
    return 0; // TODO: implement this in your own application. You may want to wrap I/O functions in a singleton.
};

inline unsigned int GetWindowWidth( )
{
    return 1024; // TODO: implement this in your own application. You may want to wrap rendering functions in a singleton.
};

inline unsigned int GetWindowHeight( )
{
    return 768; // TODO: implement this in your own application. You may want to wrap rendering functions in a singleton.
};

inline LPDIRECT3DDEVICE9 GetRenderDevice( )
{
    return NULL; // TODO: implement this in your own application. You may want to wrap rendering functions in a singleton.
};

inline float GetSecFromLastFrame( )
{
    return 1.0f/60.0f; // TODO: implement this in your own application. You may want to wrap timing functions in a singleton.
};

#endif // CAMERA_H