
//
// Asura_Projector.h
//
// Created by Dave Reed - 05/01/2007 
// 
// Copyright (C) 2007 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __ASURA_PROJECTOR_H__
#define __ASURA_PROJECTOR_H__

#ifdef ASURA_TARGET_SM3

#include "Core/Asura_Maths.h"
#include "Core/Asura_TextureManagement.h"
#include "Shadows/Asura_Shadow_System.h"
#if defined( ASURA_USE_NEW_VISIBILITY_SYSTEM )
#include "Visibility/Asura_Visibility_System.h"
#endif

enum Asura_Projector_Type
{
	ASURA_PROJECTOR_TYPE_PARALLEL	 = 0,
	ASURA_PROJECTOR_TYPE_PERSPECTIVE = 1,
};


enum Asura_Projector_BlendMode
{
	ASURA_PROJECTOR_BLEND_ADD		 = 0,
	ASURA_PROJECTOR_BLEND_MULTIPLY,
	ASURA_PROJECTOR_BLEND_MULTIPLYX2,
	ASURA_PROJECTOR_BLEND_STANDARD
};

class Asura_Projector
{

friend class Asura_Projector_System;
friend class Asura_ClientEntity_Projector;
friend class Asura_ClientEntity_DynamicLight;
friend class Asura_ClientContainerInstance_Projector;

public:
	Asura_Projector()
	{
		 ResetToDefaults();
	}

	void ResetToDefaults()
	{
		m_xPos				  = Asura_Vector_3(0,0,0);
		m_xOrient.Identity();
		m_eType				  = ASURA_PROJECTOR_TYPE_PERSPECTIVE;
		m_eBlendMode		  = ASURA_PROJECTOR_BLEND_MULTIPLYX2;
		m_fFoV				  = 3.142f/4.0f;
		m_fMinRange			  = 1.0f;
		m_fMaxRange			  = 20.0f;		

		m_fUVAspect			  = 1.0f;
		m_fScale			  = 1.0f;		
		m_fDetailTextureScale = 4.0f;

		m_iTextureIndex		  = ASURA_TEXTURE_NONE;
		m_iFalloffTextureIndex= ASURA_TEXTURE_NONE;
		m_iDetailTextureIndex = ASURA_TEXTURE_NONE;

		m_bFakeLight		  = false;
		m_bDynamicLight       = false;
		m_bDynamicSpotlight	  = false;
		m_fAngularFalloffOfs  = 0.0f;
		m_fAngularFalloffScale= 1.0f;

		m_fDistFadeStart      = 50.0f;
		m_fDistFadeRange      = 10.0f;
		m_fIntensity		  = 1.0f;

		m_fFalloffScale		  = 1.0f;
		m_fFalloffPower		  = 1.0f;

		m_afRGB[0]			  = 1.0f;			
		m_afRGB[1]			  = 1.0f;			
		m_afRGB[2]			  = 1.0f;

		m_fUScrollSpeed		  = 0.0f;
		m_fVScrollSpeed		  = 0.0f;
		m_fUScrollRange		  = 0.0f;
		m_fVScrollRange		  = 0.0f;

		m_fUScrollOfs		  = 0.0f;
		m_fVScrollOfs		  = 0.0f;

		m_bUseLimitingPlane   = false;
		m_xLimitingPlanePos   = Asura_Vector_3(0,0,0);
		m_xLimitingPlaneNormal= Asura_Vector_3(0,-1.0f,0);
		
		#if !defined( ASURA_USE_NEW_VISIBILITY_SYSTEM )
		m_iLastKnownModule    = -1;
		#endif

		UpdateVertices();		
	};

	void SetTextureIndex		( int iTextureIndex)					{ m_iTextureIndex = iTextureIndex; }
	void SetFalloffTextureIndex	( int iTextureIndex)					{ m_iFalloffTextureIndex = iTextureIndex; }
	void SetDetailTextureIndex	( int iTextureIndex)					{ m_iDetailTextureIndex = iTextureIndex; }
	void SetFakeLight			( bool bInput )							{ m_bFakeLight = bInput; }
	void SetDynamicLight		( bool bInput )							{ m_bDynamicLight = bInput; }
	void SetDynamicSpotLight	( bool bInput )							{ m_bDynamicSpotlight = bInput; }
	void SetType				( Asura_Projector_Type eInput )			{ m_eType = eInput; }
	void SetScale				( float fScale )						{ m_fScale = fScale; }
	void SetIntensity			( float fIntensity )					{ m_fIntensity = fIntensity; }
	void SetBlendMode			( Asura_Projector_BlendMode eBlendMode ){ m_eBlendMode = eBlendMode; }
	void SetPosition			( const Asura_Vector_3& xInput)			{ m_xPos = xInput; }
	void SetOrientation			( const Asura_Matrix_3x3& xInput)		{ m_xOrient = xInput; }	
	void SetFOV					( float fFoV )							{ m_fFoV = fFoV; }
	void SetRange				( float fMin, float fMax)				{ m_fMinRange = fMin; m_fMaxRange = fMax;}
	void SetFade				( float fStart, float fRange)			{ m_fDistFadeStart = fStart; m_fDistFadeRange = fRange;}
	void SetRGB					( float fRed, float fGreen, float fBlue){ m_afRGB[0] = fRed; m_afRGB[1] = fGreen; m_afRGB[2] = fBlue;}	
	void SetLimitingPlane		( Asura_Vector_3 &xPos,	Asura_Vector_3 &xDir) { m_xLimitingPlanePos=xPos; m_xLimitingPlaneNormal=xDir;}						
	void EnableLimitingPlane	( bool bEnable )						{ m_bUseLimitingPlane = bEnable; }
	
