/*=============================================================================
 *
 *  Filename:						MatList.cpp
 *  Version:            1.0
 *  Date:								06/11/96
 *  Author:             V.L.
 *
 *  Description:				implementation of MaterialList view
 *
 *===========================================================================*/

#include "stdafx.h"
#include "Acp_base.h"
#include "itf.h"
#include "incgam.h"


#include "ogd.h"
#include "gmt.h"
#include "dpt.h"
#include "x:\cpa\main\inc\_editid.h"
#include "matres.h"
#include "_interf.hpp"
#include "MatList.hpp"
#include "GMatObj.hpp"
#include "VMatObj.hpp"
#include "TexObj.hpp"
#include "diaview.hpp"
#include "diacol.hpp"
#include "diameca.hpp"
#include "diamain.hpp"
#include "TGMdef.hpp"
//ROMTEAM WorldEditor (Cristi Petrescu 12/12/97)
#include "ozo.h"
//ENDROMTEAM WorldEditor (Cristi Petrescu)

extern Material_Interface *gs_p_oMaterialInterface;

//=============================================================================
//  Constant for DragDrop type
//=============================================================================
#define C_uiMaterial	1996

//=============================================================================
//
// implementation off C3ListView class
//
//=============================================================================
IMPLEMENT_DYNCREATE(CMaterialListView, C3ListView)

//=============================================================================
//  Description : Message map
//=============================================================================
BEGIN_MESSAGE_MAP(CMaterialListView, C3ListView)
	//{{AFX_MSG_MAP(CMaterialListView)
	ON_WM_CREATE()
	ON_WM_LBUTTONDOWN()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//=============================================================================
//  Description : constructor
//=============================================================================
CMaterialListView::CMaterialListView() : C3ListView()
{
	m_fn_vSetDDTypeAndEditor( C_uiMaterial, "Material_Editor");
	m_fn_vSetBox(C_cDisplayBitmapAndText, C_wListViewBTItemWidth, C_wListViewBTItemHeight);
	m_fn_vSetBox(C_cDisplayBitmap, C_wListViewBItemWidth, C_wListViewBItemHeight);
	m_fn_vSetBox(C_cDisplayText, C_wListViewTItemWidth, C_wListViewTItemHeight);
	//m_fn_vDisableMenuItem(TLVM_lOrder);
	m_oHatchBitmap.LoadBitmap(IDB_BITMAP_HATCHED);
	m_oHatchBrush.CreatePatternBrush(&m_oHatchBitmap);
	m_fn_vSetBitmapList(NULL);
	m_wSpecialImage = TSL_cItemNotFound;

	//which materials are to be displayed ?
	CString	csFileName = M_GetMainApp()->m_csEditorDataPath + "Tools\\Material\\Material.ini";
	char *p_szFileName = (char*)(LPCSTR)csFileName;
	char sz20ProfileDimension[20];
	GetPrivateProfileString(C_szPreferencesProfileSection, C_szDisplayModeProfileString, C_szDefaultDisplayFilter, sz20ProfileDimension, 20, p_szFileName);
	m_vSetMaterialDisplayFilter(strcmp(sz20ProfileDimension, C_szDisplayFilterDisabled) ? TRUE : FALSE);
}

//=============================================================================
//  Description : destructor
//=============================================================================
CMaterialListView::~CMaterialListView()
{
}

//=============================================================================
//  Description : Create view
//=============================================================================
int CMaterialListView::OnCreate( LPCREATESTRUCT _p_stCreateStruct )
{

	if (C3ListView::OnCreate( _p_stCreateStruct ) == -1)
		return -1;
	m_cDisplayType = C_cDisplayBitmapAndText;

	return 0;
}

//=============================================================================
//  Description : on draw item
//=============================================================================
void CMaterialListView::m_fn_vOverriddenDrawItem( short wItem, CDC *pDC, RECT *rect)
{
	tdoEditorGameMaterial *p_oEditorMaterial;
	BOOL							bSelected;

	// get item data
	p_oEditorMaterial = (tdoEditorGameMaterial *) m_fn_lGetContent( wItem, m_cCurrentOrder );

	//if the item was not loaded by engine, select a gray background
	CBrush *p_oOldBrush = NULL;
	//CBrush oGrayBrush(HS_BDIAGONAL, RGB(200, 100, 70));
	//CBrush oGrayBrush(CBitmap::FromHandle(m_hHatchBitmap))
	if ( !p_oEditorMaterial->m_bIsReferenced() )
		p_oOldBrush = pDC->SelectObject(&m_oHatchBrush);

	//draw the item normally, with a special text for items with this image (in text only-mode)
	m_fn_vDrawItem( wItem, pDC, rect, m_wSpecialImage);

	//restore the original background
	if ( p_oOldBrush )
		pDC->SelectObject(p_oOldBrush);

	// reinvert rectangle if item is selected
	bSelected = m_fn_bIsItemSelected(wItem, m_cCurrentOrder);
	if (bSelected)
		pDC->InvertRect( rect );

	if (bSelected)
		pDC->InvertRect( rect );
}

