//--------------------------------------------------------------------------------------
// Copyright (C) 2008 http://shift.delblanco.es
//--------------------------------------------------------------------------------------
// SHIFT Videogame is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 3 of the License, or later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
//--------------------------------------------------------------------------------------
/// \file 3DCamera.h
/// Clase para manejar la cámara 3D de la escena.
/// Fichero con la especificación de los atributos y funciones de las cámara 3D
/// que se pueden situar en la escena
//--------------------------------------------------------------------------------------
#pragma once
#ifndef __C3DCAMERA_H__
#define __C3DCAMERA_H__

//--------------------------------------------------------------------------------------
// Ficheros de cabecera
//--------------------------------------------------------------------------------------
class C3DObjVehicle;

//--------------------------------------------------------------------------------------
// Constantes
//--------------------------------------------------------------------------------------
/// Velocidad de movimiento lineal de la cámara
#define       CAMERA3D_SPEED              4.0f
/// Velocidad de movimiento angular de la cámara
#define       CAMERA3D_A_SPEED            0.1f
/// Tipo de cámara de usuario
#define       CAMERA3D_USER               -1
/// Tipo de cámara libre
#define       CAMERA3D_FREE               0
/// Tipo de cámara persecutoria del juego (tipo 1)
#define       CAMERA3D_GAME_1             1
/// Tipo de cámara persecutoria del juego (tipo 2)
#define       CAMERA3D_GAME_2             2
/// Tipo de cámara persecutoria del juego (tipo 3)
#define       CAMERA3D_GAME_3             3
/// Tipo de cámara persecutoria del juego (tipo 4)
#define       CAMERA3D_GAME_4             4
/// Tipo de cámara persecutoria del juego (tipo 5)
#define       CAMERA3D_GAME_5             5
/// Tipo de cámara persecutoria del juego (tipo 6)
#define       CAMERA3D_GAME_6             6
/// Tipo de cámara persecutoria del juego (tipo 7)
#define       CAMERA3D_GAME_7             7

//--------------------------------------------------------------------------------------
/// Clase para manejar la cámara 3D de la escena.
//--------------------------------------------------------------------------------------
class C3DCamera
{

private:  // Campos miembro

    bool                 m_bInit;               ///< Flag que indica si el objeto está inicializado
    IDirect3DDevice9*    m_pDevice;             ///< Puntero al dispositivo de DirectX

    D3DXMATRIX			 m_ViewMatrix;			///< Matriz de vista
    D3DXMATRIX			 m_ProjectionMatrix;	///< Matriz de proyeccion

    D3DXVECTOR3			 m_Position;			///< Posicion de la camara
    D3DXVECTOR3			 m_Rotation;			///< Rotacion de la camara (sólo para la cámara libre)
    D3DXVECTOR3			 m_To;			        ///< Orientación frontal de la cámara
    D3DXVECTOR3			 m_Up;			        ///< Orientación superior de la cámara

    float				 m_fFOV;				///< Apertura de campo de vision
    float				 m_fZoom;				///< Grado de zoom
    float				 m_fAspect;			    ///< Relacion entre ancho y alto (ancho/alto)
    float				 m_fNear;				///< Plano de corte cercano
    float				 m_fFar;				///< Plano de corte lejano
    bool				 m_bModified;			///< Indica si hay que refrescar las matrices
    bool				 m_bUpdate;				///< Indica si hay que recalcular su posición de manera explícita
    int     			 m_iType;               ///< Tipo de cámara
    int     			 m_iLastType;           ///< Tipo de cámara anterior

public: // Métodos públicos

    /// Constructor
    C3DCamera();
    /// Destructor
    ~C3DCamera();

    /// Carga la cámara ante un CreateDevice
    bool initialize();
    /// Renderiza la cámara ante un FrameRender
    void render();
    /// Actualiza la cámara ante un FrameMove
    void update();
    /// Restaura la cámara ante un ResetDevice
    void restore();
    /// Libera la cámara ante un LostDevice
    void free();
    /// Libera la cámara ante un DestroyDevice
    void Release();

    /// Cambia los parámetros de la cámara para perseguir a un punto
    /// con la posición y velocidad indicadas
    void Follow(C3DObjVehicle *Vehicle);

    /// Funcion observadora del tipo de cámara
    int getType()                           {return m_iType;}
    /// Funcion observadora del último tipo de cámara
    int getLastType()                       {return m_iLastType;}
    /// Funcion observadora de la apertura de campo de vision
    float getFOV()                          {return m_fFOV;}
    /// Funcion observadora de la relación de aspecto entre ancho y alto (ancho/alto)
    float getAspect()                       {return m_fAspect;}
    /// Funcion observadora del plano de corte cercano
    float getNear()                         {return m_fNear;}
    /// Funcion observadora del plano de corte lejano
    float getFar()                          {return m_fFar;}
    /// Funcion observadora del grado de zoom
    float getZoom ()                        {return m_fZoom;}

    /// Establece el tipo de cámara
    void setType(int Type);
    /// Establece el último tipo de cámara
    void setLastType(int Type)              {m_iLastType = Type;}
    /// Toma el siguiente tipo de cámara
    void nextType(void);
    /// Establece la apertura de campo de vision
    void setFOV(float fFOV)                 {m_fFOV=fFOV; m_bModified=true;}
    /// Establece la relación de aspecto entre ancho y alto (ancho/alto)
    void setAspect(float fAspect)           {m_fAspect=fAspect; m_bModified=true;}
    /// Establece el plano de corte cercano
    void setNear(float fNear)               {m_fNear=fNear; m_bModified=true;}
    /// Establece el plano de corte lejano
    void setFar(float fFar)                 {m_fFar=fFar; m_bModified=true;}
    /// Establece el grado de zoom
    void setZoom (float fZoom)              {if(fZoom>=1.0f){ m_fZoom=fZoom; m_bModified=true;}}

    /// Funcion observadora de la posición de la cámara
    void getPosition (D3DXVECTOR3 &vPos)    {vPos=m_Position;}
    /// Establece la posición de la cámara
    void setPosition (D3DXVECTOR3 vPos)     {m_Position=vPos; m_bModified=true;}
    /// Añade un desplazamiento lineal a la posición de la cámara
    void addPosition (D3DXVECTOR3 vPos)     {m_Position+=vPos; m_bModified=true;}

    /// Funcion observadora de la rotación de la cámara (sólo para la cámara libre)
    void getRotation (D3DXVECTOR3 &vRot)    {vRot=m_Rotation;}
    /// Establece la rotación de la cámara (sólo para la cámara libre)
    void setRotation (D3DXVECTOR3 vRot)     {m_Rotation=vRot; m_bModified=true;}
    /// Añade un desplazamiento angular a la rotación de la cámara (sólo para la cámara libre)
    void addRotation (D3DXVECTOR3 vRot)     {m_Rotation+=vRot; m_bModified=true;}

    /// Funcion observadora de la dirección frontal de la cámara
    void getTo (D3DXVECTOR3 &vTo)           {vTo=m_To;}
    /// Establece la dirección frontal de la cámara
    void setTo (D3DXVECTOR3 vTo)            {m_To=vTo; m_bModified=true;}

    /// Funcion observadora de la dirección superior de la cámara
    void getUp (D3DXVECTOR3 &vUp)           {vUp=m_Up;}
    /// Establece la dirección superior de la cámara
    void setUp (D3DXVECTOR3 vUp)            {m_Up=vUp; m_bModified=true;}
};

#endif
