//--------------------------------------------------------------------------------------
// 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 3DCollision.h
/// Para manejar las colisiones de los objetos de la escena.
/// Cada objeto de la escena puede tener asociado un área de colisión, todas las
/// operaciones relacionadas con las colisiones se manejan desde este módulo
//--------------------------------------------------------------------------------------
#pragma once
#ifndef __C3DCOLLISION_H__
#define __C3DCOLLISION_H__

//--------------------------------------------------------------------------------------
// Constantes
//--------------------------------------------------------------------------------------
/// Distancia adicional para evitar efecto pegado en la recolocación tras colisiones
#define     COLLISION_EPSILON			0.1f

/// Coeficiente de elasticidad ante colisiones móvil-fijo
#define     COLLISION_E_MF				0.2f
/// Coeficiente de elasticidad ante colisiones móvil-móvil
#define     COLLISION_E_MM				0.2f

/// Tipo de colisión detectada en SRO(1) dónde (2) mete esquina en (1)
#define     COLLISION_TYPE_SRO1			1
/// Tipo de colisión detectada en SRO(2) dónde (1) mete esquina en (2)
#define     COLLISION_TYPE_SRO2			2


class C3DObject;
//--------------------------------------------------------------------------------------
/// Clase para manejar el área de colisión de los objetos de la escena
//--------------------------------------------------------------------------------------
class C3DCollision
{
friend C3DObject;

protected:  // Campos miembro

    bool					m_bInit;            ///< Flag que indica si el objeto está inicializado
    bool					m_bIsVehicle;       ///< Flag que indica si el objeto es un vehículo
    C3DObject				*m_pObject;         ///< Objeto asociado a este área de colisión
    float					m_mass;             ///< Masa del objeto, si es 0.0f el objeto no es móvil
    D3DXVECTOR4				m_v[4];             ///< Los cuatro vértices que determinan el área de colisión 2D (ejes X,Z)
	float					m_radius;			///< Radio de la circunferencia más pequeña que engloba el objeto
	float					m_momentum;			///< Momento de inercia del objeto
    D3DXMATRIX				m_transInv;			///< Inversa de la matriz de transformacion del objeto

    /// Constructor privado, sólo se podrá crear desde una instancia 3DObject
    C3DCollision();
    /// Destructor
    ~C3DCollision();

public: // Métodos públicos

    /// Inicializa el área de colisión
    bool initialize(C3DObject *Object, float dmass);
    /// Comprueba las colisiones del área de colisión con el resto de la escena
    void update();
    /// Libera el área de colisión
    void Release();

    /// Función observadora del objeto asociado
    C3DObject *getObject(void)				{return m_pObject;}

    /// Función observadora del flag que indica si es vehículo
    bool getIsVehicle(void)					{return m_bIsVehicle;}

    /// Establece los cuatro vértices que determinan el área de colisión 2D (ejes X,Z) a partir de un vector dado
    void setV(D3DXVECTOR4 *dv, bool IsVehicle);
    /// Establece los cuatro vértices que determinan el área de colisión 2D (ejes X,Z) a partir de una geometría
    void setV(LPD3DXMESH pMesh, bool IsVehicle);
    /// Función observadora de los cuatro vértices que determinan el área de colisión 2D (ejes X,Z)
    D3DXVECTOR4 *getV(void)                 {return m_v;}

    /// Establece la masa del objeto, si es 0.0f el objeto no es móvil
    void setMass(float dmass)               {m_mass = dmass;}
    /// Función observadora de la masa del objeto, si es 0.0f el objeto no es móvil
    float getMass(void)                     {return m_mass;}

    /// Obtiene la inversa de la transformacion actual del objeto
    D3DXMATRIX *getTransInv(void)           {return &m_transInv;}

	/// Función para comprobar condiciones de colisión triviales (es un método directo)
	bool CheckBasicCollision(C3DCollision *Collision);
	/// Función para comprobar colisiones mediante esferas (es un método rápido pero aproximado)
	bool CheckQuickCollision(C3DCollision *Collision);
	/// Función para comprobar colisiones mediante rectángulos (es un método lento pero más detallado)
	bool CheckFullCollision(C3DCollision *Collision, bool ReplaceElements, bool ExchangePhysics);
};

#endif
