#pragma once

#include "ShadowMapping.h"
#include "SceneObject.h"
#include "ShadowRenderList.h"
#include "SpatialPartitioningTree.h"
#include "ShadowScene.h"

class DirectionalLight : public SceneObject
{
	DXVector3		m_Dir;
	DXColor			m_Color;

	ShadowMapping* m_pSM;
	
	ShadowRenderList m_RLShadowCasters;

	//DynamicStack<SceneObject*>	m_ShadowCasters;

	int m_PassesDone;

	Frustum m_LightFrustum;
	//unsigned m_NumPlanes;
	//DXPlane m_Bound[5 + 6]; //maximum 5 planes of view frustum can bound the light + 6 of the light frustum itself
	BoundingMesh* m_ExactBound; //exact mesh of light view
	OBB m_BoxLVS; //simple bound of light view

	float m_ShadowFar;
	DXVector3 m_ShadowFarPoint;
	DXVector3 m_ShadowFarPlaneNormal;

	AABB m_Universe; //use this fake bound that is always visible, because this directinal light is everywhere

	//static void GatherShadowCasters(SpatialPartitioningTreeNode* const pNode, void* pData)
	//{
	//	FOREACH(obj, pNode->m_Objects, SceneObject)
	//	{
	//		obj->GetInfo()->AddToShadowRenderList(((DirectionalLight*)pData)->m_RLShadowCasters);
	//	}
	//}

public:

	static void GatherShadowCasters(SceneObject* const pObj, void* pData)
	{
		DirectionalLight* light = (DirectionalLight*)pData;

		if (light->GetScene()->GetShadowApp()->GetDrawObjects() || dynamic_cast<TerrainPatch*>(pObj))
		{
			pObj->AddToShadowRenderList(light->m_RLShadowCasters);
		}
	}

	DirectionalLight(ShadowScene* const pScene);
	~DirectionalLight(void);

	void UpdateShadowBound(const Camera& cam);

	void SetDirection(const DXVector3& dir) { m_Dir = dir; }
	DXVector3 GetDirection(void) const { return m_Dir; }

	void SetColor(const DXColor& col) { m_Color = col; }
	DXColor GetColor(void) const { return m_Color; }

	//update must be done when visible bound is known
	void Update(void);

	void RenderShadowMap(void);
	void RenderShadowMap(RenderList& rl);

	const IBoundingVolume& GetBoundingVolume(void) const { return m_Universe; }

	OBB GetShadowFrustum(void) const { return m_BoxLVS; }

	void UpdateShadowFarPlane(const BoundingMesh* const b);

	const Frustum& GetLightFrustum(void) const { return m_LightFrustum; }

	float GetShadowFar(void) const { return m_ShadowFar; }
	DXVector3 GetShadowFarPoint(void) const { return m_ShadowFarPoint; }
	DXVector3 GetShadowFarPlaneNormal(void) const { return m_ShadowFarPlaneNormal; }

	void CullShadowCasterRenderJobs(const DXPlane& p) { m_RLShadowCasters.CullJobsByPlane(p); }
	int GetShadowCasterCount(void) const { return m_RLShadowCasters.GetJobCount(); }
	const RenderList& GetShadowCasters(void) const { return m_RLShadowCasters; }
	void ClearRenderList(void) { m_RLShadowCasters.Clear(); }

	int GetPassesDone(void) const { return m_PassesDone; }
};