//=============================================================================
//  Description : on select item
//=============================================================================
void CMaterialListView::OnSelectItem(short wCase)
{
	if ( wCase != TSL_cItemNotFound )
	{
		tdoEditorGameMaterial *p_oGameMaterial = (tdoEditorGameMaterial *) m_fn_lGetContent(wCase);
		//if the editor material has no associated engine material yet
		if ( p_oGameMaterial && !p_oGameMaterial->fn_bIsAvailable() )
		{
			//prevent object name prefixing, because all the objects that will be created now
			//will get their names from existing sections
			BOOL bPrevLoadingWorld = gs_p_oMaterialInterface->GetInterface()->fn_bIsLoadingWorld();
			gs_p_oMaterialInterface->GetInterface()->SetLoadingWorld(TRUE);
			//make the editor material analyze its associated section to load the engine material
			p_oGameMaterial->m_vLoadAssociatedEngineMaterial();
			//restore prefixing mode (for new objects that we could create)
			gs_p_oMaterialInterface->GetInterface()->SetLoadingWorld(bPrevLoadingWorld);
			int iImage = m_iGetTextureIndexForGameMaterial(p_oGameMaterial, TRUE);
			//make the view update its display and show the correct texture
			m_fn_vSetItemImage(wCase, (short) iImage);
			m_fn_vRedrawSelectedItem(wCase);
			//update the purge button status, in case all materials are now analyzed
			gs_p_oMaterialInterface->m_p_oGetMainView()->m_vUpdatePurgeStatus();
		}
	}

	C3ListView::OnSelectItem(wCase);

	if ( wCase == TSL_cItemNotFound )
	{
		//m_fn_vRedrawSelectedItem();
		m_fn_vUnselectItem();
		gs_p_oMaterialInterface->m_fn_vShowMaterialAll();
		//Invalidate();
		return;
	}

	//show all parameters of the material
	gs_p_oMaterialInterface->m_fn_vShowMaterialAll();

	HWND hWnd = ((CWnd *) M_GetMainActiveViewport())->GetSafeHwnd();
	DD_eAddReference(hWnd, m_oDDCase.fn_p_szGetEditorName(), m_oDDCase.fn_uiGetDataType(), FALSE);
}

//=============================================================================
//  Description : change selected item image
//		called by CMaterialDescDlg when visuel change
//=============================================================================
void CMaterialListView::m_fn_vChangeSelectedItemImage( int iImage )
{
	m_fn_vSetItemImage( m_fn_lGetSelectedItem(), (short) iImage );
}

//=============================================================================
//  Description : redraw selected item
//		called by CMaterialDescDlg when visuel change
//=============================================================================
void CMaterialListView::m_fn_vRedrawSelectedItem(int iItem /*= -1*/)
{
	if ( iItem == TSL_cItemNotFound )
		iItem = m_fn_lGetSelectedItem(m_cCurrentOrder);

	RECT rect;
	m_fn_vGetCaseRect((short) iItem, &rect);
	rect.top -= GetScrollPosition().y;
	rect.bottom -= GetScrollPosition().y;
	rect.left -= GetScrollPosition().x;
	rect.right -= GetScrollPosition().x;

	InvalidateRect( &rect );
}

//=============================================================================
// Description SelectMaterial in list to fit with the given one
//=============================================================================
void CMaterialListView::m_fn_vSelectMaterial(tdoEditorGameMaterial *_p_oGameMaterial)
{
	int iPreviousSelectedItem = m_fn_lGetSelectedItem(m_cCurrentOrder);
	int	iNewSelectedItem = m_fn_iFindMaterial(_p_oGameMaterial);

	if ( iNewSelectedItem == iPreviousSelectedItem )
		return;

	//select the new item, and redraw it
	if ( iNewSelectedItem != TSL_cItemNotFound )
	{
		m_fn_vSetSelectedItem(iNewSelectedItem);
		m_vScrollToMakeItemVisible((short) iNewSelectedItem);
		m_fn_vRedrawSelectedItem(iNewSelectedItem);
	}
	else
		m_fn_vUnselectItem();

	//redraw the rectangle of the previously selected item too																			
	if ( iPreviousSelectedItem != TSL_cItemNotFound )
		m_fn_vRedrawSelectedItem(iPreviousSelectedItem);
}

//=============================================================================
// Description : Find Material item in list which correspond to the given engine material
// the index returned is the alphabetic index
//=============================================================================
int CMaterialListView::m_fn_iFindMaterial(tdoEditorGameMaterial *_p_oGameMaterial)
{
	int iItem;
	tdoEditorGameMaterial *p_oEditorMaterial;

	for ( iItem = 0; iItem < m_fn_lGetCount(); iItem++)
	{
		p_oEditorMaterial = (tdoEditorGameMaterial *) m_fn_lGetContent(iItem);
		if ((p_oEditorMaterial != NULL) && (p_oEditorMaterial == _p_oGameMaterial) )
			return iItem;
	}
	return -1;
}

//=============================================================================
// try to make the object under the cursor use the currently selected material
//=============================================================================
void CMaterialListView::m_vApplyCurrentMaterialToObjectUnderCursor(HIE_tdstPickInfo *_p_stPickInfo)
{
	M_p_oGetEditManager()->AskFor(new Material_ApplyMaterialModif(*_p_stPickInfo));
}

//=============================================================================
// handle function for OnLButtonDown
//=============================================================================
void CMaterialListView::OnLButtonDown(UINT nFlags, CPoint pt)
{
	POINT stScreenPos;

	C3ListView::OnLButtonDown( nFlags, pt);

	GetCursorPos(&stScreenPos);
	HIE_aDEF_stTabOfPickInfo a_stPickInfo;
	if ( xGetPickInfoUnderPoint(&a_stPickInfo, stScreenPos) )
		m_vApplyCurrentMaterialToObjectUnderCursor(a_stPickInfo);
}