	void SetSpotlightAngularFalloff(float fInnerAngle, float fOuterAngle);

	float GetMaxRange(void) const {return m_fMaxRange;}
	int	  GetHandle(void)	const {return m_iHandle;}
	
	Asura_Bounding_Box& GetBoundingBox(void) {return m_xBB;}
	const Asura_Bounding_Box& GetBoundingBox(void) const {return m_xBB;}

	void UpdateVertices();	
	void SetLookAt(Asura_Vector_3 xFrom, Asura_Vector_3 xAt, Asura_Vector_3 xUp);
	void RenderFrustum();
	bool PointInFrustum(Asura_Vector_3 xPoint, float fThresholdDist = 0.0f) const;
	float FrustumFade(Asura_Vector_3 xPoint) const;

	const Asura_ShadowParameters& GetShadowParameters(void) const
	{
		return m_xShadowParams;
	}

	void SetShadowParameters(const Asura_ShadowParameters& xParams) 
	{
		m_xShadowParams = xParams;
	}

	const Asura_Vector_3&		GetPosition(void)			const { return m_xPos; }
	float						GetDistFadeStart(void)		const { return m_fDistFadeStart; }
	float						GetDistFadeRange(void)		const { return m_fDistFadeRange; }
	bool						IsDynamicLight(void)		const { return m_bDynamicLight; }
	bool						IsFakeLight(void)			const { return m_bFakeLight; }
	bool						IsDynamicSpotlight(void)	const { return m_bDynamicSpotlight; }
	int							GetTextureIndex(void)		const { return m_iTextureIndex; }
	int							GetDetailTextureIndex(void)	const { return m_iDetailTextureIndex; }
	float						GetAngularFalloffOfs(void)	const { return m_fAngularFalloffOfs; }
	float						GetAngularFalloffScale(void)const { return m_fAngularFalloffScale; }
	float						GetFalloffScale(void)		const { return m_fFalloffScale; }
	float						GetFalloffPower(void)		const { return m_fFalloffPower; }
	const Asura_Vector_3*		GetVertices(void)			const { return m_axVertices; }
	Asura_Projector_BlendMode	GetBlendMode(void)			const { return m_eBlendMode; }
	float						GetMinRange(void)			const { return m_fMinRange; }
	const Asura_Matrix_3x3&		GetOrient(void)				const { return m_xOrient; }
	Asura_Projector_Type		GetType(void)				const { return m_eType; }
	float						GetFoV(void)				const { return m_fFoV; }
	float						GetScale(void)				const { return m_fScale; }
	float						GetUVAspect(void)			const { return m_fUVAspect; }
	const float*				GetRGB(void)				const { return m_afRGB; }
	float						GetIntensity(void)			const { return m_fIntensity; }
	float						GetUScrollOfs(void)			const { return m_fUScrollOfs; }
	float						GetVScrollOfs(void)			const { return m_fVScrollOfs; }
	float						GetDetailTextureScale(void)	const { return m_fDetailTextureScale; }

	#if defined( ASURA_USE_NEW_VISIBILITY_SYSTEM )
	bool IsVisible( void )
	{
		return m_xVisibilityQuery.IsAABBVisibleFromCurrentCamera( m_xBB );
	}
	#endif	
private:

	bool				 ClipToLimitingPlane(Asura_Vector_3 &xNearPoint, Asura_Vector_3 &xFarPoint, Asura_Vector_3 &xClippedPoint);	

	int					 m_iHandle;

	Asura_Vector_3		 m_xPos;
	Asura_Matrix_3x3	 m_xOrient;
	Asura_Projector_Type m_eType;
	Asura_Projector_BlendMode m_eBlendMode;

	float				 m_fFoV;
	float				 m_fMinRange;
	float				 m_fMaxRange;

	float                m_fUVAspect;
	float				 m_fScale;
	bool				 m_bFakeLight;
	bool				 m_bDynamicLight;
	float			     m_fDetailTextureScale;
	float				 m_fIntensity;

	int					 m_iTextureIndex;
	int				     m_iFalloffTextureIndex;
	int				     m_iDetailTextureIndex;
	
	float				 m_fDistFadeStart;
	float				 m_fDistFadeRange;

	bool				 m_bDynamicSpotlight;
	float				 m_fAngularFalloffOfs;
	float				 m_fAngularFalloffScale;

	float				 m_fFalloffScale;
	float				 m_fFalloffPower;

	float                m_afRGB[3];

	float				 m_fUScrollSpeed;
	float				 m_fVScrollSpeed;
	float				 m_fUScrollRange;
	float				 m_fVScrollRange;

	float				 m_fUScrollOfs;
	float				 m_fVScrollOfs;

	bool				 m_bUseLimitingPlane;
	Asura_Vector_3		 m_xLimitingPlanePos;
	Asura_Vector_3		 m_xLimitingPlaneNormal;

	Asura_Vector_3       m_axVertices[8];			// The projection frustum

	Asura_Bounding_Box   m_xBB;

	Asura_ShadowParameters m_xShadowParams;

#if defined( ASURA_USE_NEW_VISIBILITY_SYSTEM )
	Asura_Visibility_Query m_xVisibilityQuery;
#else
	int					 m_iLastKnownModule;
#endif
};

#endif //#ifdef ASURA_TARGET_SM3
#endif //__ASURA_PROJECTOR_H__
