//--------------------------------------------------------------------------------------
// 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 3DObject.h
/// Para manejar los objetos de la escena.
/// Cada objeto de la escena puede tener asociado: un área de colisión,
/// un sistema físico, un modelo gráfico, una lista de objetos que lo componen.
/// Este módulo implementa todas las operaciones para gestionar el objeto
//--------------------------------------------------------------------------------------
#pragma once
#ifndef __C3DOBJECT_H__
#define __C3DOBJECT_H__

//--------------------------------------------------------------------------------------
// Ficheros de cabecera
//--------------------------------------------------------------------------------------
#include <vector>

#include "3DMesh.h"
#include "3DCollision.h"
#include "3DPhysics.h"
#include "3DSound.h"
#include "3DParticle.h"
#include "XMLIO.h"

//--------------------------------------------------------------------------------------
// Constantes
//--------------------------------------------------------------------------------------
/// Tipo de objeto colisionable móvil
#define     OBJECT_TYPE_MOBILE			1
/// Tipo de objeto colisionable fijo con física
#define     OBJECT_TYPE_PHYSICS			2
/// Tipo de objeto colisionable fijo sin física
#define     OBJECT_TYPE_FIXED			3
/// Tipo de objeto no colisionable
#define     OBJECT_TYPE_NOCOLL			4

//--------------------------------------------------------------------------------------
/// Clase base para manejar los objetos de la escena.
//--------------------------------------------------------------------------------------
class C3DObject
{

protected:  // Campos miembro

    bool                            m_bInit;                ///< Flag que indica si el objeto está inicializado
    bool				            m_bEnabled;		    	///< Estado de procesamiento de un objeto

    C3DObject                       *m_pParent;             ///< Puntero al objeto padre (NULL si no hay padre)

    C3DMesh                         *m_pMesh;               ///< Modelo gráfico asociado al objeto
    C3DCollision                    *m_pCollision;          ///< Sistema de colisiones asociado al objeto
    C3DPhysics                      *m_pPhysics;            ///< Sistema físico asociado al objeto
    C3DSound                        *m_pSound;              ///< Sonido asociado al objeto
    std::vector<C3DObject*>         *m_paObjets;            ///< Lista de objetos que componen el resto del objeto

    D3DXMATRIX						m_Transformation;       ///< Matriz de transformacion final neta
    D3DXVECTOR3			            *m_pScale;			    ///< Vector del escalado
    D3DXVECTOR3			            *m_pRotation;			///< Vector de la rotacion
    D3DXVECTOR3			            *m_pPosition;			///< Vector de la posicion
    bool				            m_bModified;			///< Indica si el objeto fue modificado tras la última iteración
    bool				            m_bLastModified;		///< Indica si el objeto fue modificado en esta última iteración
	int								m_iTypeObject;			///< Tipo de objeto (móvil, fijo con física, fijo sin física, no colisionable)

	C3DParticles					*m_pParticles1;			///< Sistema de partículas primario
    D3DXVECTOR3			            *m_pParticles1Pos;		///< Vector de posicion relativa del sistema de partículas primario
	C3DParticles					*m_pParticles2;			///< Sistema de partículas secundario
    D3DXVECTOR3			            *m_pParticles2Pos;		///< Vector de posicion relativa del sistema de partículas secundario

    /// Carga la configuración a partir de la ruta del fichero XML
    /// (colisiones + física + modelo gráfico + resto de objetos)
    bool load(LPCWSTR ObjectPath);
    /// Carga la configuración a partir de un lector de XML
    /// (colisiones + física + modelo gráfico + resto de objetos)
    bool load(CXMLIO *myXMLIO);

    /// Para indicar al objeto que debe de reactualizar las matrices
    void setModified(void);
    /// Refresca la transformación actual del objeto, sólo si es necesario
    void refreshTransformation(void);

public: // Métodos públicos

    /// Constructor
    C3DObject();
    /// Destructor
    ~C3DObject();