//=============================================================================
//=============================================================================
Material_ApplyMaterialModif::Material_ApplyMaterialModif(
	HIE_tdstPickInfo &_r_stPickInfo
)
: CPA_Modif(0, "Game material drop")
{
	m_p_oMaterialListView = gs_p_oMaterialInterface->m_p_oGetMaterialListView();
	
	m_p_oGeometry = (Geometry3D*)gs_p_oMaterialInterface->GetMainWorld()
	->fn_p_oFindObjectWithEngine(
		_r_stPickInfo.hGeoObject,
		C_szGeometricObjectTypeName
	);

	if ( m_p_oGeometry )
	{
		m_xPickedElement = _r_stPickInfo.stPickedObject.aDEF_stDataOfElement[0].xElements;
		//TODO: is xIndexOfFace valid for spheres , lines or points ?
		m_xIndexInElement = _r_stPickInfo.stPickedObject.aDEF_stDataOfElement[0].xIndexOfFace;
		m_p_oMaterialBeforeDo = (tdoEditorGameMaterial *) 
			m_p_oGeometry->fn_p_oGetGameMaterial(m_xPickedElement, m_xIndexInElement);
		//ASSERT(m_p_oMaterialBeforeDo);

		m_p_oMaterialAfterDo = (tdoEditorGameMaterial *) m_p_oMaterialListView
		->m_fn_lGetContent(m_p_oMaterialListView->m_fn_lGetSelectedItem());
		//ASSERT(m_p_oMaterialAfterDo);

		m_bSwingFace = FALSE;
// ANNECY MT - 15/09/98 {
/*
		//ask if we want to apply the material to all faces of the IT or to the picked face only
		if ( m_p_oGeometry->fn_bIsIndexedTriangle(m_xPickedElement) )
			m_bSwingFace = gs_p_oMaterialInterface->m_bSplitIndexedTriangle();
			//m_bSwingFace = (AfxMessageBox("Apply the material to this face only", MB_YESNO) == IDYES);
*/
// END ANNECY MT }

		//if materials do not belong to the same file, forbid material drop
		CPA_FileObject *p_oCommonGMTFile = p_oGetFileObjectForReferencedPath(C_szFileNameForDefaultMaterial);
		CPA_FileObject *p_oInitialFileObject = (CPA_FileObject *) (m_p_oMaterialBeforeDo ? m_p_oMaterialBeforeDo->GetOwner() : NULL);
		CPA_FileObject *p_oFinalFileObject = (CPA_FileObject *) m_p_oMaterialAfterDo->GetOwner();
		if //make sure the user wants to do this
		( 
			(p_oInitialFileObject != p_oFinalFileObject) //if both materials do not come from the same file
			&& (p_oInitialFileObject != p_oCommonGMTFile && p_oFinalFileObject != p_oCommonGMTFile) //and those files are not the common file
		)
		{
			
			int iMixMaterials = AfxMessageBox(
				"The material being replaced does not belong to the file of the material being dropped\n"
				"In some cases, this might cause some levels to become interdependant\n"
				"(the current level will need another level to be loaded)\n"
				"Are you sure you want to do this ?",
				MB_YESNO
			);
			//if not, output a status message, and prevent completion of the modif
			if ( iMixMaterials != IDYES )
			{
				CString csMessage("You cannot drop a material from ");
				csMessage += ((CPA_FileObject *) m_p_oMaterialAfterDo->GetOwner())->GetReferencedName(gs_p_oMaterialInterface, C_szFileReferencedNameKey);
				fn_vGiveProgressInfo(csMessage + " on object '" + m_p_oGeometry->GetName() + "'", -1, C_STATUS_WARNING);
				m_p_oGeometry = NULL;
			}
		}
	}
}

//=============================================================================
//=============================================================================
BOOL Material_ApplyMaterialModif::Do()
{
  if (!m_p_oMaterialAfterDo)
	  return FALSE;
  
  return m_bDoIt(m_p_oMaterialBeforeDo, m_p_oMaterialAfterDo, TRUE);
}

//=============================================================================
//=============================================================================
BOOL Material_ApplyMaterialModif::Undo()
{
  return m_bDoIt(m_p_oMaterialAfterDo, m_p_oMaterialBeforeDo, FALSE);
}

