//
/*=============================================================================
 *
 *  Filename:      VMatObj.cpp
 *  Version:            1.0
 *  Date:								06/11/96
 *  Author:             B.G.
 *
 *  Description:    implementation of editor material class
 *
 *===========================================================================*/

#include "stdafx.h"
#include "Acp_base.h"
#include "itf.h"
#include "gmt.h"
#include "IncMEC.h"
#include "gli.h"
#include "x:\cpa\main\inc\_editid.h"

#include "inctex.h"
#include "_interf.hpp"
#include "GMatObj.hpp"
#include "VMatObj.hpp"
#include "TexObj.hpp"

extern Material_Interface *gs_p_oMaterialInterface;
extern FILE *g_xLogFile;

//=================================================================================
//=================================================================================
//=================================================================================
tdoEditorVisualMaterial::tdoEditorVisualMaterial(
	CPA_FileObject *_p_oOwnerFile,
	CString _csId,
	BOOL _bSectionAlreadyExists,
	ACP_tdxHandleOfMaterial _hTemplateVisualMaterial
)
: CPA_SaveObject(
	gs_p_oMaterialInterface, //editor
	C_szVisualMaterialTypeName, //type
	E_ss_Responsible, //responsibility
	_p_oOwnerFile, //owner (there is none)
	FALSE, //available
	(char*)LPCTSTR(_p_oOwnerFile->GetCompletionPath(gs_p_oMaterialInterface, C_szFileReferencedNameKey)), //data path to complete the referenced section name
	m_vCallBackSaveVMT//callback
)
{
	//tell the file object that an object exists for its section
	g_oCoherenceManager.m_fn_vAddALink(_p_oOwnerFile, this);

	ASSERT(_hTemplateVisualMaterial);
	//the editor object directly handles the engine object
	m_hVisualMaterial = _hTemplateVisualMaterial;
	SetAvailable(_hTemplateVisualMaterial ? TRUE : FALSE);

	// construct section name (hack: szSectionName is here as an anti-bug for ...Split...
	char szSectionName[SCR_CV_ui_Cfg_MaxLenName];
	SCR_fn_v_RdL0_ComputeSectionName(
		szSectionName,
		(char*)LPCTSTR(_p_oOwnerFile->GetReferencedName(gs_p_oMaterialInterface, C_szFileReferencedNameKey)),
		GLI_C_SectionVisualMaterial,
		(char*)LPCTSTR(_csId)
	);

	// section object
	SetSectionData(this);
	SetReferencedSectionName(szSectionName);

	// name
	if ( fn_eRename(_csId) != E_mc_None )
		SetDefaultValidName();

	fn_vUpdateSectionName();

	if ( _bSectionAlreadyExists )
		fn_vSectionSaved(); //the section is saved, and has no pending notification
	else
		fn_vSectionDeleted(); //the section does not exist, and has no pending nofitication

	if ( fn_bCanBeNotified() && !fn_bSectionExists() )
		fn_vNotifySave();

	if ( fn_bIsAvailable() )
	{
		//to simplify edition, make all textures as animation components
		long lNbTextures = GLI_lGetMaterialNumberOfAnimatedTexture(m_hVisualMaterial);
		if ( !lNbTextures )
		{
			unsigned long ulSaveType;
			GLI_xGetMaterialType(m_hVisualMaterial, &ulSaveType);
			//read the standard texture handle
			GLI_tdstTexture *p_stTexture;
			GLI_xGetMaterialTexture(m_hVisualMaterial, &p_stTexture);
			//and mark it as an animated texture as well
			if ( p_stTexture )
			{
				GLI_vAddMaterialAnimatedTexture(m_hVisualMaterial, 0, p_stTexture, (float) (100.0 + ((double) rand() / RAND_MAX)));
				lNbTextures = 1;
				//tell the engine something changed with the animated textures
				GLI_xRefreshAnimatedTexture(m_hVisualMaterial);
			}
			GLI_xSetMaterialType(m_hVisualMaterial, ulSaveType);
		}

		for ( lNbTextures --; lNbTextures >= 0; lNbTextures -- ) //scan all the textures used by the material
		{
			float fDuration;
			GLI_tdstTexture *p_stTexture;
			GLI_vGetMaterialAnimatedTexture(m_hVisualMaterial, lNbTextures,	&p_stTexture,	&fDuration);
			//now lets create the editor texture objects, if necessary
			CPA_FileObject *p_oFileObject = NULL; //if we set the file object, this means we want to create a section, else the section alredy exists
			tdoEditorTexture *p_oEditorTexture = NULL;
			CString csName;
			if
			(
				p_stTexture //if the texture object does not exist already for this engine data
				&& !(p_oEditorTexture = (tdoEditorTexture *) gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(p_stTexture))
			)
			{
				SCR_tdst_Link_Value *p_stTextureEntry;
				char sz100BitmapName[100];
				//try to find the texture when referenced as a section
				if ( p_stTextureEntry = SCR_fnp_st_Link_SearchValue(GLI_p_stGetLinkTableOfTextureSection(), (unsigned long) p_stTexture) )
				{
					char *pszKey = SCR_M_p_sz_Link_GetKey(p_stTextureEntry);
					char szTextureFile[SCR_CV_ui_Cfg_MaxLenName],	szTextureName[SCR_CV_ui_Cfg_MaxLenName];
					//get the section name from the linktable entry
					SCR_fn_v_RdL0_SplitSectionName(pszKey, szTextureFile, NULL, szTextureName);
					//get the file object for this referenced path
					p_oFileObject = p_oGetFileObjectForCompletePath(szTextureFile);
					csName = szTextureName;
					//find it by name and owner
					p_oEditorTexture = (tdoEditorTexture *) gs_p_oMaterialInterface->GetBaseObject(
						csName,
						C_szTextureTypeName,
						p_oFileObject
					);
					//since it is in the section link table, the object must exist, since the editor creates editor
					//objects for all the sections (loaded or not) at initialization...
					ASSERT(p_oEditorTexture);
					//the section was analyzed, but at some other point we might have created an editor object 
					//for the same section with another handle: the valid handle is the current one, so tell 
					//the texture section object to drop its current handle, and to update its referencing VMTs
					//as well, if relevant
					p_oEditorTexture->m_vReplaceHandle(p_stTexture);
				}
				else if ( p_stTextureEntry = SCR_fnp_st_Link_SearchValue(GLI_p_stGetLinkTableOfTexture(), (unsigned long) p_stTexture) )
				{ //the material references the bitmap directly
					strcpy(sz100BitmapName, SCR_M_p_sz_Link_GetKey(p_stTextureEntry) + SCR_M_ul_Link_GetAdditionalLong(p_stTextureEntry, 1));
				}
				else //a valid texture handle and no linktable entry ? that is not well!!!
				{
					//get the name in the texture descriptor
					GLI_vGetTextureName(p_stTexture, sz100BitmapName);
					//output some warning message
					if ( gs_p_oMaterialInterface->m_bLoadWarningsAreEnabled() )
						AfxMessageBox(
							CString("The texture ") + sz100BitmapName +
							"\nappears in more than one section, including " + szSectionName +
							"\nYou can continue your work, but you should solve this problem.",
							MB_OK
						);
					if ( g_xLogFile )
					{
						//and log the error in the log file
						CString csLogMessage("multiple bitmap reference: ");
						csLogMessage += szSectionName;
						csLogMessage += " -> ";
						csLogMessage += sz100BitmapName;
						fprintf(g_xLogFile, "%s\n", LPCTSTR(csLogMessage));
						fflush(g_xLogFile);
					}
				}
				if ( !p_oEditorTexture ) //if the material references a bitmap directly (since no section was found for the texture...)
				{
					//determine the name of the texture file for the new texture section
					CString csFileObjectName = _p_oOwnerFile->GetReferencedName(gs_p_oMaterialInterface, C_szFileReferencedNameKey);
					csFileObjectName = csFileObjectName.Left(csFileObjectName.ReverseFind('.')) + tdoEditorTexture::m_csGetScriptExtension();
					//get the associated file object
					p_oFileObject = p_oGetFileObjectForReferencedPath(csFileObjectName);
					//the section will be named from the texture it references, without the file extension
					csName = CString("TEX_") + fn_pszBaseName0(sz100BitmapName);
					csName = csName.Left(csName.ReverseFind('.'));
					//replace characters tha are fobidden in section names
					short wSpacePos;
					while ( (wSpacePos = csName.FindOneOf(" :^")) != -1 )
						csName.SetAt(wSpacePos, '_');
					//the section was not analysed: it does not exist
					//make sure we did not create at init such a texture section object that is not loaded yet...
					p_oEditorTexture = (tdoEditorTexture *) gs_p_oMaterialInterface->GetBaseObject(
						csName,
						C_szTextureTypeName,
						p_oFileObject
					);
					if ( !p_oEditorTexture ) //we did not find a loaded texture section that references the same bitmap name
					{
						//try to find an editor texture section that has the correct bitmap name
						CPA_BaseObjectList *p_oList = gs_p_oMaterialInterface->GetBaseObjectList(C_szTextureTypeName);
						//scan the list of editor textures
						Position xPos = p_oList->GetHeadPosition();
						while ( xPos )
						{
							tdoEditorTexture *p_oCurrentTexture = (tdoEditorTexture *) p_oList->GetNext(xPos);
							if 
							( 
								p_oCurrentTexture->fn_bIsAvailable() 
								&& !p_oCurrentTexture->m_csGetTextureName().CompareNoCase(sz100BitmapName) 
							)
							{ //we found a loaded editor texture that has the same bitmap, however through a different handle
								//since the texture object references this texture bitmap, use it, whatever its name
								p_oEditorTexture = p_oCurrentTexture;
								break; 
							}
						}
					}
					if ( p_oEditorTexture )
					{
						if ( !(p_stTexture = p_oEditorTexture->m_hGetEngineTexture()) ) //the texture section we found is not loaded yet
						{
							//load it now
							p_oEditorTexture->m_vLoadAssociatedEngineTexture();
							//and remember its handle
							p_stTexture = p_oEditorTexture->m_hGetEngineTexture();
						}
						//we found a loaded editor texture for an existing section, which has a different handle:
						//we now use its handle instead of our current one, since ours does not come from a section...
						GLI_vModifyMaterialAnimatedTexture(m_hVisualMaterial, lNbTextures, p_stTexture, fDuration);
						if ( lNbTextures == 0 )
							GLI_xSetMaterialTexture(m_hVisualMaterial, p_stTexture);
					}
					//since we reference a section now, we must force saving of the visual material to account for it
					fn_vNotifySave();
				}
			} //a texture object is not yet associated with the referenced texture handle

			if ( !p_oEditorTexture ) //if the editor texture already exists
				p_oEditorTexture = new tdoEditorTexture(
					p_oFileObject,
					csName,
					FALSE, //the section does not exist
					p_stTexture
				);

			//tell the cohemngr that the created editor texture is used by the visual material
			g_oCoherenceManager.m_fn_vAddALink(this, p_oEditorTexture);
		} //texture list loop 
	} //the handle is valid
}

