/// Recursive function for resolving a package request. /// /// @param[out] rspPackage Resolved package. /// @param[in] packagePath Package object path. void CachePackageLoader::ResolvePackage( AssetPtr& rspPackage, AssetPath packagePath ) { HELIUM_ASSERT( !packagePath.IsEmpty() ); rspPackage = Asset::FindObject( packagePath ); if( !rspPackage ) { AssetPtr spParent; AssetPath parentPath = packagePath.GetParent(); if( !parentPath.IsEmpty() ) { ResolvePackage( spParent, parentPath ); HELIUM_ASSERT( spParent ); } HELIUM_VERIFY( Asset::CreateObject( rspPackage, Package::GetStaticType(), packagePath.GetName(), spParent ) ); HELIUM_ASSERT( rspPackage ); HELIUM_ASSERT( rspPackage->IsA( Package::GetStaticType()->GetMetaClass() ) ); } rspPackage->SetFlags( Asset::FLAG_PRELOADED | Asset::FLAG_LINKED | Asset::FLAG_LOADED ); }
/// Find an object based on its path name. /// /// @param[in] path FilePath of the object to locate. /// /// @return Pointer to the object if found, null pointer if not found. Asset* Asset::FindObject( AssetPath path ) { // Make sure the path isn't empty. if( path.IsEmpty() ) { return NULL; } // Assemble a list of object names and instance indices, from the top level on down. size_t pathDepth = 0; size_t packageDepth = 0; for( AssetPath testPath = path; !testPath.IsEmpty(); testPath = testPath.GetParent() ) { ++pathDepth; if( testPath.IsPackage() ) { ++packageDepth; } } StackMemoryHeap<>& rStackHeap = ThreadLocalStackAllocator::GetMemoryHeap(); StackMemoryHeap<>::Marker stackMarker( rStackHeap ); Name* pPathNames = static_cast< Name* >( rStackHeap.Allocate( sizeof( Name ) * pathDepth ) ); HELIUM_ASSERT( pPathNames ); uint32_t* pInstanceIndices = static_cast< uint32_t* >( rStackHeap.Allocate( sizeof( uint32_t ) * pathDepth ) ); HELIUM_ASSERT( pInstanceIndices ); size_t pathIndex = pathDepth; for( AssetPath testPath = path; !testPath.IsEmpty(); testPath = testPath.GetParent() ) { HELIUM_ASSERT( pathIndex != 0 ); --pathIndex; pPathNames[ pathIndex ] = testPath.GetName(); pInstanceIndices[ pathIndex ] = testPath.GetInstanceIndex(); } HELIUM_ASSERT( pathIndex == 0 ); // Search from the root. return FindChildOf( NULL, pPathNames, pInstanceIndices, pathDepth, packageDepth ); }
/// Initialize this manager. /// /// @return True if this manager was initialized successfully, false if not. /// /// @see Shutdown() bool WorldManager::Initialize() { HELIUM_ASSERT( !m_spRootSceneDefinitionsPackage ); // Create the world package first. // XXX TMC: Note that we currently assume that the world package has no parents, so we don't need to handle // recursive package creation. If we want to move the world package to a subpackage, this will need to be // updated accordingly. AssetPath rootSceneDefinitionsPackagePath = GetRootSceneDefinitionPackagePath(); HELIUM_ASSERT( !rootSceneDefinitionsPackagePath.IsEmpty() ); HELIUM_ASSERT( rootSceneDefinitionsPackagePath.GetParent().IsEmpty() ); bool bCreateResult = Asset::Create< Package >( m_spRootSceneDefinitionsPackage, rootSceneDefinitionsPackagePath.GetName(), NULL ); HELIUM_ASSERT( bCreateResult ); if( !bCreateResult ) { HELIUM_TRACE( TraceLevels::Error, TXT( "WorldManager::Initialize(): Failed to create world definition package \"%s\".\n" ), *rootSceneDefinitionsPackagePath.ToString() ); return false; } HELIUM_ASSERT( m_spRootSceneDefinitionsPackage ); // Reset frame timings. m_actualFrameTickCount = 0; m_frameTickCount = 0; m_frameDeltaTickCount = 0; m_frameDeltaSeconds = 0.0f; // First frame still needs to be processed. m_bProcessedFirstFrame = false; return true; }
/// Begin asynchronous loading of an object. /// /// @param[in] path Asset path. /// /// @return ID for the load request if started successfully, invalid index if not. /// /// @see TryFinishLoad(), FinishLoad() size_t AssetLoader::BeginLoadObject( AssetPath path, bool forceReload ) { HELIUM_TRACE( TraceLevels::Info, TXT(" AssetLoader::BeginLoadObject - Loading path %s\n"), *path.ToString() ); HELIUM_ASSERT( !path.GetName().IsEmpty() ); // Search for an existing load request with the given path. ConcurrentHashMap< AssetPath, LoadRequest* >::ConstAccessor requestConstAccessor; if( m_loadRequestMap.Find( requestConstAccessor, path ) ) { LoadRequest* pRequest = requestConstAccessor->Second(); HELIUM_ASSERT( pRequest ); AtomicIncrementRelease( pRequest->requestCount ); // We can release now, as the request shouldn't get released now that we've incremented its reference count. requestConstAccessor.Release(); return m_loadRequestPool.GetIndex( pRequest ); } Asset *pAsset = NULL; if ( !forceReload ) { pAsset = Asset::Find<Asset>( path ); if ( pAsset && !pAsset->GetAllFlagsSet( Asset::FLAG_LOADED ) ) { pAsset = NULL; } } PackageLoader *pPackageLoader = 0; if ( pAsset ) { HELIUM_TRACE( TraceLevels::Info, TXT( "AssetLoader::BeginLoadObject(): Object \"%s\" already loaded.\n" ), *path.ToString() ); } else { // Get the package loader to use for the given object. pPackageLoader = GetPackageLoader( path ); if( !pPackageLoader ) { HELIUM_TRACE( TraceLevels::Error, TXT( "AssetLoader::BeginLoadObject(): Failed to locate package loader for \"%s\".\n" ), *path.ToString() ); return Invalid< size_t >(); } } // Add the load request. LoadRequest* pRequest = m_loadRequestPool.Allocate(); pRequest->path = path; pRequest->pPackageLoader = pPackageLoader; SetInvalid( pRequest->packageLoadRequestId ); pRequest->stateFlags = pAsset ? (pAsset->GetFlags() & Asset::FLAG_BROKEN ? LOAD_FLAG_FULLY_LOADED | LOAD_FLAG_ERROR : LOAD_FLAG_FULLY_LOADED ) : 0; pRequest->requestCount = 1; HELIUM_ASSERT( !pRequest->spObject ); pRequest->spObject = pAsset; pRequest->forceReload = forceReload; ConcurrentHashMap< AssetPath, LoadRequest* >::Accessor requestAccessor; if( m_loadRequestMap.Insert( requestAccessor, KeyValue< AssetPath, LoadRequest* >( path, pRequest ) ) ) { // New load request was created, so tick it once to get the load process running. requestAccessor.Release(); TickLoadRequest( pRequest ); } else { // A matching request was added while we were building our request, so reuse it. m_loadRequestPool.Release( pRequest ); pRequest = requestAccessor->Second(); HELIUM_ASSERT( pRequest ); AtomicIncrementRelease( pRequest->requestCount ); // We can release now, as the request shouldn't get released now that we've incremented its reference count. requestAccessor.Release(); } return m_loadRequestPool.GetIndex( pRequest ); }
/// Set this path to the combination of two paths. /// /// @param[in] pRootPath Root portion of the path. /// @param[in] subPath Sub-path component. /// /// @return True if the paths could be joined into a valid path (to which this path was set), false if joining was /// invalid. bool AssetPath::Join( const char* pRootPath, AssetPath subPath ) { if( !pRootPath || pRootPath[ 0 ] == TXT( '\0' ) ) { m_pEntry = subPath.m_pEntry; return true; } // Parse the root path into a series of names. StackMemoryHeap<>& rStackHeap = ThreadLocalStackAllocator::GetMemoryHeap(); StackMemoryHeap<>::Marker stackMarker( rStackHeap ); Name* pRootPathNames; uint32_t* pRootPathIndices; size_t rootPathNameCount; size_t rootPathPackageCount; if( !Parse( pRootPath, rStackHeap, pRootPathNames, pRootPathIndices, rootPathNameCount, rootPathPackageCount ) ) { return false; } if( rootPathNameCount != rootPathPackageCount ) { AssetPath testSubPathComponent = subPath.GetParent(); AssetPath subPathComponent; do { subPathComponent = testSubPathComponent; testSubPathComponent = testSubPathComponent.GetParent(); if( subPathComponent.IsPackage() ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "AssetPath::Join(): Cannot combine \"%s\" and \"%s\" (second path is rooted in a " ) TXT( "package, while the first path ends in an object).\n" ) ), pRootPath, *subPath.ToString() ); return false; } } while( !testSubPathComponent.IsEmpty() ); } // Assemble the list of path names in reverse order for performing the object path lookup/add. size_t nameCount = rootPathNameCount; size_t packageCount = rootPathPackageCount; AssetPath testPath; for( testPath = subPath; !testPath.IsEmpty(); testPath = testPath.GetParent() ) { ++nameCount; if( testPath.IsPackage() ) { ++packageCount; } } Name* pEntryNames = static_cast< Name* >( rStackHeap.Allocate( sizeof( Name ) * nameCount ) ); HELIUM_ASSERT( pEntryNames ); uint32_t* pInstanceIndices = static_cast< uint32_t* >( rStackHeap.Allocate( sizeof( uint32_t ) * nameCount ) ); HELIUM_ASSERT( pInstanceIndices ); Name* pCurrentName = pEntryNames; uint32_t* pCurrentIndex = pInstanceIndices; for( testPath = subPath; !testPath.IsEmpty(); testPath = testPath.GetParent() ) { *pCurrentName = testPath.GetName(); *pCurrentIndex = testPath.GetInstanceIndex(); ++pCurrentName; ++pCurrentIndex; } ArrayCopy( pCurrentName, pRootPathNames, rootPathNameCount ); ArrayCopy( pCurrentIndex, pRootPathIndices, rootPathNameCount ); // Set the path. Set( pEntryNames, pInstanceIndices, nameCount, packageCount ); return true; }