//=============================================================================
//=============================================================================
BOOL Material_ApplyMaterialModif::m_bDoIt(
	tdoEditorGameMaterial *_p_oBefore, 
	tdoEditorGameMaterial *_p_oAfter,
	BOOL _bSplitElement
)
{
	//do nothing if both implied materials are identical
	if ( _p_oBefore == _p_oAfter )
		return FALSE;

//ROMTEAM WorldEditor (Cristi Petrescu 22/12/97)
	// check for zone object
	// workaround to find which type of zone (if any) is the father of the geometric object
	CPA_EditorBase *poZoneEditor = gs_p_oMaterialInterface -> GetMainWorld () -> GetEditorByName ("Zone");
	ASSERT (poZoneEditor);
	// the zone type
	long lEngineType = poZoneEditor -> OnQueryAction (gs_p_oMaterialInterface, C_uiQueryTypeOfZoneByGeometricObject, (long) m_p_oGeometry);
	GMT_tdxHandleToGameMaterial hGameMaterial = m_p_oMaterialAfterDo -> m_hGetEngineMaterial ();
	GMT_tdxHandleToCollideMaterial hCollideMaterial = GMT_fn_hGetCollideMaterial (hGameMaterial);
	// the collision material type
	if (hCollideMaterial != GMT_C_InvalidCollideMaterial)
	{
		if (lEngineType == -1)
		{
			// no zone
			if (IDNO == MessageBox (NULL,
									"The object is not a zone.\n"
									"Are you sure you want to drop\n"
								    "a material with collision properties on it?\n",
									"Material warning",
									MB_ICONEXCLAMATION | MB_YESNO))
				// infirmation ...
				return FALSE;
		}
		else
		{
			// there is a collision material for this game material...
			WORD m_uwTypeOfZone = GMT_fn_wGetTypeOfCollideMaterial (hCollideMaterial);
			BOOL bWrongCollideMaterial = FALSE;
			char szMessage[255];
			char *szZone;
			strcpy (szMessage, "The collide material is ");

			switch (lEngineType)
			{
			case C_lZDM:
				szZone = "ZDM";
				break;
			case C_lZDR:
				szZone = "ZDR";
				break;
			case C_lZDE:
				szZone = "ZDE";
				break;
			}

			switch (m_uwTypeOfZone)
			{
			case 0:
				if (lEngineType != C_lZDM)
				{
					strcat (szMessage, "ZDM");
					bWrongCollideMaterial = TRUE;
				}
				break;
			case 1:
				if (lEngineType != C_lZDR)
				{
					strcat (szMessage, "ZDR");
					bWrongCollideMaterial = TRUE;
				}
				break;
			case 2:
				if (lEngineType != C_lZDE)
				{
					strcat (szMessage, "ZDE");
					bWrongCollideMaterial = TRUE;
				}
				break;
			}
			if (bWrongCollideMaterial)
			{
				strcat (szMessage, ", but the object is a ");
				strcat (szMessage, szZone);
				strcat (szMessage, " zone.");
				M_GetMainWnd()->UpdateStatus(szMessage, C_STATUSPANE_INFOS, C_STATUS_ERROR);
				return FALSE;
			}
		}			
	}
	else
	{
		if (lEngineType != -1)
		{
			// dropping a material without collision props on a zone
			if (IDNO == MessageBox (NULL,
									"The object is a zone.\n"
									"Are you sure you want to drop\n"
								    "a material with no collision properties on it?\n",
									"Material warning",
									MB_ICONEXCLAMATION | MB_YESNO))
				// infirmation ...
				return FALSE;
		}
	}
//ENDROMTEAM WorldEditor (Cristi Petrescu)

  if ( m_p_oGeometry /*&& _p_oBefore && _p_oAfter*/ )
  {
		//if no element is created, the current material may become unrefenced, so remove a link
		if ( _p_oBefore && (!m_bSwingFace || !_bSplitElement) )
			g_oCoherenceManager.m_fn_vRemoveALink(m_p_oGeometry, _p_oBefore);
		//in any case, the new material becomes referenced
		if ( _p_oAfter )
			g_oCoherenceManager.m_fn_vAddALink(m_p_oGeometry, _p_oAfter);

		ACP_tdxIndex xMaterialedElement, xMaterialedIndexInElement;
// ANNECY MT - 15/09/98 {
/*
		if ( m_bSwingFace ) //the user wants to move the IT face into a FMD before applying the material
		{
			if ( _bSplitElement ) //move the face from the IT to the FMD
			{
				m_p_oGeometry->fn_vMoveFaceToFaceDescriptors(m_xPickedElement, m_xIndexInElement, &m_xElementFMD, &m_xFaceFMD);
				//GEO_fn_vMoveFaceToFaceDescriptors((ACP_tdxHandleOfObject) m_p_oGeometry->GetData(), m_xPickedElement, m_xIndexInElement, &m_xElementFMD, &m_xFaceFMD);
				//we will apply the material to the face in the facemap descriptor
				xMaterialedElement = m_xElementFMD;
				xMaterialedIndexInElement = m_xFaceFMD;
			}
			else //move the face back from the FMD to the IT
			{
				m_p_oGeometry->fn_vMoveFaceDescriptorsToFace(m_xElementFMD, m_xFaceFMD, m_xPickedElement, m_xIndexInElement);
				//GEO_fn_vMoveFaceDescriptorsToFace((ACP_tdxHandleOfObject) m_p_oGeometry->GetData(), m_xElementFMD, m_xFaceFMD, m_xPickedElement, m_xIndexInElement);
				//we will apply the material to the indexed triangle element
				xMaterialedElement = m_xPickedElement;
				xMaterialedIndexInElement = m_xIndexInElement;
			}
			//GEO_vEndModifyObject2((ACP_tdxHandleOfObject) m_p_oGeometry->GetData());
			//make the geometric object notify that those 2 elements are to be saved
			m_p_oGeometry->fn_vNotifySaveElement(m_xPickedElement);
			if ( m_xElementFMD != m_xPickedElement )
				m_p_oGeometry->fn_vNotifySaveElement(m_xElementFMD);
		}
		else
*/
// END ANNECY MT }
		{
			xMaterialedElement = m_xPickedElement;
			xMaterialedIndexInElement = m_xIndexInElement;
		}
		//set the new material for the triangles
		m_p_oGeometry->fn_vSetGameMaterial(xMaterialedElement, xMaterialedIndexInElement, (CPA_BaseObject *) _p_oAfter);
		//redraw the material list in case the aspect changed, because if the replaced material
		//is no longer used and the list displays only used materials, it will disappear
		m_p_oMaterialListView->m_vRefreshDisplayedMaterialList(m_p_oMaterialListView->m_bDisplayAll);
		m_p_oMaterialListView->Invalidate();
		//redraw the viewport contents to see the new material
		gs_p_oMaterialInterface->GetInterface()->fn_vUpdateAll(E_mc_JustDraw);
		//tell the object it has to be saved because the material changed. If we modified the
		//faces, it is not necessary because the notification is already done
// ANNECY MT - 15/09/98 {
/*
		if ( !m_bSwingFace )
*/
// END ANNECY MT }
			m_p_oGeometry->fn_vNotifySaveElement(xMaterialedElement);
				//
		return TRUE;
  }
  return FALSE;
}

//=============================================================================
//change the bitmap associated to a game material item according to its unanimated texture
//=============================================================================
void CMaterialListView::m_vResetMaterialItemTexture(tdoEditorGameMaterial *_p_oGameMaterial)
{
	//find the item for the game material in the material list
	int iMaterialIndex = m_fn_iFindMaterial(_p_oGameMaterial);
	//find the index of the bitmap corresponding to its unanimated texture
	int iImageIndex = m_iGetTextureIndexForGameMaterial(_p_oGameMaterial, FALSE);
	//change the item's image accordingly
	m_fn_vSetItemImage(iMaterialIndex, iImageIndex);
	//then redraw it
	m_fn_vRedrawSelectedItem(iMaterialIndex);
}


