#ifndef _RUENTITYWATER_H_
#define _RUENTITYWATER_H_

// Rune entity base
#include "../../Scene/Base/RuEntityBase.h"
#include "../../Scene/Base/RuEntityContainer.h"
#include "../../Scene/Base/RuEntityModel.h"
#include "../../Scene/Controller/RuController_MaterialTexture.h"

#pragma unmanaged

// ************************************************************************************************************************************************************

enum RuWaterEffectType
{
	ruWATERFXTYPE_FULL							= 0,							//!< Full reflection + refraction
	ruWATERFXTYPE_REFLECT						= 1,							//!< Reflection only
	ruWATERFXTYPE_REFRACT						= 2,							//!< Refraction only
	ruWATERFXTYPE_CUBICENV						= 3,							//!< Cubic environment map
	ruWATERFXTYPE_DIFFUSE						= 4,							//!< Diffuse map only
	ruWATERFXTYPE_FORCE_DWORD					= 0x7FFFFFFF
};

// ************************************************************************************************************************************************************

class CRuEntity_Water : public IRuEntity_Container
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	BOOL									m_isOptimizedEntity;

	// Water settings
	RuWaterEffectType						m_effectType;									//!< Water effect type
	float									m_reflectionFactor;								//!< Water reflection factor
	float									m_refractionFactor;								//!< Water refraction factor
	float									m_alphaFactor;									//!< Water alpha factor
	float									m_baseFactor;									//!< Base map factor
	float									m_specularStrength;								//!< Specular strength
	float									m_uvScale;										//!< UV scale
	RUCOLOR									m_baseColor;									//!< Water base color
	INT32									m_baseMapFrames;								//!< Number of frames for the base map texture
	char*									m_baseMapName;									//!< Base map name, frames are build as follows: [m_baseMapName] + "_" + [frame index]
	INT32									m_normalMapFrames;								//!< Number of frames for the normal map texture
	char*									m_normalMapName;								//!< Normal map name, frames are build as follows: [m_normalMapName] + "_" + [frame index]
	INT32									m_cubeMapFrames;								//!< Number of frames for the cube map texture
	char*									m_cubeMapName;									//!< Cube map name, frames are build as follows: [m_normalMapName] + "_" + [frame index]
	float									m_waterQuadSize;								//!< Quad size for the water body, cannot be changed after the water body is initialized
	CRuVector3								m_waterOrigin;									//!< Origin of the water body
	CRuPlane4								m_waterPlane;									//!< Plane of the water

	// Geometry data
	CRuAABB									m_bounds;										//!< Water bounding box
	CRuPolySoup_Quadtree*					m_waterPolys;									//!< Lump of polygons that comprise the water body

	// Model & texture
	CRuMaterial*							m_waterMaterial;
	CRuArrayList<CRuModel *>				m_waterModels;									//!< Visual model representation of the water body

	// Animation
	CRuController_MaterialTexture*			m_baseController;								//!< Controller that alters water base texture
	CRuController_MaterialTexture*			m_causticsController;							//!< Controller that alters water caustics texture

	// Temporary stuff used by BuildWaterModel
	CRuArrayList<INT32> faceCountList;
	CRuArrayList<INT32 *> faceIndexList;

	CRuArrayList<CRuVector3> vertices;
	CRuArrayList<UINT16> indices;

public:
											CRuEntity_Water();
	virtual									~CRuEntity_Water();

	// IRuObject serialization
	virtual IRuObject*						Clone(IRuObject *clonedObject = NULL);
	virtual BOOL							SerializeFrom(IRuStream *stream);
	virtual BOOL							SerializeTo(IRuStream *stream);
	BOOL									SerializeToOptimizedWater(IRuStream *stream);

	// Entity interface
	virtual BOOL							ResetStates();
	virtual BOOL							Update(float elapsedTime);

	// Container interface
	virtual INT32							GetNumEntities();
	virtual CRuEntity*						GetEntity(INT32 index);

	// Collision
	virtual BOOL							QueryCollision(CRuCollisionQuery *colQuery);

	BOOL									HasNoGeometry() const;

	const CRuVector3&						GetWaterBodyOrigin() const;

	// Water body modification
	const CRuAABB&							GetAABB() const;
	BOOL									InitializeWaterBody(const CRuVector3 &initPt, float quadSize);
	BOOL									ExtendWaterBody(const CRuRay3 &expansionRay, float expansionRadius, INT32 tessellationLevel = 1);
	BOOL									ShrinkWaterBody(const CRuRay3 &shrinkRay, float shrinkRadius);
	BOOL									UpdateWaterOrigin();

	RuWaterEffectType						GetEffectType() const;
	float									GetReflectionFactor() const;
	float									GetRefractionFactor() const;
	float									GetAlphaFactor() const;
	float									GetBaseFactor() const;
	float									GetSpecularStrength() const;
	float									GetUVScale() const;
	RUCOLOR									GetBaseColor() const;
	INT32									GetBaseMapFrames() const;
	const char*								GetBaseMapName() const;
	INT32									GetNormalMapFrames() const;
	const char*								GetNormalMapName() const;
	INT32									GetCubeMapFrames() const;
	const char*								GetCubeMapName() const;

	void									SetEffectType(RuWaterEffectType effectType);
	void									SetReflectionFactor(float refFactor);
	void									SetRefractionFactor(float refFactor);
	void									SetAlphaFactor(float alphaFactor);
	void									SetBaseFactor(float baseFactor);
	void									SetSpecularStrength(float specularStrength);
	void									SetUVScale(float uvScale);
	void									SetBaseColor(RUCOLOR color);
	void									SetBaseMapFrames(INT32 frames);
	void									SetBaseMapName(const char *name);
	void									SetNormalMapFrames(INT32 frames);
	void									SetNormalMapName(const char *name);
	void									SetCubeMapFrames(INT32 frames);
	void									SetCubeMapName(const char *name);

protected:
	void									CalculateBounds();
	BOOL									BuildWaterModel(BOOL fastBuild);
	BOOL									BuildTextureControllers();
};

// ************************************************************************************************************************************************************

ruOBJECTMODULE_DEFINE(CRuObjectModule_Entity_Water, CRuEntity_Water)

// ************************************************************************************************************************************************************

#pragma managed

#endif