//=================================================================================
//=================================================================================
tdoEditorVisualMaterial::~tdoEditorVisualMaterial()
{
  //remove myself totally from the coherence manager database
	if ( !fn_bSectionExists() )
		g_oCoherenceManager.m_fn_vRemoveAllLinks(this, C_cLinkedAsChild);
}

//================================================================================
//================================================================================
BOOL tdoEditorVisualMaterial::m_bIsReferenced()
{
	return g_oCoherenceManager.m_fn_iGetFatherCount(this) > 1;
}

/*=================================================================================
//save a section of the form:
	{Material:<name>
		Type([Gouraud|Flat])
		AmbientColor(0.000000,0.000000,0.886275)
		DiffuseColor(1.000000,1.000000,0.960784)
		SpecularColor(1.000000,1.000000,0.960784,0.000000)
		Texture(<base texture file name (no path)>)
	}
//=================================================================================*/
/*static*/ void tdoEditorVisualMaterial::m_vCallBackSaveVMT(
	SCR_tdst_File_Description *_p_stFile,
	char *_p_szSectionName,
	void *_p_vData,
	SCR_tde_Ntfy_Action _eAction
)
{
	tdoEditorVisualMaterial *p_oEditorMaterial = (tdoEditorVisualMaterial *) _p_vData;

	if ( _eAction == SCR_EA_Ntfy_DeleteSection )
		//now the section exists, if this was not the case
		p_oEditorMaterial->fn_vSectionDeleted(); //the section does not exist, and has no pending nofitication

	if ( _eAction != SCR_EA_Ntfy_AddSection && _eAction != SCR_EA_Ntfy_RebuildSection )
	 return;

	if ( _eAction == SCR_EA_Ntfy_AddSection )
	{
		// go to end of file (we need all file directive to load this section)
		SCR_fn_v_SvL1_ToEndSection(_p_stFile);
		SCR_M_SvL0_SaveBlankLine (_p_stFile);
	}

	char szSectionName[SCR_CV_ui_Cfg_MaxLenName],szAction[SCR_CV_ui_Cfg_MaxLenName],szId[SCR_CV_ui_Cfg_MaxLenName];

	// construct section name (hack: szSectionName is here as an anti-bug for ...Split...
	SCR_fn_v_RdL0_SplitSectionName(_p_szSectionName, szSectionName, szAction, szId);
	SCR_fn_v_RdL0_ComputeSectionName(szSectionName, NULL, szAction, szId);
	// save begin section for the game material
	SCR_M_SvL0_SaveBeginSection(_p_stFile, szSectionName, SCR_CC_C_Cfg_EOL);

	//get the handles we need
	ACP_tdxHandleOfMaterial hMaterialVisual = p_oEditorMaterial->m_hGetEngineMaterial();

  //get the parameters we want to save
	unsigned long xMType;
	GEO_tdstColor stColor;
	long lSpecularExponent;

	//type
	GLI_xGetMaterialType(hMaterialVisual, &xMType);
	char *pszType;
	if ( xMType & GLI_C_lIsGouraud )
	{
		if ( xMType & GLI_C_lIsNotLightAlphaSensitive ) //the material is not alpha sensitive
			if ( xMType & GLI_C_lIsNotGrided )
				pszType = "Gouraud";
			else
				pszType = "Transparent";
		else
			pszType = "GouraudAlpha";
	}
	else //the material is not gouraud-shaded
		pszType = "Flat";
	SCR_M_SvL0_SaveEntry(_p_stFile, "Type", SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 1, pszType);

	//ambient color
	GLI_xGetMaterialAmbientCoef(hMaterialVisual, &stColor);
	SCR_M_SvL0_SaveEntry(_p_stFile, "AmbientColor", SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(
		_p_stFile, SCR_EF_SvL0_Scanf, 5, "%f,%f,%f,%f",
		(float) stColor.xR, (float) stColor.xG, (float) stColor.xB, (float) stColor.xA
	);

	//diffuse color
	GLI_xGetMaterialDiffuseCoef(hMaterialVisual, &stColor);
	SCR_M_SvL0_SaveEntry(_p_stFile, "DiffuseColor", SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(
		_p_stFile, SCR_EF_SvL0_Scanf, 5, "%f,%f,%f,%f",
		(float) stColor.xR, (float) stColor.xG, (float) stColor.xB, (float) stColor.xA
	);

	//specular color and coeff //TODO: save alpha component of the color too... when the engine loads its
	GLI_xGetMaterialSpecularCoef(hMaterialVisual, &lSpecularExponent, &stColor);
	SCR_M_SvL0_SaveEntry(_p_stFile, "SpecularColor", SCR_CC_C_Cfg_NoChar);
	SCR_fn_v_SvL0_SaveParameters_MP(
		_p_stFile, SCR_EF_SvL0_Scanf, 5, "%f,%f,%f,%ld",
		(float) stColor.xR, (float) stColor.xG, (float) stColor.xB, lSpecularExponent
	);

	//even if a texture is referenced, we save the reference only if the material
	//has the "textured" attribute...
	if ( xMType & GLI_C_lIsTextured )
	{
		long lNbTextures = GLI_lGetMaterialNumberOfAnimatedTexture(hMaterialVisual);
		BOOL bOnlyOne = ((lNbTextures == 1) ? TRUE : FALSE);
		for ( lNbTextures --; lNbTextures >= 0; lNbTextures -- ) //scan all the textures used by the material
		{
			float fDuration;
			GLI_tdstTexture *p_stTexture;
			GLI_vGetMaterialAnimatedTexture(hMaterialVisual, lNbTextures,	&p_stTexture,	&fDuration);
			//if the visual material references the texture through a section
			tdoEditorTexture *p_oEditorTexture = (tdoEditorTexture *) gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(p_stTexture);
			if ( p_oEditorTexture && g_oCoherenceManager.m_fn_ulGetLinkWeight(p_oEditorMaterial, p_oEditorTexture) )
			{
				if ( bOnlyOne ) //if there is only one texture, save it as unanimated
				{
					SCR_M_SvL0_SaveEntry(_p_stFile, "AddTexture", SCR_CC_C_Cfg_NoChar);
					SCR_fn_v_SvL0_SaveParameters_MP(
						_p_stFile, SCR_EF_SvL0_Scanf, 3, "%d,%s",
						0, LPCTSTR(p_oEditorTexture->GetReferencedSectionName())
					);
				}
				else //there are more than one: save all textures as components of the animation
				{
					SCR_M_SvL0_SaveEntry(_p_stFile, "AddTexture", SCR_CC_C_Cfg_NoChar);
					SCR_fn_v_SvL0_SaveParameters_MP(
						_p_stFile, SCR_EF_SvL0_Scanf, 4, "%d,%s,%f",
						0, LPCTSTR(p_oEditorTexture->GetReferencedSectionName()), fDuration
					);
				}
			}
		}
		//chrome attribute is relevant only if the material is textured
		if ( GLI_bIsMaterialChromed(hMaterialVisual) )
		{
			SCR_M_SvL0_SaveEntry(_p_stFile, "Env1", SCR_CC_C_Cfg_NoChar);
			SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 1, "0");
		}
		//backface attribute too
		pszType = ( xMType & GLI_C_lIsTestingBackface ) ? "OFF" : "ON";
		SCR_M_SvL0_SaveEntry(_p_stFile, "Backface", SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP(_p_stFile, SCR_EF_SvL0_Normal, 1, pszType);
	}

	//scroll
	long lSwitch;
	float fUSpeed, fVSpeed;
	GLI_xGetMaterialTextureScrollingCoef(hMaterialVisual, 0, &lSwitch, &fUSpeed, &fVSpeed);
	if ( lSwitch )
	{
		SCR_M_SvL0_SaveEntry(_p_stFile, "Scroll", SCR_CC_C_Cfg_NoChar);
		SCR_fn_v_SvL0_SaveParameters_MP(
			_p_stFile, SCR_EF_SvL0_Scanf, 4, "%ld,%f,%f",
			0, fUSpeed, fVSpeed
		);
	}

	// End Section
	SCR_M_SvL0_SaveEndSection(_p_stFile, SCR_CC_C_Cfg_EOL);

	//now the section exists, if this was not the case
	p_oEditorMaterial->fn_vSectionSaved(); // the section is saved and has no pending notification
}

//=================================================================================
//=================================================================================
//=================================================================================
// static functions for the class
//=================================================================================
//=================================================================================
//=================================================================================
CString tdoEditorVisualMaterial::m_csGetMaterialType() 
{ 
	return C_szVisualMaterialTypeName; 
}

CString tdoEditorVisualMaterial::m_csGetScriptExtension()
{
	return ".vmt";
}