//=============================================================================
// Description : returns the index of the bitmap that represents the current
// texture of the specified editor game material
//=============================================================================
int CMaterialListView::m_iGetTextureIndexForGameMaterial(
	tdoEditorGameMaterial *_p_oGameMaterial, 
	BOOL _bLoadIfNotFound
)
{
	GMT_tdxHandleToGameMaterial hGameMaterial = _p_oGameMaterial->m_hGetEngineMaterial();
	int iImage;
	if ( GMT_fn_b_ulIsValid(hGameMaterial) )
	{
		//get the visual material
		ACP_tdxHandleOfMaterial hVisualMaterial = GMT_fn_hGetVisualMaterial(_p_oGameMaterial->m_hGetEngineMaterial());
		tdoEditorVisualMaterial *p_oVisualMaterial = (tdoEditorVisualMaterial *) gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(hVisualMaterial);
		long lNbTextures = GLI_lGetMaterialNumberOfAnimatedTexture(hVisualMaterial);
		//if we dont load the associated bitmaps, just go for the first texture of the list
		if ( !lNbTextures )
		{
			iImage = m_fn_p_oGetBitmapList()->m_fn_iGetBitmapIndex(C_szNoBitmapName);
			m_fn_p_oGetBitmapList()->m_fn_vSetBitmapLong(iImage, 0);
		}
		else
		{
			if ( !_bLoadIfNotFound && lNbTextures )
				lNbTextures = 1;
			for ( lNbTextures --; lNbTextures >= 0; lNbTextures -- ) //scan all textures in animation list
			{
				//get its texture, and the associated editor texture as well
				float fDuration;
				GLI_tdstTexture *p_stTexture;
				GLI_vGetMaterialAnimatedTexture(hVisualMaterial, lNbTextures, &p_stTexture, &fDuration);
				//find the bitmap used as texture
				tdoEditorTexture *p_oEditorTexture = (tdoEditorTexture *) gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(p_stTexture);
				//SCR_tdst_Link_Value *p_stTextureEntry = SCR_fnp_st_Link_SearchValue(GLI_p_stGetLinkTableOfTexture(), (unsigned long) p_stTexture);
				//char *pszTextureName = SCR_M_p_sz_Link_GetKey(p_stTextureEntry) + SCR_M_ul_Link_GetAdditionalLong(p_stTextureEntry, 1);
				//normally the bitmap list references all bitmaps found in the texture directory...
				iImage = m_fn_p_oGetBitmapList()->m_fn_iGetBitmapIndex((char *)LPCTSTR(p_oEditorTexture->m_csGetTextureName())/*pszTextureName*/);
				if ( iImage == -1 ) //the bitmap is not yet loaded
				{
					if ( _bLoadIfNotFound ) //if we want to load it
					{
						//remember current directory
						char szCurDir[_MAX_PATH];
						long lCurDirLen = _MAX_PATH;
						lCurDirLen = GetCurrentDirectory(lCurDirLen, szCurDir);
						//change to the textures directory
						if (!SetCurrentDirectory(fn_szGetTexturesDataPath()))
							//return a failsafe bitmap index if an error occured
							iImage = m_fn_p_oGetBitmapList()->m_fn_iGetBitmapIndex(C_szUnviewableBitmapName);
						else
						{
							//load the bitmap in the bitmap list
							tdoEditorVisualMaterial *p_oMaterial = (tdoEditorVisualMaterial *) 
								gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(hVisualMaterial);
							iImage = m_fn_p_oGetBitmapList()->m_fn_iAdd(p_oEditorTexture->m_csGetTextureName());
							//and restore the previous directory
							SetCurrentDirectory(szCurDir);
							//if we could load the image, associate it to the texture
							if ( iImage != -1 )
								m_fn_p_oGetBitmapList()->m_fn_vSetBitmapLong(iImage, (long) p_stTexture);
							else
								//get the image corresponding to an unviewable texture
								iImage = m_fn_p_oGetBitmapList()->m_fn_iGetBitmapIndex(C_szUnviewableBitmapName);
						}
					}
					else
						//load the image corresponding to an unviewable texture
						iImage = m_fn_p_oGetBitmapList()->m_fn_iGetBitmapIndex(C_szUnviewableBitmapName);
				}
				else //the bitmap is already loaded: associate the texture to it
					m_fn_p_oGetBitmapList()->m_fn_vSetBitmapLong(iImage, (long) p_stTexture);
			} //for all textures in animated list
		} //the material has a texture
	}
	else //the game material is not valid
		iImage = m_fn_p_oGetBitmapList()->m_fn_iGetBitmapIndex(C_szUnviewableBitmapName);

	return iImage;
}

//=============================================================================
//=============================================================================
void CMaterialListView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	gs_p_oMaterialInterface->_OnKeyDown(nChar, nRepCnt, nFlags);
}

//=============================================================================
//=============================================================================
void CMaterialListView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	gs_p_oMaterialInterface->_OnKeyUp(nChar, nRepCnt, nFlags);
}

//=============================================================================
// Description : update the image indexes for the listed game materials because
//the bitmaps were reloaded
//=============================================================================
void CMaterialListView::m_vBitmapListWasRefreshed(void)
{
	for ( long lIndex = 0; lIndex < m_fn_lGetCount(); lIndex ++ )
	{
		//find the name of the texture for the game material
		tdoEditorGameMaterial *p_oMaterial;
		p_oMaterial = (tdoEditorGameMaterial *) m_fn_lGetContent(lIndex);
		int iImage = m_iGetTextureIndexForGameMaterial(p_oMaterial, FALSE);
		int iMaterialIndex = m_fn_iFindMaterial(p_oMaterial);
		m_fn_vSetItemImage(iMaterialIndex, (short) iImage);
	}
	Invalidate();
}

//=============================================================================
//=============================================================================
void CMaterialListView::_OnCommand(short _wMenuId)
{
	if ( _wMenuId == 9 )
		m_vRefreshDisplayedMaterialList(!m_bDisplayAll);
	else if ( _wMenuId == 10 )
		m_vAnalyzeAllMaterials();
}

//=============================================================================
//=============================================================================
void CMaterialListView::_InitPopupMenu(CMenu &r_oMenu, short wFirstValue) 
{
	r_oMenu.AppendMenu(MF_SEPARATOR);
	//make sure the id I want to use is available
	ASSERT(9 >= wFirstValue);
	r_oMenu.AppendMenu((m_bDisplayAll ? MF_CHECKED : MF_UNCHECKED) | MF_STRING, 9, "Display All");
	if ( m_bDisplayAll )
		r_oMenu.AppendMenu(MF_STRING, 10, "Analyze All");
}

