/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : W3DView                                                      *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/Tools/W3DView/DataTreeView.cpp               $*
 *                                                                                             *
 *                       Author:: Patrick Smith                                                *
 *                                                                                             *
 *                     $Modtime:: 6/18/01 9:11a                                               $*
 *                                                                                             *
 *                    $Revision:: 35                                                          $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */


#include "StdAfx.H"
#include "W3DView.H"
#include "DataTreeView.H"
#include "RendObj.H"
#include "ViewerAssetMgr.H"
#include "Globals.h"
#include "W3DViewDoc.H"
#include "MainFrm.H"
#include "DistLod.H"
#include "AnimObj.H"
#include "HcAnim.H"
#include "AssetInfo.H"
#include "Utils.H"
#include "Vector.H"
#include "Part_Emt.H"
#include "Agg_Def.H"
#include "BMP2D.H"
#include "HLod.H"
#include "ViewerScene.h"
#include "texture.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


////////////////////////////////////////////////////////////////////////////
//	Local Prototypes
////////////////////////////////////////////////////////////////////////////
void Set_Highest_LOD (RenderObjClass *render_obj);


////////////////////////////////////////////////////////////////////////////
//	MFC Stuff
////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CDataTreeView, CTreeView)


////////////////////////////////////////////////////////////////////////////
//
//  CDataTreeView
//
////////////////////////////////////////////////////////////////////////////
CDataTreeView::CDataTreeView (void)
        : m_hMaterialsRoot (NULL),          
			 m_hMeshRoot  (NULL),
			 m_hMeshCollectionRoot (NULL),
			 m_hAggregateRoot (NULL),
			 m_hPrimitivesRoot (NULL),
			 m_hEmitterRoot (NULL),
          m_hLODRoot (NULL),
			 m_hSoundRoot (NULL),
			 m_iPrimitivesIcon (-1),
          m_iAnimationIcon (-1),
          m_iTCAnimationIcon(-1),
			 m_iADAnimationIcon(-1),
          m_iMeshIcon (-1),
          m_iMaterialIcon (-1),
          m_iLODIcon (-1),
			 m_iAggregateIcon (-1),
			 m_iEmitterIcon (-1),
			 m_iSoundIcon (-1),
			 m_RestrictAnims (true)

{
    return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  ~CDataTreeView
//
CDataTreeView::~CDataTreeView (void)
{
    return ;
}


BEGIN_MESSAGE_MAP(CDataTreeView, CTreeView)
	//{{AFX_MSG_MAP(CDataTreeView)
	ON_WM_CREATE()
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelChanged)
	ON_NOTIFY_REFLECT(TVN_DELETEITEM, OnDeleteItem)
	ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


////////////////////////////////////////////////////////////////////////////
//
//  OnDraw
//
void
CDataTreeView::OnDraw (CDC *pDC)
{
	return ;
}

/////////////////////////////////////////////////////////////////////////////
// CDataTreeView diagnostics

#ifdef _DEBUG
void CDataTreeView::AssertValid() const
{
	CTreeView::AssertValid();
}

void CDataTreeView::Dump(CDumpContext& dc) const
{
	CTreeView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CDataTreeView message handlers


////////////////////////////////////////////////////////////////////////////
//
//  PreCreateWindow
//
BOOL
CDataTreeView::PreCreateWindow (CREATESTRUCT& cs) 
{
    // Modify the style bits for the window so it will
    // have buttons and lines between nodes.
    cs.style |= TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS;

    // Allow the base class to process this message
	return CTreeView::PreCreateWindow(cs);
}

////////////////////////////////////////////////////////////////////////////
//
//  OnInitialUpdate
//
void
CDataTreeView::OnInitialUpdate (void)
{
	// Allow the base class to process this message
    CTreeView::OnInitialUpdate ();
	
	// TODO: Add your specialized code here and/or call the base class
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  CreateRootNodes
//
void
CDataTreeView::CreateRootNodes (void) 
{
	// Insert all the root nodes
	m_hMaterialsRoot		= GetTreeCtrl ().InsertItem ("Materials", m_iMaterialIcon, m_iMaterialIcon);	
	m_hMeshRoot				= GetTreeCtrl ().InsertItem ("Mesh", m_iMeshIcon, m_iMeshIcon);
	m_hHierarchyRoot		= GetTreeCtrl ().InsertItem ("Hierarchy", m_iHierarchyIcon, m_iHierarchyIcon);
	m_hLODRoot				= GetTreeCtrl ().InsertItem ("H-LOD", m_iLODIcon, m_iLODIcon);
	m_hMeshCollectionRoot = GetTreeCtrl ().InsertItem ("Mesh Collection", m_iMeshIcon, m_iMeshIcon);
	m_hAggregateRoot		= GetTreeCtrl ().InsertItem ("Aggregate", m_iAggregateIcon, m_iAggregateIcon);    
	m_hEmitterRoot			= GetTreeCtrl ().InsertItem ("Emitter", m_iEmitterIcon, m_iEmitterIcon);	
	m_hPrimitivesRoot		= GetTreeCtrl ().InsertItem ("Primitives", m_iPrimitivesIcon, m_iPrimitivesIcon);
	m_hSoundRoot			= GetTreeCtrl ().InsertItem ("Sounds", m_iSoundIcon, m_iSoundIcon);
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnCreate
//
int
CDataTreeView::OnCreate (LPCREATESTRUCT lpCreateStruct) 
{
	if (CTreeView::OnCreate(lpCreateStruct) == -1)
		return -1;

    CImageList imageList;
    imageList.Create (16, 18, ILC_COLOR | ILC_MASK, 5, 10);
    
    // Add the icons to the imagelist
    m_iAnimationIcon		= imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_ANIMATION)));
	 m_iTCAnimationIcon	= imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_ANIMATION_COMPRESSED)));
	 m_iADAnimationIcon  = imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_ANIMATION_COMPRESSED_DELTA)));
    m_iMeshIcon			= imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_MESH)));
    m_iMaterialIcon		= imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_MATERIAL)));
    m_iLODIcon				= imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_LOD)));
	 m_iAggregateIcon		= imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_HIERARCHY)));
	 m_iEmitterIcon		= imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_HIERARCHY)));
	 m_iHierarchyIcon		= imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_HIERARCHY)));
	 m_iPrimitivesIcon	= imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_PRIMITIVES)));
	 m_iSoundIcon			= imageList.Add (::LoadIcon (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDI_SOUND)));

    // Pass the imagelist onto the tree control
    GetTreeCtrl ().SetImageList (&imageList, TVSIL_NORMAL);
    imageList.Detach ();

    // Create the root nodes that will hold the contain
    // asset types.
    CreateRootNodes ();
	return 0;
}


