///////////////////////////////////////////////////////////////////////////////
/// @file RenderMaterial.cpp
///
/// @brief class for material renderstate settings
///
/// @author Lightning
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Nov 2001
/// @author Lightning
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#include "deRenderStates_priv.hpp"

WorldObjectClassImp(deRenderMaterial);

//constructor and destructor
deRenderMaterial::deRenderMaterial()
{
	//set the colors to 0
	memset(&m_Data.AmbientColor, 0, sizeof(m_Data.AmbientColor));
	memset(&m_Data.DiffuseColor, 0, sizeof(m_Data.DiffuseColor));
	memset(&m_Data.EmissiveColor, 0, sizeof(m_Data.DiffuseColor));
	memset(&m_Data.SpecularColor, 0, sizeof(m_Data.SpecularColor));

	m_Data.AmbientSource = MATSOURCE_MATERIAL;
	m_Data.DiffuseSource = MATSOURCE_DIFFUSE;
	m_Data.SpecularSource = MATSOURCE_SPECULAR;
	m_Data.EmissiveSource = MATSOURCE_MATERIAL;

	//set the power to 0
	m_Data.Power = 0.0f;

	return;
}

deRenderMaterial::~deRenderMaterial()
{
	return;
}

IdeRenderState::Type deRenderMaterial::GetRSType() const
{
	return TYPE_MATERIAL;
}

void * deRenderMaterial::GetRSInterface(IdeRenderState::Type type) const
{
	if (type == TYPE_MATERIAL)
		return ((IdeRenderMaterial*)this);
	if (type == IdeRenderState::TYPE_RSTATE)
		return ((IdeRenderState*)this);
	return NULL;
}

struct deRenderMaterial_Header_t
{
	short VersionMajor;
	short VersionMinor;
};
static const deRenderMaterial_Header_t deRenderMaterial_Header = {0,1};
/*
Version 0.1:
October 2, 2002
deColor {deFloat r,g,b,a}
32-bit enum MatSource {MATSOURCE_MATERIAL, MATSOURCE_DIFFUSE, MATSOURCE_SPECULAR}

short		Version_Major
short		Version_Minor
deColor		AmbientColor;
deColor		DiffuseColor;
deColor		EmissiveColor;
deColor		SpecularColor;
MatSource	AmbientSource;
MatSource	DiffuseSource;
MatSource	SpecularSource;
MatSource	EmissiveSource;
float		Power;
[total length = 68 bytes]
*/

deBoolean deRenderMaterial::Serialize(IdeFile* FS)
{
	if (FS == NULL)
		return deFALSE;

	DE3D_STREAM_PUT(FS, deRenderMaterial_Header.VersionMajor, u16);
	DE3D_STREAM_PUT(FS, deRenderMaterial_Header.VersionMinor, u16);
	//ambient color
	DE3D_STREAM_PUT(FS, m_Data.AmbientColor.r, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.AmbientColor.g, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.AmbientColor.b, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.AmbientColor.a, deFloat);
	//diffuse color
	DE3D_STREAM_PUT(FS, m_Data.DiffuseColor.r, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.DiffuseColor.g, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.DiffuseColor.b, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.DiffuseColor.a, deFloat);
	//emissive color
	DE3D_STREAM_PUT(FS, m_Data.EmissiveColor.r, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.EmissiveColor.g, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.EmissiveColor.b, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.EmissiveColor.a, deFloat);
	//specular color
	DE3D_STREAM_PUT(FS, m_Data.SpecularColor.r, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.SpecularColor.g, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.SpecularColor.b, deFloat);
	DE3D_STREAM_PUT(FS, m_Data.SpecularColor.a, deFloat);
	// the sources
	DE3D_STREAM_PUT(FS, m_Data.AmbientSource, s32);
	DE3D_STREAM_PUT(FS, m_Data.DiffuseSource, s32);
	DE3D_STREAM_PUT(FS, m_Data.SpecularSource, s32);
	DE3D_STREAM_PUT(FS, m_Data.EmissiveSource, s32);
	//specular power
	DE3D_STREAM_PUT(FS, m_Data.Power, float);

	return deTRUE;
}

deBoolean deRenderMaterial::DeSerialize(IdeFile* FS, long DataLength)
{
	if (FS == NULL)
		return deFALSE;
	
	u32 Length = 0;
	short VersionMajor, VersionMinor;
	
	DE3D_STREAM_GET(FS, VersionMajor, u16, Length, DataLength);
	DE3D_STREAM_GET(FS, VersionMinor, u16, Length, DataLength);
	if (VersionMajor > deRenderMaterial_Header.VersionMajor ||
		(VersionMajor == deRenderMaterial_Header.VersionMajor && VersionMinor > deRenderMaterial_Header.VersionMinor))
			return deFALSE;

	if (VersionMajor == 0 && VersionMinor == 1)
	{
		//ambient color
		DE3D_STREAM_GET(FS, m_Data.AmbientColor.r, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.AmbientColor.g, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.AmbientColor.b, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.AmbientColor.a, deFloat, Length, DataLength);
		//diffuse color
		DE3D_STREAM_GET(FS, m_Data.DiffuseColor.r, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.DiffuseColor.g, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.DiffuseColor.b, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.DiffuseColor.a, deFloat, Length, DataLength);
		//emissive color
		DE3D_STREAM_GET(FS, m_Data.EmissiveColor.r, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.EmissiveColor.g, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.EmissiveColor.b, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.EmissiveColor.a, deFloat, Length, DataLength);
		//specular color
		DE3D_STREAM_GET(FS, m_Data.SpecularColor.r, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.SpecularColor.g, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.SpecularColor.b, deFloat, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.SpecularColor.a, deFloat, Length, DataLength);
		//the sources
		DE3D_STREAM_GET(FS, m_Data.AmbientSource, s32, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.DiffuseSource, s32, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.SpecularSource, s32, Length, DataLength);
		DE3D_STREAM_GET(FS, m_Data.EmissiveSource, s32, Length, DataLength);
		//specular power
		DE3D_STREAM_GET(FS, m_Data.Power, float, Length, DataLength);
	}
	else
		return deFALSE;
	
	return deTRUE;
}