//=============================================================================
//=============================================================================
void CMaterialListView::m_vAnalyzeAllMaterials()
{
	BOOL bPrevLoadingWorld = gs_p_oMaterialInterface->GetInterface()->fn_bIsLoadingWorld();
	//prevent object name prefixing, because all the objects that will be created now
	//will get their names from existing sections
	gs_p_oMaterialInterface->GetInterface()->SetLoadingWorld(TRUE);

	long lCount, lNbMaterials = m_fn_lGetCount();
	CString csStatusMessage;
	csStatusMessage.Format("Analyzing %d materials", lNbMaterials);
	for ( lCount = 0; lCount < lNbMaterials; lCount ++ )
	{
		tdoEditorGameMaterial *p_oGameMaterial = (tdoEditorGameMaterial *) m_fn_lGetContent(lCount);
		fn_vGiveProgressInfo(csStatusMessage, (100 * lCount) / lNbMaterials);
		if ( p_oGameMaterial && !p_oGameMaterial->fn_bIsAvailable() )
		{
			//make the editor material analyze its associated section to load the engine material
			//but without uploading the texture to the graphic board
			p_oGameMaterial->m_vLoadAssociatedEngineMaterial(FALSE);
			int iImage = m_iGetTextureIndexForGameMaterial(p_oGameMaterial, TRUE);
			//make the view update its display and show the correct texture
			m_fn_vSetItemImage(lCount, (short) iImage);
			m_fn_vRedrawSelectedItem(lCount);
		}
	}
	fn_vGiveProgressInfo("", -1);
	//restore prefixing mode (for new objects that we could create)
	gs_p_oMaterialInterface->GetInterface()->SetLoadingWorld(bPrevLoadingWorld);
	//now we can upload all textures to the board's vram
	GLI_vEndofGeometricLoad();
	//update the purge button status, in case all materials are now analyzed
	gs_p_oMaterialInterface->m_p_oGetMainView()->m_vUpdatePurgeStatus();
	//make the view redraw itself
}

//=============================================================================
//=============================================================================
void CMaterialListView::m_vRefreshDisplayedMaterialList(BOOL _bAllMaterials, BOOL _bKillAll /* = FALSE */)
{
	if ( _bKillAll )
		m_fn_bDeleteAllItems();

	//update internal flag for menu
	m_bDisplayAll = _bAllMaterials;

	CPA_FileObject *p_oCurrentFileObject = gs_p_oMaterialInterface->m_p_oGetCurrentFileObject();
	CPA_List<CPA_BaseObject> oListedMaterials;
	if ( p_oCurrentFileObject )
		gs_p_oMaterialInterface->GetMainWorld()->fn_lFindObjects(
			&oListedMaterials,
			"", // obj name
			C_szGameMaterialTypeName, //type
			p_oCurrentFileObject // owner
		);
	//find all editor material objects
	long lCurMaterial = 0, lNbMaterials = oListedMaterials.GetCount();
	POSITION xPos;
	xPos = oListedMaterials.GetHeadPosition();
	while ( xPos )
	{
		fn_vGiveProgressInfo("updating list of displayed materials", ((lCurMaterial ++) * 100) / lNbMaterials);
		//extract the editor game material
		tdoEditorGameMaterial *p_oGameMaterial = (tdoEditorGameMaterial *) oListedMaterials.GetNext(xPos);

		if ( _bAllMaterials || p_oGameMaterial->m_bIsReferenced()	)
		{ //we want the material to be displayed
			//find the material in the list
			int iItem = m_fn_iFindMaterial(p_oGameMaterial);
			if ( iItem == TSL_cItemNotFound )
			{
				//find an image to display for the material
				int iImage = m_iGetTextureIndexForGameMaterial(p_oGameMaterial, TRUE);
				//add the material to the list with the correct texture
				int iAddedItem = m_fn_iAddItem(p_oGameMaterial->GetName(), (short) iImage, (long) p_oGameMaterial);
				//m_fn_vSetItemImage(iAddedItem, iImage); ?
			}
		}
		else if ( !_bKillAll) //we want the material not to be displayed, and all materials were not removed
		{
			//find the material in the list
			int iItem = m_fn_iFindMaterial(p_oGameMaterial);
			if ( iItem != TSL_cItemNotFound ) //if we found it, remove it from the list
			{
				//make the frames undisplay the material if we remove the selected material
				if ( m_fn_lGetSelectedItem() == iItem )
				{
					m_fn_vUnselectItem();
					gs_p_oMaterialInterface->m_fn_vShowMaterialAll();
				}
				m_fn_bDeleteItem(iItem);
			}
		}
	}
	fn_vGiveProgressInfo("", -1);
}

//=============================================================================
// Description : Create a new material
// template the given material or default material if parameter is null
//=============================================================================
void CMaterialListView::m_fn_vCreateNewMaterial(tdoEditorGameMaterial *_p_oTemplateMaterial, CString _csName)
{
	Material_CreateOrCopyMaterialModif *p_oModif
	= new Material_CreateOrCopyMaterialModif(_p_oTemplateMaterial, _csName);
	M_p_oGetEditManager()->AskFor(p_oModif);
}

//=============================================================================
//=============================================================================
Material_CreateOrCopyMaterialModif::Material_CreateOrCopyMaterialModif
(
	tdoEditorGameMaterial *_p_oTemplateMaterial,
	CString _csName
)
: CPA_Modif(0, "")
{
	m_p_oMaterialListView = gs_p_oMaterialInterface->m_p_oGetMaterialListView();

	m_csNameToGive = _csName;

	//create the engine material
	m_hTemplateMaterial = GMT_fn_hCreateGameMaterial();

	if ( _p_oTemplateMaterial )
	{
		SetName("Game material duplication");
		//create a copy of the template material
		GMT_fn_vCopyGameMaterial(m_hTemplateMaterial, _p_oTemplateMaterial->m_hGetEngineMaterial());
	}
	else
	{
		SetName("Game material creation");

		//give the game material a visual material, which is the minimum
		ACP_tdxHandleOfMaterial hVisualMaterial;
		GLI_xCreateMaterial(&hVisualMaterial);
		//now give it to the game material
		GMT_fn_vSetVisualMaterial(m_hTemplateMaterial, hVisualMaterial);
		//and create a set of initial values for future use
//		GMT_fn_vSetGameMaterialInitialValues(m_hTemplateMaterial);
	}
	//if for redo/undo, I use a destroymodif to reuse the code...
	m_p_oDestroyModif = NULL;
}