////////////////////////////////////////////////////////////////////////////
//
//  Load_Materials_Into_Tree
//
void
CDataTreeView::Load_Materials_Into_Tree (void) 
{
	// Get an iterator from the asset manager that we can
	// use to enumerate the currently loaded textures
	HashTemplateIterator<StringClass,TextureClass*> ite(WW3DAssetManager::Get_Instance()->Texture_Hash());
		
	// Loop through all the textures in the manager
	for (ite.First ();
		  !ite.Is_Done ();
		  ite.Next ()) {

		// Get the current texture name
		TextureClass* ptexture=ite.Peek_Value();
		LPCTSTR texture_name = ptexture->Get_Texture_Name();

		if ((ptexture != NULL) &&
			 FindChildItem (m_hMaterialsRoot, texture_name) == NULL) {

			// Add this entry to the tree
			HTREEITEM tree_item = GetTreeCtrl ().InsertItem (texture_name, m_iMaterialIcon, m_iMaterialIcon, m_hMaterialsRoot, TVI_SORT);
			ASSERT (tree_item != NULL);

			// Allocate a new asset information class to associate with this entry
			ptexture->Add_Ref ();
			AssetInfoClass *asset_info = new AssetInfoClass (texture_name, TypeMaterial, NULL, (DWORD)ptexture);
			GetTreeCtrl ().SetItemData (tree_item, (ULONG)asset_info);
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  LoadAssetsIntoTree
//
void
CDataTreeView::LoadAssetsIntoTree (void) 
{
	// Turn off repainting
	GetTreeCtrl ().SetRedraw (FALSE);

	DynamicVectorClass<CString> dist_lod_list;

	// Get an iterator from the asset manager that we can
	// use to enumerate the currently loaded assets
	RenderObjIterator *pObjEnum = WW3DAssetManager::Get_Instance()->Create_Render_Obj_Iterator ();
	ASSERT (pObjEnum);
	if (pObjEnum) {

		// Loop through all the assets in the manager
		for (pObjEnum->First ();
			  pObjEnum->Is_Done () == FALSE;
			  pObjEnum->Next ()) {

			// Does this render obj really exist?
			LPCTSTR pszItemName = pObjEnum->Current_Item_Name ();
			if (WW3DAssetManager::Get_Instance()->Render_Obj_Exists (pszItemName)) {
				
				BOOL bInsert = FALSE;
				HTREEITEM hParentNode = NULL;
				ASSET_TYPE assetType = TypeUnknown;
				int iIconIndex = -1;

				// What type of asset is this?
				switch (pObjEnum->Current_Item_Class_ID ()) {

					case RenderObjClass::CLASSID_COLLECTION:						
						// This is a 'mesh collection', we want to add this under the 'collection' node.
						bInsert = TRUE;
						hParentNode = m_hMeshCollectionRoot;
						assetType = TypeMesh;
						iIconIndex = m_iMeshIcon;
						break;

					//
					// This is a mesh render object, we want to add this under the mesh node.
					//
					case RenderObjClass::CLASSID_MESH:						
						bInsert			= TRUE;
						hParentNode		= m_hMeshRoot;
						assetType		= TypeMesh;
						iIconIndex		= m_iMeshIcon;
						break;

					//
					// This is a sound render obj, we want to add this under the sound node.
					//					
					case RenderObjClass::CLASSID_SOUND:
						bInsert			= TRUE;
						hParentNode		= m_hSoundRoot;
						assetType		= TypeSound;
						iIconIndex		= m_iSoundIcon;						
						break;

					case RenderObjClass::CLASSID_HMODEL:
						// Shouldn't happen
						ASSERT (0);
						break;

					case RenderObjClass::CLASSID_PARTICLEEMITTER:							
						// This is an 'emitter', we want to add this under the 'emitter' node.
						bInsert = TRUE;
						hParentNode = m_hEmitterRoot;
						assetType = TypeEmitter;
						iIconIndex = m_iEmitterIcon;
						break;

					case RenderObjClass::CLASSID_SPHERE:
					case RenderObjClass::CLASSID_RING:
						bInsert		= TRUE;
						hParentNode = m_hPrimitivesRoot;
						assetType	= TypePrimitives;
						iIconIndex	= m_iPrimitivesIcon;
						break;

					case RenderObjClass::CLASSID_DISTLOD:
						dist_lod_list.Add (pszItemName);
					case RenderObjClass::CLASSID_HLOD:
						// Assume this is a simple hierarchy LOD, we want to add this under the hierarchy node.
						bInsert = TRUE;
						hParentNode = m_hHierarchyRoot;
						assetType = TypeHierarchy;
						iIconIndex = m_iHierarchyIcon;

						// Test this HLOD to see if its a true LOD or a simple hierarchy
						if (::Is_Real_LOD (pszItemName)) {
							hParentNode = m_hLODRoot;
							assetType = TypeLOD;
							iIconIndex = m_iLODIcon;
						}
						break;
				}

				if (bInsert) {

					// Check to see if this object is an aggregate
					if (::Is_Aggregate (pszItemName)) {
						hParentNode = m_hAggregateRoot;
						assetType = TypeAggregate;
						iIconIndex = m_iAggregateIcon;
					}

					// If this object isn't already in the tree then add it
					if (FindChildItem (hParentNode, pszItemName) == NULL) {

						// Add this entry to the tree
						HTREEITEM hItem = GetTreeCtrl ().InsertItem (pszItemName, iIconIndex, iIconIndex, hParentNode, TVI_SORT);
						ASSERT (hItem != NULL);

						// Allocate a new asset information class to associate with this entry
						AssetInfoClass *asset_info = new AssetInfoClass (pszItemName, assetType);
						GetTreeCtrl ().SetItemData (hItem, (ULONG)asset_info);
					}
				}
			}
		}

		// Free the enumerator object we created earlier
		SAFE_DELETE (pObjEnum);
	}

	// Loop through all the old-style dist lod's and convert their prototypes
	// to the new HLOD format
	for (int index = 0; index < dist_lod_list.Count (); index ++) {
		HLodClass *plod = (HLodClass *)WW3DAssetManager::Get_Instance ()->Create_Render_Obj (dist_lod_list[index]);
		if (plod != NULL) {
			HLodDefClass *definition = new HLodDefClass (*plod);
			HLodPrototypeClass *prototype = new HLodPrototypeClass (definition);
			WW3DAssetManager::Get_Instance ()->Remove_Prototype (dist_lod_list[index]);
			WW3DAssetManager::Get_Instance ()->Add_Prototype (prototype);
		}
	}

	// Now that we've added all the hierarchies to the tree, add their animations
	// as well.
	LoadAnimationsIntoTree ();
	Load_Materials_Into_Tree ();

	// Turn;repainting back on
	GetTreeCtrl ().SetRedraw (TRUE);

	// Force the window to be repainted
	Invalidate (FALSE);
	UpdateWindow ();
	return ;
}

////////////////////////////////////////////////////////////////////////////
//
//  LoadAnimationsIntoTree
//
void
CDataTreeView::LoadAnimationsIntoTree (void)
{
    // Get an iterator from the asset manager that we can
    // use to enumerate the currently loaded assets
    AssetIterator *pAnimEnum = WW3DAssetManager::Get_Instance()->Create_HAnim_Iterator ();
    ASSERT (pAnimEnum);
    if (pAnimEnum)
    {
        // Loop through all the animations in the manager
        for (pAnimEnum->First ();
             (pAnimEnum->Is_Done () == FALSE);
             pAnimEnum->Next ())
        {
            LPCTSTR pszAnimName = pAnimEnum->Current_Item_Name ();

            // Get an instance of the animation object
            HAnimClass *pHierarchyAnim = WW3DAssetManager::Get_Instance()->Get_HAnim (pszAnimName);
            
            ASSERT (pHierarchyAnim);
            if (pHierarchyAnim)
            {
                // Get the name of the hierarchy that this animation belongs to
                LPCTSTR pszHierarchyName = pHierarchyAnim->Get_HName ();

                // Loop through all the hierarchies and add this animation to any pertinent ones
                for (HTREEITEM hNode = FindFirstChildItemBasedOnHierarchyName (m_hHierarchyRoot, pszHierarchyName);
                     (hNode != NULL);
                     hNode = FindSiblingItemBasedOnHierarchyName (hNode, pszHierarchyName))
                {
                    // Is this animation already loaded into the tree?
                    HTREEITEM hAnimationNode = FindChildItem (hNode, pszAnimName);
                    if (hAnimationNode == NULL)
                    {
                        // Add this animation as a child of the hierarchy
                        hAnimationNode = GetTreeCtrl ().InsertItem (pszAnimName, m_iAnimationIcon, m_iAnimationIcon, hNode, TVI_SORT);
                        ASSERT (hAnimationNode != NULL);
                                    
                        // Associate the items name with its entry
                        GetTreeCtrl ().SetItemData (hAnimationNode, (ULONG)new AssetInfoClass (pszAnimName, TypeAnimation));
                    }
                }

                // Loop through all the aggregates and add this animation to any pertinent ones
                for (hNode = FindFirstChildItemBasedOnHierarchyName (m_hAggregateRoot, pszHierarchyName);
                     (hNode != NULL);
                     hNode = FindSiblingItemBasedOnHierarchyName (hNode, pszHierarchyName))
                {
                    // Is this animation already loaded into the tree?
                    HTREEITEM hAnimationNode = FindChildItem (hNode, pszAnimName);
                    if (hAnimationNode == NULL)
                    {
                        // Add this animation as a child of the hierarchy
                        hAnimationNode = GetTreeCtrl ().InsertItem (pszAnimName, m_iAnimationIcon, m_iAnimationIcon, hNode, TVI_SORT);
                        ASSERT (hAnimationNode != NULL);
                                    
                        // Associate the items name with its entry
                        GetTreeCtrl ().SetItemData (hAnimationNode, (ULONG)new AssetInfoClass (pszAnimName, TypeAnimation));
                    }
                }

                // Loop through all the hierarchies and add this animation to any pertinent ones
                for (hNode = FindFirstChildItemBasedOnHierarchyName (m_hLODRoot, pszHierarchyName);
                     (hNode != NULL);
                     hNode = FindSiblingItemBasedOnHierarchyName (hNode, pszHierarchyName))
                {
                    // Is this animation already loaded into the tree?
                    HTREEITEM hAnimationNode = FindChildItem (hNode, pszAnimName);
                    if (hAnimationNode == NULL)
                    {
                        // Add this animation as a child of the hierarchy
                        hAnimationNode = GetTreeCtrl ().InsertItem (pszAnimName, m_iAnimationIcon, m_iAnimationIcon, hNode, TVI_SORT);
                        ASSERT (hAnimationNode != NULL);
                                    
                        // Associate the items name with its entry
                        GetTreeCtrl ().SetItemData (hAnimationNode, (ULONG)new AssetInfoClass (pszAnimName, TypeAnimation));
                    }
                }

                // Release our hold on this animation...
					 MEMBER_RELEASE (pHierarchyAnim);
            }							
        }
        
        // Free the object
        delete pAnimEnum;
        pAnimEnum = NULL;
    }
    
    return ;
}

////////////////////////////////////////////////////////////////////////////
//
//  LoadAnimationsIntoTree
//
void
CDataTreeView::LoadAnimationsIntoTree (HTREEITEM hItem)
{
    // Get the data associated with this item
    AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (hItem);
    ASSERT (asset_info != NULL);

    // Get an iterator from the asset manager that we can
    // use to enumerate the currently loaded assets
    AssetIterator *pAnimEnum = WW3DAssetManager::Get_Instance()->Create_HAnim_Iterator ();
    ASSERT (pAnimEnum);
    if (pAnimEnum)
    {
        // Loop through all the animations in the manager
        for (pAnimEnum->First ();
             (pAnimEnum->Is_Done () == FALSE);
             pAnimEnum->Next ())
        {
            LPCTSTR pszAnimName = pAnimEnum->Current_Item_Name ();

            // Get an instance of the animation object
            HAnimClass *pHierarchyAnim = WW3DAssetManager::Get_Instance()->Get_HAnim (pszAnimName);
            
            ASSERT (pHierarchyAnim);
            if (pHierarchyAnim)
            {
                // Get the name of the hierarchy that this animation belongs to
                LPCTSTR pszHierarchyName = pHierarchyAnim->Get_HName ();

                // Does the item match the hierarchy name?
                if (::lstrcmp (asset_info->Get_Hierarchy_Name (), pszHierarchyName) == 0)
                {
                    // Is this animation already loaded into the tree?
                    HTREEITEM hAnimationNode = FindChildItem (hItem, pszAnimName);
                    if (hAnimationNode == NULL)
                    {
                        // Add this animation as a child of the hierarchy
                        hAnimationNode = GetTreeCtrl ().InsertItem (pszAnimName, m_iAnimationIcon, m_iAnimationIcon, hItem, TVI_SORT);
                        ASSERT (hAnimationNode != NULL);
                                    
                        // Associate the items name with its entry
                        GetTreeCtrl ().SetItemData (hAnimationNode, (ULONG)new AssetInfoClass (pszAnimName, TypeAnimation));
                    }
                }

                // Release our hold on the animation object
                MEMBER_RELEASE (pHierarchyAnim);
            }				
        }
        
        // Free the object
        delete pAnimEnum;
        pAnimEnum = NULL;
    }
    
    return ;
}
   

////////////////////////////////////////////////////////////////////////////
//
//  Determine_Tree_Location
//
ASSET_TYPE
CDataTreeView::Determine_Tree_Location
(
	RenderObjClass &render_obj,
	HTREEITEM &hroot,
	int &icon_index
)
{
	ASSET_TYPE type = TypeUnknown;

	// What class does this render object belong to?
	switch (render_obj.Class_ID ()) {
		
		case RenderObjClass::CLASSID_COLLECTION:
			hroot				= m_hMeshCollectionRoot;
			type				= TypeMesh;
			icon_index		= m_iMeshIcon;
			break;

		case RenderObjClass::CLASSID_MESH:
			hroot = m_hMeshRoot;
			type = TypeMesh;
			icon_index = m_iMeshIcon;
			break;						  
		
		case RenderObjClass::CLASSID_SOUND:
			hroot				= m_hSoundRoot;
			type				= TypeSound;
			icon_index		= m_iSoundIcon;
			break;						  		

		case RenderObjClass::CLASSID_HMODEL:			
			// Shouldn't happen
			ASSERT (0);
			break;

		case RenderObjClass::CLASSID_PARTICLEEMITTER:
			hroot				= m_hEmitterRoot;
			type				= TypeEmitter;
			icon_index		= m_iEmitterIcon;
			break;

		case RenderObjClass::CLASSID_SPHERE:
		case RenderObjClass::CLASSID_RING:
			hroot				= m_hPrimitivesRoot;
			type				= TypePrimitives;
			icon_index		= m_iPrimitivesIcon;
			break;
	
		case RenderObjClass::CLASSID_DISTLOD:
		case RenderObjClass::CLASSID_HLOD:
         hroot				= m_hHierarchyRoot;
         type				= TypeHierarchy;
         icon_index		= m_iHierarchyIcon;

			//
			// Determine if this is a true LOD or a simple hierarchy
			//
			if (((HLodClass &)render_obj).Get_LOD_Count () > 1) {
				hroot			= m_hLODRoot;
				type			= TypeLOD;
				icon_index	= m_iLODIcon;
			}
			break;
	}

	//
	// Is this an aggregate?
	//
	if (render_obj.Get_Base_Model_Name () != NULL) {
		hroot			= m_hAggregateRoot;
		type			= TypeAggregate;
		icon_index	= m_iAggregateIcon;
	}

	// Return the type of node
	return type;
}



////////////////////////////////////////////////////////////////////////////
//
//  Determine_Tree_Location
//
void
CDataTreeView::Determine_Tree_Location
(
	ASSET_TYPE type,
	HTREEITEM &hroot,
	int &icon_index
)
{
	// What type of asset is this?
	switch (type) {

		case TypeMesh:
			hroot			= m_hMeshRoot;
			icon_index	= m_iMeshIcon;
			break;

		case TypeSound:
			hroot			= m_hSoundRoot;
			icon_index	= m_iSoundIcon;
			break;

		case TypeAggregate:
			hroot			= m_hAggregateRoot;
			icon_index	= m_iAggregateIcon;
			break;

		case TypeHierarchy:
			// Shouldn't happen
			ASSERT (0);
			break;

		case TypeEmitter:
			hroot			= m_hEmitterRoot;
			icon_index	= m_iEmitterIcon;
			break;

		case TypePrimitives:
			hroot			= m_hPrimitivesRoot;
			icon_index	= m_iPrimitivesIcon;
			break;

		case TypeLOD:
			hroot			= m_hLODRoot;
			icon_index	= m_iLODIcon;
			break;
	}

	return ;
}



////////////////////////////////////////////////////////////////////////////
//
//  Add_Asset_To_Tree
//
bool
CDataTreeView::Add_Asset_To_Tree
(
	LPCTSTR name,
	ASSET_TYPE type,
	bool bselect
)
{
	// Assume failure
	bool retval = false;

	// Param OK?
	ASSERT (name != NULL);
	if (name != NULL) {

		// Turn off repainting
		GetTreeCtrl ().SetRedraw (FALSE);
		
		// Determime where this asset should go
		HTREEITEM hparent = NULL;
		int icon_index = 0;
		Determine_Tree_Location (type, hparent, icon_index);

		// Is this asset already in the tree?
		HTREEITEM htree_item = FindChildItem (hparent, name);
		if (htree_item == NULL) {

			// Add this object to the tree
			htree_item = GetTreeCtrl ().InsertItem (name,
																 icon_index,
																 icon_index,
																 hparent,
																 TVI_SORT);
			
			// Associate the render object with its entry in the tree
			AssetInfoClass *asset_info = new AssetInfoClass (name, type);
			GetTreeCtrl ().SetItemData (htree_item, (ULONG)asset_info);

			// Load the object's animations into the tree (if necessary)
			if (asset_info->Can_Asset_Have_Animations ()) {
				LoadAnimationsIntoTree (htree_item);
			}

			// Success!
			retval = (htree_item != NULL);
		}

		// Select the instance (if requested)
		if (bselect) {
			GetTreeCtrl ().SelectItem (htree_item);
			GetTreeCtrl ().EnsureVisible (htree_item);
		}

		// Turn painting back on
		GetTreeCtrl ().SetRedraw (TRUE);

		// Force the window to be repainted
		Invalidate (FALSE);
		UpdateWindow ();
	}

	// Return the true/false result code
	return retval;
}


////////////////////////////////////////////////////////////////////////////
//
//  FindChildItem
//
HTREEITEM
CDataTreeView::FindChildItem
(
	HTREEITEM hParentItem,
	RenderObjClass *prender_obj
)
{
	// Assume we won't find the item
	HTREEITEM hchild_item = NULL;

	// Loop through all the children of this node
	for (HTREEITEM htree_item = GetTreeCtrl ().GetChildItem (hParentItem);
		  (htree_item != NULL) && (hchild_item == NULL);
		  htree_item = GetTreeCtrl ().GetNextSiblingItem (htree_item)) {

		// Get the data associated with this item
		AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (htree_item);

		// Is this the item we were looking for?
		if (asset_info &&
			 asset_info->Peek_Render_Obj () == prender_obj) {

			// This was the item we were looking for, return
			// its handle to the caller
			hchild_item = htree_item;
		}
	}

	// Return the child item handle
	return hchild_item;
}


////////////////////////////////////////////////////////////////////////////
//
//  FindChildItem
//
HTREEITEM
CDataTreeView::FindChildItem
(
    HTREEITEM hParentItem,
    LPCTSTR pszChildItemName
)
{
    // Assume we won't find the item
    HTREEITEM hChildItem = NULL;

    // Loop through all the children of this node
    for (HTREEITEM hTreeItem = GetTreeCtrl ().GetChildItem (hParentItem);
         (hTreeItem != NULL) && (hChildItem == NULL);
         hTreeItem = GetTreeCtrl ().GetNextSiblingItem (hTreeItem))
    {
        // Is this the child item we were looking for?
        if (::lstrcmp (GetTreeCtrl ().GetItemText (hTreeItem), pszChildItemName) == 0)
        {
            // This was the child item we were looking for, return
            // its handle to the caller
            hChildItem = hTreeItem;
        }
    }

    // Return the child item handle
    return hChildItem;
}

////////////////////////////////////////////////////////////////////////////
//
//  FindSiblingItemBasedOnHierarchyName
//
HTREEITEM
CDataTreeView::FindSiblingItemBasedOnHierarchyName
(
    HTREEITEM hCurrentItem,
    LPCTSTR pszHierarchyName
)
{
    // Assume we won't find the item
    HTREEITEM hSiblingItem = NULL;

    // Loop through all the siblings of this node
    HTREEITEM hTreeItem = hCurrentItem;
    while (((hTreeItem = GetTreeCtrl ().GetNextSiblingItem (hTreeItem)) != NULL) &&
           (hSiblingItem == NULL))
    {
        // Get the data associated with this item
        AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (hTreeItem);

        // Is this the item we were looking for?
        if (m_RestrictAnims == false ||
				(asset_info && ::lstrcmp (asset_info->Get_Hierarchy_Name (), pszHierarchyName) == 0))
        {
            // This was the item we were looking for, return
            // its handle to the caller
            hSiblingItem = hTreeItem;
        }        
    }

    // Return the sibling item handle
    return hSiblingItem;
}

////////////////////////////////////////////////////////////////////////////
//
//  FindFirstChildItemBasedOnHierarchyName
//
HTREEITEM
CDataTreeView::FindFirstChildItemBasedOnHierarchyName
(
    HTREEITEM hParentItem,
    LPCTSTR pszHierarchyName
)
{
    // Assume we won't find the item
    HTREEITEM hChildItem = NULL;

    // Loop through all the children of this node
    for (HTREEITEM hTreeItem = GetTreeCtrl ().GetChildItem (hParentItem);
         (hTreeItem != NULL) && (hChildItem == NULL);
         hTreeItem = GetTreeCtrl ().GetNextSiblingItem (hTreeItem))
    {
        // Get the data associated with this item
        AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (hTreeItem);

        //
		  // Is this the item we were looking for?
		  //
        if (m_RestrictAnims == false ||
				(asset_info && ::lstrcmp (asset_info->Get_Hierarchy_Name (), pszHierarchyName) == 0))
        {
            // This was the child item we were looking for, return
            // its handle to the caller
            hChildItem = hTreeItem;
        }        
    }

    // Return the child item handle
    return hChildItem;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnSelChanged
//
void
CDataTreeView::OnSelChanged
(
    NMHDR* pNMHDR,
    LRESULT* pResult
)
{
	// Display the new selection
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	Display_Asset (pNMTreeView->itemNew.hItem);
	(*pResult) = 0;
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Display_Asset
//
void
CDataTreeView::Display_Asset (HTREEITEM htree_item)
{
	if (htree_item == NULL) {
		htree_item = GetTreeCtrl ().GetSelectedItem ();
	}

	//
	// Get the object associated with this entry
	//
	AssetInfoClass *asset_info = NULL;	
	if (htree_item != NULL) {
		asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (htree_item);
	}

	if (asset_info != NULL) {

		// Get the current document, so we can get a pointer to the scene
		CW3DViewDoc *pdoc = (CW3DViewDoc *)GetDocument ();
		ASSERT (pdoc != NULL);
		if (pdoc != NULL) {

			// What type of asset is it?
			switch (asset_info->Get_Type ())
			{
				case TypeCompressedAnimation:
				case TypeAnimation:
				{
					HTREEITEM hParentItem = GetTreeCtrl ().GetParentItem (htree_item);
					if (hParentItem != NULL) {

						// Ask the document to start playing the animation for this object
						RenderObjClass *prender_obj = Create_Render_Obj_To_Display (hParentItem);                         
						pdoc->PlayAnimation (prender_obj,
						asset_info->Get_Name ());
						MEMBER_RELEASE (prender_obj);
					}
				}
				break;

				case TypeEmitter:
				{
					// Ask the document to display this object
					ParticleEmitterClass *emitter = (ParticleEmitterClass *)Create_Render_Obj_To_Display (htree_item);
					pdoc->Display_Emitter (emitter);
					MEMBER_RELEASE (emitter);
				}
				break;

				case TypeHierarchy:
				{
					// If the advanced animation option is turned on, display a dialog
					// where the user can choose which animations to play together.

				}

				default:
				{
					// Ask the document to display this object
					RenderObjClass *prender_obj = Create_Render_Obj_To_Display (htree_item);
					pdoc->DisplayObject (prender_obj);
					MEMBER_RELEASE (prender_obj);
				}
				break;
			}

			// Get the main window of our app
			CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
			if (pCMainWnd != NULL) {

				// Let the main window know our selection type has changed
				pCMainWnd->OnSelectionChanged (asset_info->Get_Type ());

				if (asset_info->Get_Type () == TypeAggregate) {
					pCMainWnd->Update_Emitters_List ();
				} else {

					::EnableMenuItem (::GetSubMenu (::GetMenu (*pCMainWnd), 3), 3, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
					HMENU hsub_menu = pCMainWnd->Get_Emitters_List_Menu ();
					int index = 0;
					while (::RemoveMenu (hsub_menu, index, MF_BYPOSITION)) {
						//index ++;
					}
				}
			}
		}
	} else {

		// Reset the display
		CW3DViewDoc* pdoc = (CW3DViewDoc *)GetDocument ();
		ASSERT (pdoc != NULL);
		if (pdoc != NULL) {
			pdoc->DisplayObject ((RenderObjClass *)NULL);
			
			CMainFrame *main_wnd = (CMainFrame *)::AfxGetMainWnd ();
			if (main_wnd != NULL) {
				main_wnd->OnSelectionChanged (TypeUnknown);
			}
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  OnDeleteItem
//
void
CDataTreeView::OnDeleteItem
(
	NMHDR *pNMHDR,
	LRESULT *pResult
) 
{
	// Get the information object for this asset
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;	
	AssetInfoClass *asset_info = (AssetInfoClass *)pNMTreeView->itemOld.lParam;
	
	// If this is a texture, then free our hold on its interface
	if (asset_info && (asset_info->Get_Type () == TypeMaterial)) {
		TextureClass *ptexture = (TextureClass *)asset_info->Get_User_Number ();
		REF_PTR_RELEASE (ptexture);
	}

	// Free the asset information object
	SAFE_DELETE (asset_info);

	// Reset the data associated with this entry
	GetTreeCtrl ().SetItemData (pNMTreeView->itemOld.hItem, NULL);
	(*pResult) = 0;
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Get_Current_Asset_Info
//
AssetInfoClass *
CDataTreeView::Get_Current_Asset_Info (void) const
{
	AssetInfoClass *asset_info = NULL;

	// Get the currently selected node from the tree control
	HTREEITEM htree_item = GetTreeCtrl ().GetSelectedItem ();
	if (htree_item != NULL) {

		// Get the data associated with this item
		asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (htree_item);
	}

	// Return the asset information associated with the current item
	return asset_info;
}


////////////////////////////////////////////////////////////////////////////
//
//  Get_Current_Render_Obj
//
RenderObjClass *
CDataTreeView::Get_Current_Render_Obj (void) const
{
	RenderObjClass *prender_obj = NULL;

	// Get the currently selected node from the tree control
	HTREEITEM htree_item = GetTreeCtrl ().GetSelectedItem ();
	if (htree_item != NULL) {

		// Get the data associated with this item
		AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (htree_item);
		if (asset_info != NULL) {

			// Return the render object pointer
			prender_obj = asset_info->Peek_Render_Obj ();
		}
	}

	// Return the render object pointer
	return prender_obj;
}


////////////////////////////////////////////////////////////////////////////
//
//  GetCurrentSelectionName
//
LPCTSTR
CDataTreeView::GetCurrentSelectionName (void)
{
	LPCTSTR pname = NULL;

	// Get the currently selected node from the tree control
	HTREEITEM htree_item = GetTreeCtrl ().GetSelectedItem ();
	if (htree_item != NULL) {

		// Get the data associated with this item
		AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (htree_item);
		if (asset_info != NULL) {

			// Return the name of the asset to the caller
			pname = asset_info->Get_Name ();
		}
	}

	// Return the name of the selected node
	return pname;
}

////////////////////////////////////////////////////////////////////////////
//
//  GetCurrentSelectionType
//
ASSET_TYPE
CDataTreeView::GetCurrentSelectionType (void)
{
	ASSET_TYPE type = TypeUnknown;

	// Get the currently selected node from the tree control
	HTREEITEM htree_item = GetTreeCtrl ().GetSelectedItem ();
	if (htree_item != NULL) {
		
		// Get the associated asset information for this node.
		AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (htree_item);
		if (asset_info != NULL) {
			type = asset_info->Get_Type ();
		}
	}

	// Return the type of the selected node
	return type;
}

////////////////////////////////////////////////////////////////////////////
//
//  OnDblclk
//
void
CDataTreeView::OnDblclk
(
    NMHDR* pNMHDR,
    LRESULT* pResult
)
{
    // Get the main window of our app
    CMainFrame *pCMainWnd = (CMainFrame *)::AfxGetMainWnd ();
    if (pCMainWnd != NULL)
    {
        // Display the properties for the currently selected object
        //pCMainWnd->ShowObjectProperties ();
    }

	(*pResult) = 0;
    return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Build_Render_Object_List
//
void
CDataTreeView::Build_Render_Object_List
(
	DynamicVectorClass <CString> &asset_list,
	HTREEITEM hparent
)
{
	// Loop through all the children of this node
	for (HTREEITEM htree_item = GetTreeCtrl ().GetChildItem (hparent);
		  (htree_item != NULL);
		  htree_item = GetTreeCtrl ().GetNextSiblingItem (htree_item)) {		

		// Determine if this is an asset type we want to add to the list
		AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (htree_item);
		if ((asset_info != NULL) &&
			 (asset_info->Get_Type () != TypeAnimation) &&
			 (asset_info->Get_Type () != TypeCompressedAnimation) &&
			 (asset_info->Get_Type () != TypeMaterial))
		{
			asset_list.Add (GetTreeCtrl ().GetItemText (htree_item));
		}

		// If this item has children, then add the children recursively
		if (GetTreeCtrl ().ItemHasChildren (htree_item)) {
			Build_Render_Object_List (asset_list, htree_item);
		}
	}
	
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Create_Render_Obj_To_Display
//
////////////////////////////////////////////////////////////////////////////
RenderObjClass *
CDataTreeView::Create_Render_Obj_To_Display (HTREEITEM htree_item)
{
	// Lookup the information object associated with this asset
	RenderObjClass *render_obj = NULL;
	AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (htree_item);
	if (asset_info != NULL) {
		
		// Use the asset's instance if there is one, otherwise attempt to create one
		render_obj = asset_info->Get_Render_Obj ();
		if (render_obj == NULL) {

			// If this is a texture, then create a special BMP obj from it
			if (asset_info->Get_Type () == TypeMaterial) {
				TextureClass *ptexture = (TextureClass *)asset_info->Get_User_Number ();
				if (ptexture != NULL) {
					render_obj = new Bitmap2DObjClass (ptexture, 0.5F, 0.5F, true, false, false, true);
				}
			}

			//
			// Finally, if we aren't successful, create a new instance based on its name
			//
			if (render_obj == NULL) {
				render_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj (asset_info->Get_Name ());				
			}
		}
	}

	//
	//	Force the highest level LOD
	//
	if (	render_obj != NULL &&
			::GetCurrentDocument ()->GetScene ()->Are_LODs_Switching () == false)
	{
		Set_Highest_LOD (render_obj);
	}
	
	return render_obj;
}


////////////////////////////////////////////////////////////////////////////
//
//  Refresh_Asset
//
void
CDataTreeView::Refresh_Asset
(
	LPCTSTR new_name,
	LPCTSTR old_name,
	ASSET_TYPE type
)
{
	// Params OK?
	if ((new_name != NULL) && (old_name != NULL)) {

		// Turn off repainting
		GetTreeCtrl ().SetRedraw (FALSE);
		
		// Determime where this asset should go
		HTREEITEM hparent = NULL;
		int icon_index = 0;
		Determine_Tree_Location (type, hparent, icon_index);

		// Can we find the item we are supposed to refresh?
		HTREEITEM htree_item = FindChildItem (hparent, old_name);
		if (htree_item != NULL) {

			// Refresh the item's text in the tree control
			GetTreeCtrl ().SetItemText (htree_item, new_name);

			// Refresh the associated asset info structure
			AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (htree_item);
			if (asset_info != NULL) {
				asset_info->Set_Name (new_name);
			}		
		} else {

			// This asset wasn't already in the tree, so add it...
			Add_Asset_To_Tree (new_name, type, true);
		}

		// Turn painting back on
		GetTreeCtrl ().SetRedraw (TRUE);

		// Force the window to be repainted
		Invalidate (FALSE);
		UpdateWindow ();	
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Select_Next
//
void
CDataTreeView::Select_Next (void)
{
	//
	//	Get the selected entry in the tree control
	//
	HTREEITEM hselected = GetTreeCtrl ().GetSelectedItem ();
	if (hselected != NULL) {

		//
		//	Select the item that follows the currently selected item
		//
		HTREEITEM hitem = GetTreeCtrl ().GetNextItem (hselected, TVGN_NEXT);
		if (hitem != NULL) {
			GetTreeCtrl ().SelectItem (hitem);
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Select_Prev
//
void
CDataTreeView::Select_Prev (void)
{
	//
	//	Get the selected entry in the tree control
	//
	HTREEITEM hselected = GetTreeCtrl ().GetSelectedItem ();
	if (hselected != NULL) {

		//
		//	Select the item that follows the currently selected item
		//
		HTREEITEM hitem = GetTreeCtrl ().GetNextItem (hselected, TVGN_PREVIOUS);
		if (hitem != NULL) {
			GetTreeCtrl ().SelectItem (hitem);
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Reload_Lightmap_Models
//
////////////////////////////////////////////////////////////////////////////
void
CDataTreeView::Reload_Lightmap_Models (void)
{
	Free_Child_Models (m_hMeshCollectionRoot);
	Free_Child_Models (m_hHierarchyRoot);
	Free_Child_Models (m_hMeshRoot);
	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Free_Child_Models
//
////////////////////////////////////////////////////////////////////////////
void
CDataTreeView::Free_Child_Models (HTREEITEM parent_item)
{
	//
	// Loop through all the children of this node
	//
	for (	HTREEITEM tree_item = GetTreeCtrl ().GetChildItem (parent_item);
			tree_item != NULL;
			tree_item = GetTreeCtrl ().GetNextSiblingItem (tree_item))
	{
		//
		// Get the data associated with this item
		//
		AssetInfoClass *asset_info = (AssetInfoClass *)GetTreeCtrl ().GetItemData (tree_item);
		if (asset_info  != NULL) {
			WW3DAssetManager::Get_Instance ()->Remove_Prototype (asset_info->Get_Name ());
		}        
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Set_Highest_LOD
//
////////////////////////////////////////////////////////////////////////////
void
Set_Highest_LOD (RenderObjClass *render_obj) 
{
	if (render_obj != NULL) {
		for (int index = 0; index < render_obj->Get_Num_Sub_Objects (); index ++) {
			RenderObjClass *sub_obj = render_obj->Get_Sub_Object (index);
			if (sub_obj != NULL) {
				Set_Highest_LOD (sub_obj);
			}
			MEMBER_RELEASE (sub_obj);
		}

		//
		// Switcht this LOD to its highest level
		//
		if (render_obj->Class_ID () == RenderObjClass::CLASSID_HLOD) {
			((HLodClass *)render_obj)->Set_LOD_Level (((HLodClass *)render_obj)->Get_Lod_Count () - 1);
		}
	}

	return ;
}


////////////////////////////////////////////////////////////////////////////
//
//  Restrict_Anims
//
////////////////////////////////////////////////////////////////////////////
void
CDataTreeView::Restrict_Anims (bool onoff)
{
	if (m_RestrictAnims != onoff) {
		m_RestrictAnims = onoff;
		
		//
		//	Reload the tree
		//
		GetTreeCtrl ().DeleteAllItems ();
		CreateRootNodes ();
		LoadAssetsIntoTree ();
	}

	return ;
}

