#ifndef LIGHTDESC_H
#define LIGHTDESC_H

#include "ssemath.h"
#include "vector.h"

enum LightType_t
{
	MATERIAL_LIGHT_DISABLE = 0,
	MATERIAL_LIGHT_POINT,
	MATERIAL_LIGHT_DIRECTIONAL,
	MATERIAL_LIGHT_SPOT,
};

enum LightType_OptimizationFlags_t
{
	LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 = 1,
	LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 = 2,
	LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 = 4,
	LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED = 8,
};

struct LightDesc_t
{
	LightType_t m_Type;										 
	Vector m_Color;											  
	Vector m_Position;										    
	Vector m_Direction;										      
	float  m_Range;											    
	float m_Falloff;										      
	float m_Attenuation0;									    
	float m_Attenuation1;									    
	float m_Attenuation2;									    
	float m_Theta;											       
	float m_Phi;											   

	float m_ThetaDot;
	float m_PhiDot;
	unsigned int m_Flags;
protected:
	float OneOver_ThetaDot_Minus_PhiDot;
	float m_RangeSquared;
public:

	void RecalculateDerivedValues(void);			       

	LightDesc_t(void)
	{
	}

	LightDesc_t(const Vector& pos, const Vector& color)
	{
		InitPoint(pos, color);
	}

	LightDesc_t(const Vector& pos, const Vector& color, const Vector& point_at,
		float inner_cone_boundary, float outer_cone_boundary)
	{
		InitSpot(pos, color, point_at, inner_cone_boundary, outer_cone_boundary);
	}

	void InitPoint(const Vector& pos, const Vector& color);
	void InitDirectional(const Vector& dir, const Vector& color);
	void InitSpot(const Vector& pos, const Vector& color, const Vector& point_at,
		float inner_cone_boundary, float outer_cone_boundary);

	void ComputeLightAtPoints(const FourVectors& pos, const FourVectors& normal,
		FourVectors& color, bool DoHalfLambert = false) const;
	void ComputeNonincidenceLightAtPoints(const FourVectors& pos, FourVectors& color) const;
	void ComputeLightAtPointsForDirectional(const FourVectors& pos,
		const FourVectors& normal,
		FourVectors& color, bool DoHalfLambert = false) const;

	void SetupOldStyleAttenuation(float fQuadatricAttn, float fLinearAttn, float fConstantAttn);

	void SetupNewStyleAttenuation(float fFiftyPercentDistance, float fZeroPercentDistance);


	bool IsDirectionWithinLightCone(const Vector& rdir) const
	{
		return ((m_Type != MATERIAL_LIGHT_SPOT) || (rdir.Dot(m_Direction) >= m_PhiDot));
	}

	float OneOverThetaDotMinusPhiDot() const
	{
		return OneOver_ThetaDot_Minus_PhiDot;
	}
};


inline void LightDesc_t::InitPoint(const Vector& pos, const Vector& color)
{
	m_Type = MATERIAL_LIGHT_POINT;
	m_Color = color;
	m_Position = pos;
	m_Range = 0.0;									 
	m_Attenuation0 = 1.0;
	m_Attenuation1 = 0;
	m_Attenuation2 = 0;
	RecalculateDerivedValues();
}


inline void LightDesc_t::InitDirectional(const Vector& dir, const Vector& color)
{
	m_Type = MATERIAL_LIGHT_DIRECTIONAL;
	m_Color = color;
	m_Direction = dir;
	m_Range = 0.0;									 
	m_Attenuation0 = 1.0;
	m_Attenuation1 = 0;
	m_Attenuation2 = 0;
	RecalculateDerivedValues();
}


inline void LightDesc_t::InitSpot(const Vector& pos, const Vector& color, const Vector& point_at,
	float inner_cone_boundary, float outer_cone_boundary)
{
	m_Type = MATERIAL_LIGHT_SPOT;
	m_Color = color;
	m_Position = pos;
	m_Direction = point_at;
	m_Direction -= pos;
	VectorNormalizeFast(m_Direction);
	m_Falloff = 5.0;										   
	m_Theta = inner_cone_boundary;
	m_Phi = outer_cone_boundary;

	m_Range = 0.0;										 

	m_Attenuation0 = 1.0;
	m_Attenuation1 = 0;
	m_Attenuation2 = 0;
	RecalculateDerivedValues();
}


#endif