//=============================================================================
//=============================================================================
Material_CreateOrCopyMaterialModif::~Material_CreateOrCopyMaterialModif()
{
	if ( m_p_oDestroyModif )
	{
		delete m_p_oDestroyModif;
		m_p_oDestroyModif = NULL;
	}
	else 
	{
		//if not even done once, the engine materials are not used, so we destroy them both
		if ( !HasBeenDone() )
		{
			if ( GMT_fn_b_ulIsValid(m_hTemplateMaterial) )
			{
				//delete the visual material that was created especially for this template
				ACP_tdxHandleOfMaterial hVisualMaterial = GMT_fn_hGetVisualMaterial(m_hTemplateMaterial);
				GLI_xDeleteMaterial(hVisualMaterial);
				//then delete the template itself
				GMT_fn_vDestroyGameMaterial(m_hTemplateMaterial);
			}
			GMT_fn_vInvalidate(&m_hTemplateMaterial);
		}
		else
			//if done once, the destroy modif exists, and we should not get here...
			ASSERT(FALSE);
	}
}

//=============================================================================
//=============================================================================
BOOL Material_CreateOrCopyMaterialModif::Do()
{
	if ( m_p_oDestroyModif ) //this is hence a redo of creation -> an undo of destruction
		return m_p_oDestroyModif->Undo();
	else //no modif exists: this is the first do()
	{
		//create an editor material, containing a brand new engine material cloned from the template
		//an editor visual material will be created automatically as well
		//the new game material will be notified for save because its section does not exists
		tdoEditorGameMaterial *p_oEditorGameMaterialAfterDo = new tdoEditorGameMaterial(
			gs_p_oMaterialInterface->m_p_oGetCurrentFileObject(), 
			m_csNameToGive, 
			FALSE, 
			m_hTemplateMaterial
		);
		//remember the name that was actually given to the editor object
		m_csNameToGive = p_oEditorGameMaterialAfterDo->GetName();
		//retrieve the handle to the visual material and the associated editor object
		ACP_tdxHandleOfMaterial hCreatedVisualMaterial = GMT_fn_hGetVisualMaterial(p_oEditorGameMaterialAfterDo->m_hGetEngineMaterial());

		//get the handle to the bitmap for the material
		GLI_tdstTexture *p_stTexture;
		GLI_xGetMaterialTexture(hCreatedVisualMaterial, &p_stTexture);

		//find the bitmap used as texture
		int iImage;
		if (p_stTexture == NULL)
			iImage = m_p_oMaterialListView->m_fn_p_oGetBitmapList()->m_fn_iGetBitmapIndex(C_szNoBitmapName);
		else
			iImage = m_p_oMaterialListView->m_fn_p_oGetBitmapList()->m_fn_iGetBitmapIndexByLong((long) p_stTexture);

		//add the editor material in the material list
		long lIndexInListAfterDo = m_p_oMaterialListView->m_fn_iAddItem(
			p_oEditorGameMaterialAfterDo->GetName(), 
			(short) iImage, 
			(long) p_oEditorGameMaterialAfterDo
		);
		m_p_oMaterialListView->m_fn_vSetItemImage(lIndexInListAfterDo, (short) iImage);

		//make the list select this material and redraw itself
		m_p_oMaterialListView->OnSelectItem((short) lIndexInListAfterDo);
		m_p_oMaterialListView->m_vScrollToMakeItemVisible((short) lIndexInListAfterDo);

		//create a destroy modif for future do/undo
		m_p_oDestroyModif = new Material_DestroyMaterialModif(p_oEditorGameMaterialAfterDo);
		return TRUE;
	}
}

//=============================================================================
//=============================================================================
BOOL Material_CreateOrCopyMaterialModif::Undo()
{
	ASSERT(m_p_oDestroyModif);
	return m_p_oDestroyModif->Do(); //an undo of creation is a do of destruction
}

//=============================================================================
// Description : Delete selected material
//     verify that material is unused
//=============================================================================
void CMaterialListView::m_fn_vDeleteMaterial(tdoEditorGameMaterial *_p_oMaterialToDelete)
{
	//if the material has other fathers than its file (meaning there are geometric objects)
	if ( _p_oMaterialToDelete->m_bIsReferenced() )
		AfxMessageBox("Material used in scene, can't be deleted", MB_ICONSTOP | MB_OK );
	else
	{
		//short wItemImageIndex = m_fn_wGetImage(iItem);
		Material_DestroyMaterialModif *p_oModif = new Material_DestroyMaterialModif(_p_oMaterialToDelete);
		M_p_oGetEditManager()->AskFor(p_oModif);
	}
}

//=============================================================================
//=============================================================================
Material_DestroyMaterialModif::Material_DestroyMaterialModif(
	tdoEditorGameMaterial *_p_oDeletedGameMaterial
)
: CPA_Modif(0, "Material deletion")
{
	m_bMaterialWasInList = FALSE;
	m_p_oMaterialListView = gs_p_oMaterialInterface->m_p_oGetMaterialListView();

	//remember the editor game material
	m_p_oDeletedGameMaterial = _p_oDeletedGameMaterial;
	GMT_tdxHandleToGameMaterial hGameMaterial = m_p_oDeletedGameMaterial->m_hGetEngineMaterial();
	//and the editor visual material as well
	ACP_tdxHandleOfMaterial hVisualMaterial = GMT_fn_hGetVisualMaterial(hGameMaterial);
	m_p_oDeletedVisualMaterial = (tdoEditorVisualMaterial *) 
		gs_p_oMaterialInterface->m_p_oGetEditorObjectForEngine(hVisualMaterial);
	ASSERT(m_p_oDeletedVisualMaterial);

	//prepare the do/undo of the associated collide material deletion
	GMT_tdxHandleToCollideMaterial hMaterialCollide = GMT_fn_hGetCollideMaterial(hGameMaterial);
	if ( hMaterialCollide != GMT_C_InvalidCollideMaterial )
		m_p_oDeleteEngineCollideModif = new tdoDeleteEngineCollideModif(hGameMaterial, hMaterialCollide);
	else
		m_p_oDeleteEngineCollideModif = NULL;
	//prepare the do/undo of the associated mechanics material deletion
	DNM_tdxHandleToMecMatCharacteristics hMaterialMechanics = GMT_fn_hGetMechanicsMaterial(hGameMaterial);
	if ( DNM_fn_bIsMatCharacteristicsValid(hMaterialMechanics) )
		m_p_oDeleteEngineMechanicsModif = new tdoDeleteEngineMechanicsModif(hGameMaterial, hMaterialMechanics);
	else 
		m_p_oDeleteEngineMechanicsModif = NULL;
}

