#include "MLRHeaders.hpp"

//#############################################################################
//#########################    MLRShadowLight    ################################
//#############################################################################

MLRShadowLight::ClassData*
	MLRShadowLight::DefaultData = NULL;

int shadowCount = 0;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRShadowLight::InitializeClass()
{
	Verify(!DefaultData);
	Verify(gos_GetCurrentHeap() == StaticHeap);
	DefaultData =
		new ClassData(
			MLRShadowLightClassID,
			"MidLevelRenderer::MLRShadowLight",
			MLRInfiniteLightWithFalloff::DefaultData
		);
	Register_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRShadowLight::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRShadowLight::MLRShadowLight() :
	MLRInfiniteLightWithFalloff(DefaultData)
{
	Verify(gos_GetCurrentHeap() == LightsHeap);
	lightMap = NULL;
// MSL 5.02 Shadow
//		
// 	Needed a way to clip out a shadow when it is out of range.
//  Out of range is when it is past the fogend setting of the current mission.
//
	showShadow = true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRShadowLight::MLRShadowLight(
	Stuff::MemoryStream *stream,
	int version
) :
	MLRInfiniteLightWithFalloff(DefaultData, stream, version)
{
	Check_Object(stream);
	Verify(gos_GetCurrentHeap() == LightsHeap);
	lightMap = NULL;
// MSL 5.02 Shadow
//		
// 	Needed a way to clip out a shadow when it is out of range.
//  Out of range is when it is past the fogend setting of the current mission.
//
	showShadow = true;
	if (version >= 13)
		*stream >> blobDistance;
	else
		blobDistance = outerRadius;
	if (version > 7)
	{
		MString name;
		*stream >> name;
		if (name.GetLength() > 0)
		{
			Check_Object(MLRTexturePool::Instance);
			MLRTexture *texture = (*MLRTexturePool::Instance)(name, 0);
			if (!texture)
				texture = MLRTexturePool::Instance->Add(name, 0);
			Check_Object(texture);
			lightMap = new MLRLightMap(texture);
			Register_Object(lightMap);
			lightMap->AttachReference();
			lightMask |= MLRState::LightMapLightingMode;
		}
	}
	DWORD hints = gosHint_DisableMipmap | gosHint_DontShrink;

	static char name[12];
	sprintf(name, "shadow%03d", shadowCount++);
	shadowTexture = MLRTexturePool::Instance->Add(name, gos_Texture_Keyed, 64, (gos_TextureHints)hints);

	MLRState lightMapState = lightMap->GetState();
	blobTextureHandle = lightMapState.GetTextureHandle();

	lightMapState.SetAlphaMode(MLRState::AlphaInvAlphaMode);
	lightMapState.SetBumpMapOff();

	lightMap->SetState(lightMapState);

	lightName = name;

	detailShadow = true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRShadowLight::MLRShadowLight(Stuff::Page *page):
	MLRInfiniteLightWithFalloff(DefaultData, page)
{
	Check_Object(page);
	Verify(gos_GetCurrentHeap() == LightsHeap);
	lightMap = NULL;
// MSL 5.02 Shadow
//		
// 	Needed a way to clip out a shadow when it is out of range.
//  Out of range is when it is past the fogend setting of the current mission.
//
	showShadow = true;
	const char* lightmap;
	if (page->GetEntry("ShadowMap", &lightmap))
	{
		Check_Pointer(lightmap);
		Check_Object(MLRTexturePool::Instance);
		MLRTexture *texture = (*MLRTexturePool::Instance)(lightmap, 0);
		if (!texture)
			texture = MLRTexturePool::Instance->Add(lightmap, 0);
		Check_Object(texture);
		lightMap = new MLRLightMap(texture);
		Register_Object(lightMap);
		lightMap->AttachReference();
		lightMask |= MLRState::LightMapLightingMode;
	}

	DWORD hints = gosHint_DisableMipmap | gosHint_DontShrink;

	// creating unique names
	static char shadowName[10];

	sprintf(shadowName, "Shadow%03d", shadowCount++);

	shadowTexture = MLRTexturePool::Instance->Add(shadowName, gos_Texture_Keyed, 64, (gos_TextureHints)hints);

	MLRState lightMapState = lightMap->GetState();
	blobTextureHandle = lightMapState.GetTextureHandle();

	lightMapState.SetAlphaMode(MLRState::AlphaInvAlphaMode);
	lightMapState.SetBumpMapOff();

	lightMap->SetState(lightMapState);

	lightName = shadowName;

	detailShadow = true;
	blobDistance = 100;
	page->GetEntry("BlobDistance", &blobDistance);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRShadowLight::~MLRShadowLight()
{
	if(lightMap!=NULL)
	{
		lightMap->DetachReference();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRShadowLight::Save(Stuff::MemoryStream *stream)
{
	Check_Object(this);
	Check_Object(stream);

	MLRInfiniteLightWithFalloff::Save(stream);
	*stream << blobDistance;
	if (lightMap)
	{
		Check_Object(lightMap);
		unsigned handle = lightMap->GetState().GetTextureHandle();
		MLRTexture *texture = (*MLRTexturePool::Instance)[handle];
		if(texture)
		{
			Check_Object(texture);
			MString name = texture->GetTextureName();
			*stream << name;
		}
		else
		{
			*stream << *MString::s_Empty;
		}
	}
	else
		*stream << *MString::s_Empty;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRShadowLight::Write(Stuff::Page *page)
{
	Check_Object(this);
	Check_Object(page);

	MLRInfiniteLightWithFalloff::Write(page);
	page->SetEntry("BlobDistance", blobDistance);
	if (lightMap)
	{
		Check_Object(lightMap);
		unsigned handle = lightMap->GetState().GetTextureHandle();
		MLRTexture *texture = (*MLRTexturePool::Instance)[handle];
		Check_Object(texture);
		page->SetEntry("ShadowMap", texture->GetTextureName());
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRShadowLight::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRShadowLight::SetLightMap(MLRLightMap *light_map)
{
	Check_Object(this);
	if (lightMap)
	{
		lightMap->DetachReference();
	}
	lightMap = light_map;

	if (lightMap == NULL)
	{
		lightMask &= ~MLRState::LightMapLightingMode;
	}
	else
	{
		lightMap->AttachReference();
		lightMask |= MLRState::LightMapLightingMode;
	}

	MLRState lightMapState = light_map->GetState();
	blobTextureHandle = lightMapState.GetTextureHandle();

	lightMapState.SetAlphaMode(MLRState::AlphaInvAlphaMode);
	lightMapState.SetBumpMapOff();

	lightMap->SetState(lightMapState);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRShadowLight::SeeDetailShadow(bool b)
{
	Check_Object(this);

	if(b!=detailShadow)
	{
		detailShadow = b;
		MLRState state = lightMap->GetState();
		if(b==true)
		{
			state.SetTextureHandle(shadowTexture->GetTextureHandle());
		}
		else
		{
			state.SetTextureHandle(blobTextureHandle);
		}
		state.SetBumpMapOff();
		lightMap->SetState(state);
	}
}