    /// Inicializa el objeto a partir de la ruta del fichero XML
    /// (colisiones + física + sonido + modelo gráfico + resto de objetos)
    bool initialize(C3DObject *dParent, LPCWSTR ObjectPath);
    /// Inicializa el objeto a partir de un lector de XML
    /// (colisiones + física + sonido + modelo gráfico + resto de objetos)
    bool initialize(C3DObject *dParent, CXMLIO *myXMLIO);

    /// Renderiza el objeto
    /// (modelo gráfico + resto de objetos)
    void render();
    /// Actualiza el objeto
    /// (colisiones + física + sonido + resto de objetos)
    void update();
    /// Libera el objeto
    /// (colisiones + física + sonido + modelo gráfico + resto de objetos)
    void Release();        

    /// Función observadora del modelo gráfico asociado
    C3DMesh *getMesh(void);
    /// Función observadora de la colisión asociada
    C3DCollision *getCollision(void);
    /// Función observadora de la física asociada
    C3DPhysics *getPhysics(void);
    /// Función que indica si el objeto tiene o no física asociada
    bool hasPhysics(void)								{return (m_pPhysics!=NULL);}
    /// Función observadora del sonido asociado
    C3DSound *getSound(void);
    /// Función observadora de la lista de objetos que componen el objeto
    std::vector<C3DObject*> *getObjects(void);

	/// Función observadora del tipo de objeto (móvil, fijo con física, fijo sin física, no colisionable)
	int getTypeObject(void)								{return m_iTypeObject;}

    /// Obtiene la transformacion actual del objeto
    D3DXMATRIX *getTransformation(void)					{return &m_Transformation;}
    /// Toma o calcula la inversa de la transformacion actual del objeto
    D3DXMATRIX *calculateTransInv(D3DXMATRIX *result);

	/// Función para obtener el sistema de partículas primario
	C3DParticles *getParticles1(void)					{return m_pParticles1;}
	/// Función para obtener el sistema de partículas secundario
	C3DParticles *getParticles2(void)					{return m_pParticles2;}

    /// Función para cambiar el estado de procesamiento de un objeto, activado/desactivado
    void setEnabled(bool enabled);
    /// Función tomar el estado de procesamiento de un objeto, activado/desactivado
    bool getEnabled(void)                               {return m_bEnabled;}
	/// Función tomar el flag de modificación del objeto tras la última iteración
    bool getModified(void)                              {return m_bModified;}
	/// Función tomar el flag de modificación del objeto en esta última iteración
    bool getLastModified(void)                          {return m_bLastModified;}

    /// Establece el escalado del objeto
	void setScale(D3DXVECTOR3 &Vec);
    /// Toma el escalado actual del objeto
	void getScale(D3DXVECTOR3 &Vec);
    /// Elimina el escalado actual del objeto
    void resetScale(void)                               {SAFE_DELETE(m_pScale);}

    /// Establece la rotación del objeto
	void setRotation(D3DXVECTOR3 &Vec);
    /// Toma la rotación actual del objeto
	void getRotation(D3DXVECTOR3 &Vec);
    /// Elimina la rotación actual del objeto
    void resetRotation(void)                            {SAFE_DELETE(m_pRotation);}

    /// Establece la posición del objeto
    void setPosition(D3DXVECTOR3 &Vec);
    /// Toma la posición actual del objeto
    void getPosition(D3DXVECTOR3 &Vec);
    /// Elimina la posición actual del objeto
    void resetPosition(void)                            {SAFE_DELETE(m_pPosition);}

    /// Añade un escalado al objeto
	void addScale(D3DXVECTOR3 &Vec);
    /// Añade una posición al objeto para aplicar antes de la rotación
	void addPrePosition(D3DXVECTOR3 &Vec);
    /// Añade una rotación al objeto
	void addRotation(D3DXVECTOR3 &Vec);
    /// Añade una posición al objeto
    void addPosition(D3DXVECTOR3 &Vec);

	/// Manejador de colisión básica
	virtual bool onQuickCollision(C3DObject *object)	{return true;}
	/// Manejador de colisión completa
	virtual bool onFullCollision(C3DObject *object)		{return true;}
};

#endif