//=============================================================================
//=============================================================================
Material_DestroyMaterialModif::~Material_DestroyMaterialModif()
{
	//destroy the other modifs, 
	//they will take care of the fact that they have been done or not by themselves
	if ( m_p_oDeleteEngineCollideModif )
		delete m_p_oDeleteEngineCollideModif;
	if ( m_p_oDeleteEngineMechanicsModif )
		delete m_p_oDeleteEngineMechanicsModif;

	//if the modif is not done or is undone, the objects are in use, so dont destroy them
	if ( HasBeenDone() )
	{
		//tell the scripts we dont want to save the material
		m_p_oDeletedGameMaterial->fn_vNotifyUnSave();
		m_p_oDeletedVisualMaterial->fn_vNotifyUnSave();
		//and destroy the objects
		if ( m_p_oDeletedVisualMaterial )
		{
			//destroy the engine visual material
			ACP_tdxHandleOfMaterial hVisualMaterial = m_p_oDeletedVisualMaterial->m_hGetEngineMaterial();
			if ( hVisualMaterial )
				GLI_xDeleteMaterial(hVisualMaterial);
			//destroy the editor visual material
			delete m_p_oDeletedVisualMaterial;
			m_p_oDeletedVisualMaterial = NULL;
		}
		if ( m_p_oDeletedGameMaterial )
		{
			//destroy the engine game material
			GMT_tdxHandleToGameMaterial hGameMaterial = m_p_oDeletedGameMaterial->m_hGetEngineMaterial();
			if ( GMT_fn_b_ulIsValid(hGameMaterial) )
				GMT_fn_vDestroyGameMaterial(hGameMaterial);
			//destroy the editor game material
			delete m_p_oDeletedGameMaterial;
			m_p_oDeletedGameMaterial = NULL;
		}
	}
}

//=============================================================================
// do the material deletion
//=============================================================================
BOOL Material_DestroyMaterialModif::Do()
{
	//disable the submaterials 
	BOOL bResult = TRUE;
	if ( m_p_oDeleteEngineCollideModif )
		bResult = m_p_oDeleteEngineCollideModif->Do();
	if ( bResult && m_p_oDeleteEngineMechanicsModif )
		bResult = m_p_oDeleteEngineMechanicsModif->Do();

	//if this succeeded, remove the visual and game materials
	if ( bResult )
	{
		//remove the links between the game material and its submaterial
		g_oCoherenceManager.m_fn_vRemoveALink(m_p_oDeletedGameMaterial, m_p_oDeletedVisualMaterial);
		//make the hierarchy believe the objects no longer exist
		m_p_oDeletedVisualMaterial->fn_bUnValidate();
		m_p_oDeletedGameMaterial->fn_bUnValidate();
		//tell we dont want to save the game and visual materials
		m_p_oDeletedGameMaterial->fn_vNotifyUnSave();
		m_p_oDeletedVisualMaterial->fn_vNotifyUnSave();
		//remove the material from the list of displayed materials, if relevant
		int iItem = m_p_oMaterialListView->m_fn_iFindMaterial(m_p_oDeletedGameMaterial);
		if ( iItem != TSL_cItemNotFound )
		{
			m_bMaterialWasInList = TRUE;
			m_p_oMaterialListView->m_fn_bDeleteItem(iItem);
			m_p_oMaterialListView->m_fn_vChangeDisplayType(m_p_oMaterialListView->m_cDisplayType);
		}
		gs_p_oMaterialInterface->m_fn_vShowMaterialAll();
	}
	return bResult;
}

//=============================================================================
// undo/redo the material deletion
//=============================================================================
BOOL Material_DestroyMaterialModif::Undo()
{
	//reinsert the objects in the lists of the hierarchy editor
	m_p_oDeletedGameMaterial->fn_bValidate();
	m_p_oDeletedVisualMaterial->fn_bValidate();

	//and tell the scripts the objects have to be saved
	m_p_oDeletedGameMaterial->fn_vNotifyRestore();
	m_p_oDeletedVisualMaterial->fn_vNotifyRestore();

	//if the material was displayed before we removed it, make it visible again.
	//note that if this material has no links, it might appear nonetheless in the view
	//whereas the mode is to display only used materials...
	if ( m_bMaterialWasInList )
	{
		//get the handle to the bitmap for the material
		GLI_tdstTexture *p_stTexture;
		GLI_xGetMaterialTexture(m_p_oDeletedVisualMaterial->m_hGetEngineMaterial(), &p_stTexture);
		//find the bitmap used as texture
		int iImage;
		if (p_stTexture == NULL)
			iImage = m_p_oMaterialListView->m_fn_p_oGetBitmapList()->m_fn_iGetBitmapIndex(C_szNoBitmapName);
		else
			iImage = m_p_oMaterialListView->m_fn_p_oGetBitmapList()->m_fn_iGetBitmapIndexByLong((long) p_stTexture);
		//reinsert an item in the list
		m_p_oMaterialListView->m_fn_iAddItem(
			m_p_oDeletedGameMaterial->GetName(),
			(short) iImage,
			(long) m_p_oDeletedGameMaterial
		);
	}

	//now reenable the submaterials 
	BOOL bResult = TRUE;
	if ( m_p_oDeleteEngineMechanicsModif )
		bResult = m_p_oDeleteEngineMechanicsModif->Undo();
	if ( bResult && m_p_oDeleteEngineCollideModif )
		bResult = m_p_oDeleteEngineCollideModif->Undo();

	//and display the material we deleted
	gs_p_oMaterialInterface->m_fn_vShowMaterialAll(m_p_oDeletedGameMaterial);

	return TRUE;
}
