#include "precompiled.h" #include "ObjectManager.h" #include "graphics/ObjectBase.h" #include "graphics/ObjectEntry.h" #include "ps/CLogger.h" #include "ps/Profile.h" #include "ps/Filesystem.h" #define LOG_CATEGORY "graphics" template static void delete_pair_2nd(std::pair v) { delete v.second; } template struct second_equals { T x; second_equals(const T& x) : x(x) {} template bool operator()(const S& v) { return v.second == x; } }; bool operator< (const CObjectManager::ObjectKey& a, const CObjectManager::ObjectKey& b) { if (a.ActorName < b.ActorName) return true; else if (a.ActorName > b.ActorName) return false; else return a.ActorVariation < b.ActorVariation; } CObjectManager::CObjectManager(CMeshManager& meshManager, CSkeletonAnimManager& skeletonAnimManager) : m_MeshManager(meshManager), m_SkeletonAnimManager(skeletonAnimManager) { } CObjectManager::~CObjectManager() { UnloadObjects(); } CObjectBase* CObjectManager::FindObjectBase(const char* objectname) { debug_assert(strcmp(objectname, "") != 0); // See if the base type has been loaded yet: std::map::iterator it = m_ObjectBases.find(objectname); if (it != m_ObjectBases.end()) return it->second; // Not already loaded, so try to load it: CObjectBase* obj = new CObjectBase(*this); if (obj->Load(objectname)) { m_ObjectBases[objectname] = obj; return obj; } else delete obj; LOG(CLogger::Error, LOG_CATEGORY, "CObjectManager::FindObjectBase(): Cannot find object '%s'", objectname); return 0; } CObjectEntry* CObjectManager::FindObject(const char* objname) { std::vector > selections; // TODO - should this really be empty? return FindObjectVariation(objname, selections); } CObjectEntry* CObjectManager::FindObjectVariation(const char* objname, const std::vector >& selections) { CObjectBase* base = FindObjectBase(objname); if (! base) return NULL; return FindObjectVariation(base, selections); } CObjectEntry* CObjectManager::FindObjectVariation(CObjectBase* base, const std::vector >& selections) { PROFILE( "object variation loading" ); // Look to see whether this particular variation has already been loaded std::vector choices = base->CalculateVariationKey(selections); ObjectKey key (base->m_Name, choices); std::map::iterator it = m_Objects.find(key); if (it != m_Objects.end()) return it->second; // If it hasn't been loaded, load it now CObjectEntry* obj = new CObjectEntry(base); // TODO: type ? // TODO (for some efficiency): use the pre-calculated choices for this object, // which has already worked out what to do for props, instead of passing the // selections into BuildVariation and having it recalculate the props' choices. if (! obj->BuildVariation(selections, choices, *this)) { DeleteObject(obj); return NULL; } m_Objects[key] = obj; return obj; } void CObjectManager::DeleteObject(CObjectEntry* entry) { std::map::iterator it; while (m_Objects.end() != (it = find_if(m_Objects.begin(), m_Objects.end(), second_equals(entry)))) m_Objects.erase(it); delete entry; } void CObjectManager::UnloadObjects() { std::for_each( m_Objects.begin(), m_Objects.end(), delete_pair_2nd ); m_Objects.clear(); std::for_each( m_ObjectBases.begin(), m_ObjectBases.end(), delete_pair_2nd ); m_ObjectBases.clear(); } static LibError GetObjectName_ThunkCb(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), uintptr_t cbData) { std::vector* names = (std::vector*)cbData; CStr name(pathname.string()); names->push_back(name.AfterFirst("actors/")); return INFO::CB_CONTINUE; } void CObjectManager::GetAllObjectNames(std::vector& names) { fs_ForEachFile(g_VFS, "art/actors/", GetObjectName_ThunkCb, (uintptr_t)&names, "*.xml", DIR_RECURSIVE); } void CObjectManager::GetPropObjectNames(std::vector& names) { fs_ForEachFile(g_VFS, "art/actors/props/", GetObjectName_ThunkCb, (uintptr_t)&names, "*.xml", DIR_RECURSIVE); }