deBoolean deRenderMaterial::SetAmbientColor(deColor *AmbientColor)
{
	//set the light ambient color

	//if not locked, fail
	if(!m_LockFlag)
		DEBUGRETURN(deFALSE, "SetAmbientColor: Not Locked");

	m_Data.AmbientColor = *AmbientColor;
	return deTRUE;
}

deBoolean deRenderMaterial::GetAmbientColor(deColor *AmbientColor) const
{
	//get the ambient color
	*AmbientColor = m_Data.AmbientColor;

	//return true
	return deTRUE;
}

deBoolean deRenderMaterial::SetDiffuseColor(deColor *DiffuseColor)
{
	//set the light diffuse color

	//if not locked, fail
	if(!m_LockFlag)
		DEBUGRETURN(deFALSE, "SetDiffuseColor: Not Locked");

	m_Data.DiffuseColor = *DiffuseColor;
	return deTRUE;
}

deBoolean deRenderMaterial::GetDiffuseColor(deColor *DiffuseColor) const
{
	//get the diffuse color
	*DiffuseColor = m_Data.DiffuseColor;

	//return true
	return deTRUE;
}

deBoolean deRenderMaterial::SetSpecularColor(deColor *SpecularColor)
{
	//set the light specular color

	//if not locked, fail
	if(!m_LockFlag)
		DEBUGRETURN(deFALSE, "SetSpecularColor: Not Locked");

	m_Data.SpecularColor = *SpecularColor;
	return deTRUE;
}

deBoolean deRenderMaterial::GetSpecularColor(deColor *SpecularColor) const
{
	//get the specular color
	*SpecularColor = m_Data.SpecularColor;

	return deTRUE;
}


deBoolean deRenderMaterial::SetEmissiveColor(deColor *EmissiveColor)
{
	//set the light emissive color
	
	//if not locked, fail
	if(!m_LockFlag)
		DEBUGRETURN(deFALSE, "SetEmissiveColor: Not Locked");
	
	m_Data.EmissiveColor = *EmissiveColor;
	return deTRUE;
}

deBoolean deRenderMaterial::GetEmissiveColor(deColor *EmissiveColor) const
{
	//get the emissive color
	*EmissiveColor = m_Data.EmissiveColor;
	
	//return true
	return deTRUE;
}

deBoolean deRenderMaterial::SetAmbientSource(MatSource_t Source)
{
	if (Source < MATSOURCE_MATERIAL || Source >= MATSOURCE_COUNT)
		DEBUGRETURN(deFALSE, "SetAmbientSource: Bad Source");

	m_Data.AmbientSource = Source;
	return deTRUE;
}

IdeRenderMaterial::MatSource_t deRenderMaterial::GetAmbientSource() const
{
	return m_Data.AmbientSource;
}

deBoolean deRenderMaterial::SetDiffuseSource(MatSource_t Source)
{
	if (Source < MATSOURCE_MATERIAL || Source >= MATSOURCE_COUNT)
		DEBUGRETURN(deFALSE, "SetDiffuseSource: Bad Source");
	
	m_Data.DiffuseSource = Source;
	return deTRUE;
}

IdeRenderMaterial::MatSource_t deRenderMaterial::GetDiffuseSource() const
{
	return m_Data.DiffuseSource;
}

deBoolean deRenderMaterial::SetSpecularSource(MatSource_t Source)
{
	if (Source < MATSOURCE_MATERIAL || Source >= MATSOURCE_COUNT)
		DEBUGRETURN(deFALSE, "SetSpecularSource: Bad Source");
	
	m_Data.SpecularSource = Source;
	return deTRUE;
}

IdeRenderMaterial::MatSource_t deRenderMaterial::GetSpecularSource() const
{
	return m_Data.SpecularSource;
}

deBoolean deRenderMaterial::SetEmissiveSource(MatSource_t Source)
{
	if (Source < MATSOURCE_MATERIAL || Source >= MATSOURCE_COUNT)
		DEBUGRETURN(deFALSE, "SetEmissiveSource: Bad Source");
	
	m_Data.EmissiveSource = Source;
	return deTRUE;
}

IdeRenderMaterial::MatSource_t deRenderMaterial::GetEmissiveSource() const
{
	return m_Data.EmissiveSource;
}

deBoolean deRenderMaterial::SetSpecularPower(float Power)
{
	//set the power of the material

	//if not locked, fail
	if(!m_LockFlag)
		DEBUGRETURN(deFALSE, "SetSpecularPower: Not Locked");

	//set it
	m_Data.Power = Power;
	return deTRUE;
}

float deRenderMaterial::GetSpecularPower() const
{
	//return the power
	return m_Data.Power;
}

const deRenderMaterial::MatData* deRenderMaterial::GetAllData() const
{
	return &m_Data;
}

deBoolean deRenderMaterial::SetAllData(const MatData* Data)
{
	if (!m_LockFlag)
		DEBUGRETURN(deFALSE, "SetAllData: Not Locked");
	
	memcpy(&m_Data, Data, sizeof(MatData));
	
	return deTRUE;
}
