Пример #1
0
/// Perform a non-blocking attempt to sync with an asynchronous shader variant load request.
///
/// @param[in]  loadId      Load request ID.
/// @param[out] rspVariant  Smart pointer set to the variant reference if loading has completed.
///
/// @return  True if loading has completed, false if not.  Note that if this returns true, the load request ID will
///          no longer be valid for its current load request and should not be reused.
///
/// @see BeginLoadVariant()
bool Shader::TryFinishLoadVariant( size_t loadId, ShaderVariantPtr& rspVariant )
{
    HELIUM_ASSERT( IsValid( loadId ) );

    // Use the try-finish-load override if one is registered.
    if( sm_pTryFinishLoadVariantOverride )
    {
        bool bFinished = sm_pTryFinishLoadVariantOverride( sm_pVariantLoadOverrideData, loadId, rspVariant );

        return bFinished;
    }

    // Attempt to sync the object load request.
    GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance();
    HELIUM_ASSERT( pObjectLoader );

    GameObjectPtr spObject;
    bool bFinished = pObjectLoader->TryFinishLoad( loadId, spObject );
    if( bFinished )
    {
        rspVariant = Reflect::AssertCast< ShaderVariant >( spObject.Get() );
    }

    return bFinished;
}
Пример #2
0
void MapPart::addGameObjectsFromFile(std::string fileName){

	GameObjectLoader loader;
	auto gos = loader.LoadGameObjects(fileName);
	for each(auto gameObject in gos){
		addGameObject(gameObject);
	}
Пример #3
0
/// Begin asynchronous loading of a shader variant.
///
/// @param[in] shaderType       Shader type.
/// @param[in] userOptionIndex  Index associated with the user option combination for the shader variant.
///
/// @return  ID associated with the load procedure, or an invalid index if the load could not be started.
///
/// @see TryFinishLoadVariant()
size_t Shader::BeginLoadVariant( RShader::EType shaderType, uint32_t userOptionIndex )
{
    HELIUM_ASSERT( static_cast< size_t >( shaderType ) < static_cast< size_t >( RShader::TYPE_MAX ) );

    // Make sure the user option index is valid.
    if( userOptionIndex >= m_variantCounts[ shaderType ] )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            ( TXT( "Shader::BeginLoadVariant(): Invalid user option index %" ) TPRIuSZ TXT( " specified for " )
            TXT( "variant of shader \"%s\" (only %" ) TPRIuSZ TXT ( " variants are available for shader type %" )
            TPRId32 TXT( ").\n" ) ),
            userOptionIndex,
            *GetPath().ToString(),
            m_variantCounts[ shaderType ],
            static_cast< int32_t >( shaderType ) );

        return Invalid< size_t >();
    }

    // Use the begin-load override if one is registered.
    if( sm_pBeginLoadVariantOverride )
    {
        size_t loadId = sm_pBeginLoadVariantOverride(
            sm_pVariantLoadOverrideData,
            this,
            shaderType,
            userOptionIndex );

        return loadId;
    }

    // Build the object path name.
    tchar_t shaderTypeCharacter;
    if( shaderType == RShader::TYPE_VERTEX )
    {
        shaderTypeCharacter = TXT( 'v' );
    }
    else
    {
        HELIUM_ASSERT( shaderType == RShader::TYPE_PIXEL );
        shaderTypeCharacter = TXT( 'p' );
    }

    String variantNameString;
    variantNameString.Format( TXT( "%c%" ) TPRIu32, shaderTypeCharacter, userOptionIndex );

    GameObjectPath variantPath;
    HELIUM_VERIFY( variantPath.Set( Name( variantNameString ), false, GetPath() ) );

    // Begin the load process.
    GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance();
    HELIUM_ASSERT( pObjectLoader );

    size_t loadId = pObjectLoader->BeginLoadObject( variantPath );

    return loadId;
}
Пример #4
0
/// Perform a non-blocking attempt to sync with an asynchronous shader variant load request.
///
/// @param[in]  loadId      Load request ID.
/// @param[out] rspVariant  Smart pointer set to the variant reference if loading has completed.
///
/// @return  True if loading has completed, false if not.  Note that if this returns true, the load request ID will
///          no longer be valid for its current load request and should not be reused.
///
/// @see BeginLoadVariant()
bool ShaderVariantResourceHandler::TryFinishLoadVariant( size_t loadId, ShaderVariantPtr& rspVariant )
{
    HELIUM_ASSERT( IsValid( loadId ) );

    // Get the load request and acquire exclusive access to the request entry in the lookup hash set.
    LoadRequest* pLoadRequest = m_loadRequestPool.GetObject( loadId );
    HELIUM_ASSERT( pLoadRequest );

    LoadRequestSetType::Accessor loadRequestAccessor;
    HELIUM_VERIFY( m_loadRequestSet.Find( loadRequestAccessor, pLoadRequest ) );

    // Check if the load request has completed.
    ShaderVariant* pVariant = pLoadRequest->spVariant;
    if( pVariant && !pVariant->GetAnyFlagSet( GameObject::FLAG_PRECACHED ) )
    {
        if( !pVariant->TryFinishPrecacheResourceData() )
        {
            return false;
        }

        pVariant->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED | GameObject::FLAG_PRECACHED );
        pVariant->ConditionalFinalizeLoad();

        // Cache the shader data, but don't evict the raw resource data for the current platform.
        GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance();
        HELIUM_ASSERT( pObjectLoader );
        pObjectLoader->CacheObject( pVariant, false );
    }

    rspVariant = pVariant;

    // Decrement the request count and release the entry if the count has reached zero.
    int32_t newRequestCount = AtomicDecrementRelease( pLoadRequest->requestCount );
    if( newRequestCount == 0 )
    {
        m_loadRequestSet.Remove( loadRequestAccessor );

        pLoadRequest->spVariant.Release();
        m_loadRequestPool.Release( pLoadRequest );
    }

    return true;
}
Пример #5
0
/// Initialize application configuration settings.
///
/// @return  True if initialization was successful, false if not.
bool ConfigInitialization::Initialize()
{
    Config& rConfig = Config::GetStaticInstance();

    GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance();
    HELIUM_ASSERT( pObjectLoader );

    HELIUM_TRACE( TRACE_INFO, TXT( "Loading configuration settings.\n" ) );

    rConfig.BeginLoad();
    while( !rConfig.TryFinishLoad() )
    {
        pObjectLoader->Tick();
    }

    HELIUM_TRACE( TRACE_DEBUG, TXT( "Configuration settings loaded.\n" ) );

    return true;
}
Пример #6
0
/// Deserialize the link tables for an object load.
///
/// @param[in] pRequest  Load request data.
bool CachePackageLoader::DeserializeLinkTables( LoadRequest* pRequest )
{
    HELIUM_ASSERT( pRequest );

    uint8_t* pBufferCurrent = pRequest->pAsyncLoadBuffer;
    uint8_t* pPropertyStreamEnd = pRequest->pPropertyStreamEnd;
    HELIUM_ASSERT( pBufferCurrent );
    HELIUM_ASSERT( pPropertyStreamEnd );
    HELIUM_ASSERT( pBufferCurrent <= pPropertyStreamEnd );

    uint32_t propertyStreamSize = 0;
    if( pBufferCurrent + sizeof( propertyStreamSize ) > pPropertyStreamEnd )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ),
            *pRequest->pEntry->path.ToString() );

        return false;
    }

    MemoryCopy( &propertyStreamSize, pBufferCurrent, sizeof( propertyStreamSize ) );
    pBufferCurrent += sizeof( propertyStreamSize );

    if( propertyStreamSize > static_cast< size_t >( pPropertyStreamEnd - pBufferCurrent ) )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            ( TXT( "CachePackageLoader: Property stream size (%" ) TPRIu32 TXT( " bytes) for \"%s\" exceeds the " )
            TXT( "amount of data cached.  Value will be clamped.\n" ) ),
            propertyStreamSize,
            *pRequest->pEntry->path.ToString() );

        propertyStreamSize = static_cast< uint32_t >( pPropertyStreamEnd - pBufferCurrent );
    }

    pPropertyStreamEnd = pBufferCurrent + propertyStreamSize;
    pRequest->pPropertyStreamEnd = pPropertyStreamEnd;

    // Adjust the end of the persistent resource data stream to account for the resource sub-data count padded on
    // the end (note that non-resources will not have this padding).
    if( pRequest->pPersistentResourceStreamEnd - pPropertyStreamEnd >= sizeof( uint32_t ) )
    {
        pRequest->pPersistentResourceStreamEnd -= sizeof( uint32_t );
    }
    else
    {
        pRequest->pPersistentResourceStreamEnd = pPropertyStreamEnd;
    }

    StackMemoryHeap<>& rStackHeap = ThreadLocalStackAllocator::GetMemoryHeap();

    // Load the type link table.
    uint32_t typeLinkTableSize = 0;
    if( pBufferCurrent + sizeof( typeLinkTableSize ) > pPropertyStreamEnd )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ),
            *pRequest->pEntry->path.ToString() );

        return false;
    }

    MemoryCopy( &typeLinkTableSize, pBufferCurrent, sizeof( typeLinkTableSize ) );
    pBufferCurrent += sizeof( typeLinkTableSize );

    pRequest->typeLinkTable.Resize( 0 );
    pRequest->typeLinkTable.Reserve( typeLinkTableSize );

    uint_fast32_t typeLinkTableSizeFast = typeLinkTableSize;
    for( uint_fast32_t linkTableIndex = 0; linkTableIndex < typeLinkTableSizeFast; ++linkTableIndex )
    {
        uint32_t typeNameSize;
        if( pBufferCurrent + sizeof( typeNameSize ) > pPropertyStreamEnd )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ),
                *pRequest->pEntry->path.ToString() );

            return false;
        }

        MemoryCopy( &typeNameSize, pBufferCurrent, sizeof( typeNameSize ) );
        pBufferCurrent += sizeof( typeNameSize );

        if( pBufferCurrent + sizeof( tchar_t ) * typeNameSize > pPropertyStreamEnd )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ),
                *pRequest->pEntry->path.ToString() );

            return false;
        }

        StackMemoryHeap<>::Marker stackMarker( rStackHeap );
        tchar_t* pTypeNameString = static_cast< tchar_t* >( rStackHeap.Allocate(
            sizeof( tchar_t ) * ( typeNameSize + 1 ) ) );
        HELIUM_ASSERT( pTypeNameString );

        MemoryCopy( pTypeNameString, pBufferCurrent, sizeof( tchar_t ) * typeNameSize );
        pBufferCurrent += sizeof( tchar_t ) * typeNameSize;

        pTypeNameString[ typeNameSize ] = TXT( '\0' );

        Name typeName( pTypeNameString );

        GameObjectType* pType = GameObjectType::Find( typeName );
        if( !pType )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: Failed to locate type \"%s\" when attempting to deserialize \"%s\".\n" ),
                pTypeNameString,
                *pRequest->pEntry->path.ToString() );
        }

        pRequest->typeLinkTable.Push( pType );
    }

    // Load the object link table.
    uint32_t objectLinkTableSize = 0;
    if( pBufferCurrent + sizeof( objectLinkTableSize ) > pPropertyStreamEnd )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ),
            *pRequest->pEntry->path.ToString() );

        return false;
    }

    MemoryCopy( &objectLinkTableSize, pBufferCurrent, sizeof( objectLinkTableSize ) );
    pBufferCurrent += sizeof( objectLinkTableSize );

    pRequest->objectLinkTable.Resize( 0 );
    pRequest->objectLinkTable.Reserve( objectLinkTableSize );

    StackMemoryHeap<>::Marker stackMarker( rStackHeap );

    // Track the link table object paths so that we can use them for issuing additional load requests for the object
    // template and owner dependencies (this way, we can sync on those load requests during the preload process
    // while still providing load requests for the caller to resolve if necessary).
    GameObjectPath* pObjectLinkTablePaths = static_cast< GameObjectPath* >( rStackHeap.Allocate(
        sizeof( GameObjectPath ) * objectLinkTableSize ) );
    HELIUM_ASSERT( pObjectLinkTablePaths );
    ArrayUninitializedFill( pObjectLinkTablePaths, GameObjectPath( NULL_NAME ), objectLinkTableSize );

    GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance();
    HELIUM_ASSERT( pObjectLoader );

    uint_fast32_t objectLinkTableSizeFast = objectLinkTableSize;
    for( uint_fast32_t linkTableIndex = 0; linkTableIndex < objectLinkTableSizeFast; ++linkTableIndex )
    {
        uint32_t pathStringSize;
        if( pBufferCurrent + sizeof( pathStringSize ) > pPropertyStreamEnd )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ),
                *pRequest->pEntry->path.ToString() );

            return false;
        }

        MemoryCopy( &pathStringSize, pBufferCurrent, sizeof( pathStringSize ) );
        pBufferCurrent += sizeof( pathStringSize );

        if( pBufferCurrent + sizeof( tchar_t ) * pathStringSize > pPropertyStreamEnd )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ),
                *pRequest->pEntry->path.ToString() );

            return false;
        }

        StackMemoryHeap<>::Marker stackMarker( rStackHeap );
        tchar_t* pPathString = static_cast< tchar_t* >( rStackHeap.Allocate(
            sizeof( tchar_t ) * ( pathStringSize + 1 ) ) );
        HELIUM_ASSERT( pPathString );

        MemoryCopy( pPathString, pBufferCurrent, sizeof( tchar_t ) * pathStringSize );
        pBufferCurrent += sizeof( tchar_t ) * pathStringSize;

        pPathString[ pathStringSize ] = TXT( '\0' );

        size_t linkLoadId;
        SetInvalid( linkLoadId );

        GameObjectPath path;
        if( !path.Set( pPathString ) )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                ( TXT( "CachePackageLoader: Invalid object path \"%s\" found in linker table when deserializing " )
                TXT( "\"%s\".  Setting to null.\n" ) ),
                pPathString,
                *pRequest->pEntry->path.ToString() );

            pRequest->flags |= LOAD_FLAG_ERROR;
        }
        else
        {
            pObjectLinkTablePaths[ linkTableIndex ] = path;

            // Begin loading the link table entry.
            linkLoadId = pObjectLoader->BeginLoadObject( path );
            if( IsInvalid( linkLoadId ) )
            {
                HELIUM_TRACE(
                    TraceLevels::Error,
                    ( TXT( "CachePackageLoader: Failed to begin loading \"%s\" as a link dependency for \"%s\".  " )
                    TXT( "Setting to null.\n" ) ),
                    pPathString,
                    *pRequest->pEntry->path.ToString() );

                pRequest->flags |= LOAD_FLAG_ERROR;
            }
        }

        pRequest->objectLinkTable.Push( linkLoadId );
    }

    // Read the type link information.
    uint32_t typeLinkIndex;
    if( pBufferCurrent + sizeof( typeLinkIndex ) > pPropertyStreamEnd )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ),
            *pRequest->pEntry->path.ToString() );

        return false;
    }

    MemoryCopy( &typeLinkIndex, pBufferCurrent, sizeof( typeLinkIndex ) );
    pBufferCurrent += sizeof( typeLinkIndex );

    if( typeLinkIndex >= typeLinkTableSizeFast )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "CachePackageLoader: Invalid link table index for the type of \"%s\".\n" ),
            *pRequest->pEntry->path.ToString() );

        return false;
    }

    GameObjectType* pType = pRequest->typeLinkTable[ typeLinkIndex ];
    if( !pType )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "CachePackageLoader: Type not found for object \"%s\".\n" ),
            *pRequest->pEntry->path.ToString() );

        return false;
    }

    pRequest->spType = pType;

    // Read the template link information.
    if( pBufferCurrent + sizeof( pRequest->templateLinkIndex ) > pPropertyStreamEnd )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ),
            *pRequest->pEntry->path.ToString() );

        return false;
    }

    MemoryCopy( &pRequest->templateLinkIndex, pBufferCurrent, sizeof( pRequest->templateLinkIndex ) );
    pBufferCurrent += sizeof( pRequest->templateLinkIndex );

    if( IsValid( pRequest->templateLinkIndex ) )
    {
        if( pRequest->templateLinkIndex >= objectLinkTableSizeFast )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: Invalid link table index for the template of \"%s\".\n" ),
                *pRequest->pEntry->path.ToString() );

            SetInvalid( pRequest->templateLinkIndex );

            return false;
        }

        size_t templateLoadId = pObjectLoader->BeginLoadObject(
            pObjectLinkTablePaths[ pRequest->templateLinkIndex ] );
        HELIUM_ASSERT( templateLoadId == pRequest->objectLinkTable[ pRequest->templateLinkIndex ] );
        HELIUM_UNREF( templateLoadId );
    }

    // Read the owner link information.
    if( pBufferCurrent + sizeof( pRequest->ownerLinkIndex ) > pPropertyStreamEnd )
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "CachePackageLoader: End of buffer reached when attempting to deserialize \"%s\".\n" ),
            *pRequest->pEntry->path.ToString() );

        return false;
    }

    MemoryCopy( &pRequest->ownerLinkIndex, pBufferCurrent, sizeof( pRequest->ownerLinkIndex ) );
    pBufferCurrent += sizeof( pRequest->ownerLinkIndex );

    if( IsValid( pRequest->ownerLinkIndex ) )
    {
        if( pRequest->ownerLinkIndex >= objectLinkTableSizeFast )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: Invalid link table index for the owner of \"%s\".\n" ),
                *pRequest->pEntry->path.ToString() );

            SetInvalid( pRequest->ownerLinkIndex );

            return false;
        }

        size_t ownerLoadId = pObjectLoader->BeginLoadObject( pObjectLinkTablePaths[ pRequest->ownerLinkIndex ] );
        HELIUM_ASSERT( ownerLoadId == pRequest->objectLinkTable[ pRequest->ownerLinkIndex ] );
        HELIUM_UNREF( ownerLoadId );
    }

    pRequest->pSerializedData = pBufferCurrent;

    return true;
}
Пример #7
0
/// Tick the object deserialization process for the given object load request.
///
/// @param[in] pRequest  Load request.
///
/// @return  True if the deserialization process has completed, false if it still needs time to process.
bool CachePackageLoader::TickDeserialize( LoadRequest* pRequest )
{
    HELIUM_ASSERT( pRequest );
    HELIUM_ASSERT( !( pRequest->flags & LOAD_FLAG_PRELOADED ) );

    GameObject* pObject = pRequest->spObject;

    const Cache::Entry* pCacheEntry = pRequest->pEntry;
    HELIUM_ASSERT( pCacheEntry );

    // Wait for the template and owner objects to load.
    GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance();
    HELIUM_ASSERT( pObjectLoader );

    if( IsValid( pRequest->templateLinkIndex ) )
    {
        HELIUM_ASSERT( pRequest->templateLinkIndex < pRequest->objectLinkTable.GetSize() );
        size_t templateLoadId = pRequest->objectLinkTable[ pRequest->templateLinkIndex ];
        if( IsValid( templateLoadId ) && !pObjectLoader->TryFinishLoad( templateLoadId, pRequest->spTemplate ) )
        {
            return false;
        }

        SetInvalid( pRequest->templateLinkIndex );

        if( !pRequest->spTemplate )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: Failed to load template object for \"%s\".\n" ),
                *pCacheEntry->path.ToString() );

            if( pObject )
            {
                pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED );
                pObject->ConditionalFinalizeLoad();
            }

            DefaultAllocator().Free( pRequest->pAsyncLoadBuffer );
            pRequest->pAsyncLoadBuffer = NULL;

            pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR;

            return true;
        }
    }

    GameObject* pTemplate = pRequest->spTemplate;

    if( IsValid( pRequest->ownerLinkIndex ) )
    {
        HELIUM_ASSERT( pRequest->ownerLinkIndex < pRequest->objectLinkTable.GetSize() );
        size_t ownerLoadId = pRequest->objectLinkTable[ pRequest->ownerLinkIndex ];
        if( IsValid( ownerLoadId ) && !pObjectLoader->TryFinishLoad( ownerLoadId, pRequest->spOwner ) )
        {
            return false;
        }

        SetInvalid( pRequest->ownerLinkIndex );

        if( !pRequest->spOwner )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: Failed to load owner object for \"%s\".\n" ),
                *pCacheEntry->path.ToString() );

            if( pObject )
            {
                pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED );
                pObject->ConditionalFinalizeLoad();
            }

            DefaultAllocator().Free( pRequest->pAsyncLoadBuffer );
            pRequest->pAsyncLoadBuffer = NULL;

            pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR;

            return true;
        }
    }

    GameObject* pOwner = pRequest->spOwner;

    HELIUM_ASSERT( !pOwner || pOwner->IsFullyLoaded() );
    HELIUM_ASSERT( !pTemplate || pTemplate->IsFullyLoaded() );

    GameObjectType* pType = pRequest->spType;
    HELIUM_ASSERT( pType );

    // If we already had an existing object, make sure the type and template match.
    if( pObject )
    {
        const GameObjectType* pExistingType = pObject->GetGameObjectType();
        HELIUM_ASSERT( pExistingType );
        if( pExistingType != pType )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                ( TXT( "CachePackageLoader: Cannot load \"%s\" using the existing object as the types do not " )
                TXT( "match (existing type: \"%s\"; serialized type: \"%s\".\n" ) ),
                *pCacheEntry->path.ToString(),
                *pExistingType->GetName(),
                *pType->GetName() );

            pObject->SetFlags( GameObject::FLAG_PRELOADED | GameObject::FLAG_LINKED );
            pObject->ConditionalFinalizeLoad();

            DefaultAllocator().Free( pRequest->pAsyncLoadBuffer );
            pRequest->pAsyncLoadBuffer = NULL;

            pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR;

            return true;
        }
    }
    else
    {
        // Create the object.
        if( !GameObject::CreateObject( pRequest->spObject, pType, pCacheEntry->path.GetName(), pOwner, pTemplate ) )
        {
            HELIUM_TRACE(
                TraceLevels::Error,
                TXT( "CachePackageLoader: Failed to create \"%s\" during loading.\n" ),
                *pCacheEntry->path.ToString() );

            DefaultAllocator().Free( pRequest->pAsyncLoadBuffer );
            pRequest->pAsyncLoadBuffer = NULL;

            pRequest->flags |= LOAD_FLAG_PRELOADED | LOAD_FLAG_ERROR;

            return true;
        }

        pObject = pRequest->spObject;
        HELIUM_ASSERT( pObject );
    }
        
    Reflect::ObjectPtr cached_object = Cache::ReadCacheObjectFromBuffer(pRequest->pSerializedData, 0, pRequest->pPropertyStreamEnd - pRequest->pSerializedData);

    if (!cached_object.ReferencesObject())
    {
        HELIUM_TRACE(
            TraceLevels::Error,
            TXT( "CachePackageLoader: Failed to deserialize object \"%s\".\n" ),
            *pCacheEntry->path.ToString() );

        // Clear out object references (object can now be considered fully loaded as well).
        // pmd - Not sure that we need to do this.. but if we do, just use this visitor
        //ClearLinkIndicesFromObject clifo_visitor;
        //pObject->Accept(clifo_visitor);
        pObject->SetFlags( GameObject::FLAG_LINKED );
        pObject->ConditionalFinalizeLoad();

        pRequest->flags |= LOAD_FLAG_ERROR;
    }
    else
    {
        cached_object->CopyTo(pObject);
                
        if( !pObject->IsDefaultTemplate() )
        {
            // Load persistent resource data.
            Resource* pResource = Reflect::SafeCast< Resource >( pObject );
            if( pResource )
            {
                Reflect::ObjectPtr cached_prd = Cache::ReadCacheObjectFromBuffer(
                    pRequest->pPropertyStreamEnd, 
                    0, 
                    (pRequest->pPersistentResourceStreamEnd - pRequest->pPropertyStreamEnd));

                if (!cached_prd.ReferencesObject())
                {
                    HELIUM_TRACE(
                        TraceLevels::Error,
                        ( TXT( "CachePackageLoader: Failed to deserialize persistent resource " )
                        TXT( "data for \"%s\".\n" ) ),
                        *pCacheEntry->path.ToString() );
                }
                else
                {
                    pResource->LoadPersistentResourceObject(cached_prd);
                }
            }
        }
    }

    DefaultAllocator().Free( pRequest->pAsyncLoadBuffer );
    pRequest->pAsyncLoadBuffer = NULL;

    pObject->SetFlags( GameObject::FLAG_PRELOADED );

    pRequest->flags |= LOAD_FLAG_PRELOADED;

    // GameObject is now preloaded.
    return true;
}
Пример #8
0
/// @copydoc PackageLoader::TryFinishLoadObject()
bool CachePackageLoader::TryFinishLoadObject(
    size_t requestId,
    GameObjectPtr& rspObject,
    DynamicArray< GameObjectLoader::LinkEntry >& rLinkTable )
{
    HELIUM_ASSERT( requestId < m_loadRequests.GetSize() );
    HELIUM_ASSERT( m_loadRequests.IsElementValid( requestId ) );

    LoadRequest* pRequest = m_loadRequests[ requestId ];
    HELIUM_ASSERT( pRequest );
    if( !( pRequest->flags & LOAD_FLAG_PRELOADED ) )
    {
        return false;
    }

    // Sync on template and owner dependencies.
    GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance();
    HELIUM_ASSERT( pObjectLoader );

    DynamicArray< size_t >& rInternalLinkTable = pRequest->objectLinkTable;

    if( IsValid( pRequest->templateLinkIndex ) )
    {
        size_t linkLoadId = rInternalLinkTable[ pRequest->templateLinkIndex ];
        if( IsValid( linkLoadId ) && !pObjectLoader->TryFinishLoad( linkLoadId, pRequest->spTemplate ) )
        {
            return false;
        }

        SetInvalid( pRequest->templateLinkIndex );
    }

    if( IsValid( pRequest->ownerLinkIndex ) )
    {
        size_t linkLoadId = rInternalLinkTable[ pRequest->ownerLinkIndex ];
        if( IsValid( linkLoadId ) && !pObjectLoader->TryFinishLoad( linkLoadId, pRequest->spOwner ) )
        {
            return false;
        }

        SetInvalid( pRequest->ownerLinkIndex );
    }

    rspObject = pRequest->spObject;
    GameObject* pObject = rspObject;
    if( pObject && ( pRequest->flags & LOAD_FLAG_ERROR ) )
    {
        pObject->SetFlags( GameObject::FLAG_BROKEN );
    }

    pRequest->spObject.Release();

    size_t linkTableSize = rInternalLinkTable.GetSize();
    rLinkTable.Resize( 0 );
    rLinkTable.Reserve( linkTableSize );
    for( size_t linkIndex = 0; linkIndex < linkTableSize; ++linkIndex )
    {
        GameObjectLoader::LinkEntry* pEntry = rLinkTable.New();
        HELIUM_ASSERT( pEntry );
        pEntry->loadId = rInternalLinkTable[ linkIndex ];
        pEntry->spObject.Release();
    }

    rInternalLinkTable.Resize( 0 );

    HELIUM_ASSERT( IsInvalid( pRequest->asyncLoadId ) );
    HELIUM_ASSERT( !pRequest->pAsyncLoadBuffer );

    pRequest->spType.Release();
    pRequest->spTemplate.Release();
    pRequest->spOwner.Release();
    pRequest->typeLinkTable.Resize( 0 );

    HELIUM_ASSERT( pObject || pRequest->pEntry );
    HELIUM_TRACE(
        TraceLevels::Debug,
        ( TXT( "CachePackageLoader::TryFinishLoadObject(): Load request for \"%s\" (ID: %" ) TPRIuSZ TXT( ") " )
        TXT( "synced.\n" ) ),
        *( pObject ? pObject->GetPath() : pRequest->pEntry->path ).ToString(),
        requestId );

    m_loadRequests.Remove( requestId );
    m_loadRequestPool.Release( pRequest );

    return true;
}
Пример #9
0
/// Initialize all resources provided by this manager.
///
/// @see Shutdown(), PostConfigUpdate()
void RenderResourceManager::Initialize()
{
    // Release any existing resources.
    Shutdown();

    // Get the renderer and graphics configuration.
    Renderer* pRenderer = Renderer::GetStaticInstance();
    if( !pRenderer )
    {
        return;
    }

    Config& rConfig = Config::GetStaticInstance();
    StrongPtr< GraphicsConfig > spGraphicsConfig(
        rConfig.GetConfigObject< GraphicsConfig >( Name( TXT( "GraphicsConfig" ) ) ) );
    if( !spGraphicsConfig )
    {
        HELIUM_TRACE(
            TRACE_ERROR,
            TXT( "RenderResourceManager::Initialize(): Initialization failed; missing GraphicsConfig.\n" ) );

        return;
    }

    // Create the standard rasterizer states.
    RRasterizerState::Description rasterizerStateDesc;

    rasterizerStateDesc.fillMode = RENDERER_FILL_MODE_SOLID;
    rasterizerStateDesc.cullMode = RENDERER_CULL_MODE_BACK;
    rasterizerStateDesc.winding = RENDERER_WINDING_CLOCKWISE;
    rasterizerStateDesc.depthBias = 0;
    rasterizerStateDesc.slopeScaledDepthBias = 0.0f;
    m_rasterizerStates[ RASTERIZER_STATE_DEFAULT ] = pRenderer->CreateRasterizerState( rasterizerStateDesc );
    HELIUM_ASSERT( m_rasterizerStates[ RASTERIZER_STATE_DEFAULT ] );

    rasterizerStateDesc.cullMode = RENDERER_CULL_MODE_NONE;
    m_rasterizerStates[ RASTERIZER_STATE_DOUBLE_SIDED ] = pRenderer->CreateRasterizerState( rasterizerStateDesc );
    HELIUM_ASSERT( m_rasterizerStates[ RASTERIZER_STATE_DOUBLE_SIDED ] );

    rasterizerStateDesc.depthBias = 1;
    rasterizerStateDesc.slopeScaledDepthBias = 2.0f;
    m_rasterizerStates[ RASTERIZER_STATE_SHADOW_DEPTH ] = pRenderer->CreateRasterizerState( rasterizerStateDesc );
    HELIUM_ASSERT( m_rasterizerStates[ RASTERIZER_STATE_SHADOW_DEPTH ] );

    rasterizerStateDesc.depthBias = 0;
    rasterizerStateDesc.slopeScaledDepthBias = 0.0f;
    rasterizerStateDesc.fillMode = RENDERER_FILL_MODE_WIREFRAME;
    m_rasterizerStates[ RASTERIZER_STATE_WIREFRAME_DOUBLE_SIDED ] = pRenderer->CreateRasterizerState(
        rasterizerStateDesc );
    HELIUM_ASSERT( m_rasterizerStates[ RASTERIZER_STATE_WIREFRAME_DOUBLE_SIDED ] );

    rasterizerStateDesc.cullMode = RENDERER_CULL_MODE_BACK;
    m_rasterizerStates[ RASTERIZER_STATE_WIREFRAME ] = pRenderer->CreateRasterizerState( rasterizerStateDesc );
    HELIUM_ASSERT( m_rasterizerStates[ RASTERIZER_STATE_WIREFRAME ] );

    // Create the standard blend states.
    RBlendState::Description blendStateDesc;

    blendStateDesc.bBlendEnable = false;
    m_blendStates[ BLEND_STATE_OPAQUE ] = pRenderer->CreateBlendState( blendStateDesc );
    HELIUM_ASSERT( m_blendStates[ BLEND_STATE_OPAQUE ] );

    blendStateDesc.colorWriteMask = 0;
    m_blendStates[ BLEND_STATE_NO_COLOR ] = pRenderer->CreateBlendState( blendStateDesc );
    HELIUM_ASSERT( m_blendStates[ BLEND_STATE_NO_COLOR ] );

    blendStateDesc.colorWriteMask = RENDERER_COLOR_WRITE_MASK_FLAG_ALL;
    blendStateDesc.bBlendEnable = true;

    blendStateDesc.sourceFactor = RENDERER_BLEND_FACTOR_SRC_ALPHA;
    blendStateDesc.destinationFactor = RENDERER_BLEND_FACTOR_INV_SRC_ALPHA;
    blendStateDesc.function = RENDERER_BLEND_FUNCTION_ADD;
    m_blendStates[ BLEND_STATE_TRANSPARENT ] = pRenderer->CreateBlendState( blendStateDesc );
    HELIUM_ASSERT( m_blendStates[ BLEND_STATE_TRANSPARENT ] );

    blendStateDesc.sourceFactor = RENDERER_BLEND_FACTOR_ONE;
    blendStateDesc.destinationFactor = RENDERER_BLEND_FACTOR_ONE;
    m_blendStates[ BLEND_STATE_ADDITIVE ] = pRenderer->CreateBlendState( blendStateDesc );
    HELIUM_ASSERT( m_blendStates[ BLEND_STATE_ADDITIVE ] );

    blendStateDesc.function = RENDERER_BLEND_FUNCTION_REVERSE_SUBTRACT;
    m_blendStates[ BLEND_STATE_SUBTRACTIVE ] = pRenderer->CreateBlendState( blendStateDesc );
    HELIUM_ASSERT( m_blendStates[ BLEND_STATE_SUBTRACTIVE ] );

    blendStateDesc.sourceFactor = RENDERER_BLEND_FACTOR_DEST_COLOR;
    blendStateDesc.destinationFactor = RENDERER_BLEND_FACTOR_ZERO;
    blendStateDesc.function = RENDERER_BLEND_FUNCTION_ADD;
    m_blendStates[ BLEND_STATE_MODULATE ] = pRenderer->CreateBlendState( blendStateDesc );
    HELIUM_ASSERT( m_blendStates[ BLEND_STATE_MODULATE ] );

    // Create the standard depth/stencil states.
    RDepthStencilState::Description depthStateDesc;

    depthStateDesc.stencilWriteMask = 0;
    depthStateDesc.bStencilTestEnable = false;

    depthStateDesc.depthFunction = RENDERER_COMPARE_FUNCTION_LESS_EQUAL;
    depthStateDesc.bDepthTestEnable = true;
    depthStateDesc.bDepthWriteEnable = true;
    m_depthStencilStates[ DEPTH_STENCIL_STATE_DEFAULT ] = pRenderer->CreateDepthStencilState( depthStateDesc );
    HELIUM_ASSERT( m_depthStencilStates[ DEPTH_STENCIL_STATE_DEFAULT ] );

    depthStateDesc.bDepthWriteEnable = false;
    m_depthStencilStates[ DEPTH_STENCIL_STATE_TEST_ONLY ] = pRenderer->CreateDepthStencilState( depthStateDesc );
    HELIUM_ASSERT( m_depthStencilStates[ DEPTH_STENCIL_STATE_TEST_ONLY ] );

    depthStateDesc.bDepthTestEnable = false;
    m_depthStencilStates[ DEPTH_STENCIL_STATE_NONE ] = pRenderer->CreateDepthStencilState( depthStateDesc );
    HELIUM_ASSERT( m_depthStencilStates[ DEPTH_STENCIL_STATE_NONE ] );

    // Create the standard sampler states that are not dependent on configuration settings.
    RSamplerState::Description samplerStateDesc;
    samplerStateDesc.filter = RENDERER_TEXTURE_FILTER_MIN_POINT_MAG_POINT_MIP_POINT;
    samplerStateDesc.addressModeW = RENDERER_TEXTURE_ADDRESS_MODE_CLAMP;
    samplerStateDesc.mipLodBias = 0;
    samplerStateDesc.maxAnisotropy = spGraphicsConfig->GetMaxAnisotropy();

    for( size_t addressModeIndex = 0; addressModeIndex < RENDERER_TEXTURE_ADDRESS_MODE_MAX; ++addressModeIndex )
    {
        ERendererTextureAddressMode addressMode = static_cast< ERendererTextureAddressMode >( addressModeIndex );
        samplerStateDesc.addressModeU = addressMode;
        samplerStateDesc.addressModeV = addressMode;
        samplerStateDesc.addressModeW = addressMode;

        m_samplerStates[ TEXTURE_FILTER_POINT ][ addressModeIndex ] = pRenderer->CreateSamplerState(
            samplerStateDesc );
        HELIUM_ASSERT( m_samplerStates[ TEXTURE_FILTER_POINT ][ addressModeIndex ] );
    }

    // Create the standard set of mesh vertex descriptions.
    RVertexDescription::Element vertexElements[ 6 ];

    vertexElements[ 0 ].type = RENDERER_VERTEX_DATA_TYPE_FLOAT32_3;
    vertexElements[ 0 ].semantic = RENDERER_VERTEX_SEMANTIC_POSITION;
    vertexElements[ 0 ].semanticIndex = 0;
    vertexElements[ 0 ].bufferIndex = 0;

    vertexElements[ 1 ].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
    vertexElements[ 1 ].semantic = RENDERER_VERTEX_SEMANTIC_COLOR;
    vertexElements[ 1 ].semanticIndex = 0;
    vertexElements[ 1 ].bufferIndex = 0;

    vertexElements[ 2 ].type = RENDERER_VERTEX_DATA_TYPE_FLOAT16_2;
    vertexElements[ 2 ].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
    vertexElements[ 2 ].semanticIndex = 0;
    vertexElements[ 2 ].bufferIndex = 0;

    vertexElements[ 3 ].type = RENDERER_VERTEX_DATA_TYPE_FLOAT32_2;
    vertexElements[ 3 ].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
    vertexElements[ 3 ].semanticIndex = 1;
    vertexElements[ 3 ].bufferIndex = 0;

    m_spSimpleVertexDescription = pRenderer->CreateVertexDescription( vertexElements, 2 );
    HELIUM_ASSERT( m_spSimpleVertexDescription );

    m_spSimpleTexturedVertexDescription = pRenderer->CreateVertexDescription( vertexElements, 3 );
    HELIUM_ASSERT( m_spSimpleTexturedVertexDescription );

    m_spProjectedVertexDescription = pRenderer->CreateVertexDescription( vertexElements, 4 );
    HELIUM_ASSERT( m_spProjectedVertexDescription );

    vertexElements[ 1 ].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
    vertexElements[ 1 ].semantic = RENDERER_VERTEX_SEMANTIC_NORMAL;
    vertexElements[ 1 ].semanticIndex = 0;
    vertexElements[ 1 ].bufferIndex = 0;

    vertexElements[ 2 ].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
    vertexElements[ 2 ].semantic = RENDERER_VERTEX_SEMANTIC_TANGENT;
    vertexElements[ 2 ].semanticIndex = 0;
    vertexElements[ 2 ].bufferIndex = 0;

    vertexElements[ 3 ].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
    vertexElements[ 3 ].semantic = RENDERER_VERTEX_SEMANTIC_COLOR;
    vertexElements[ 3 ].semanticIndex = 0;
    vertexElements[ 3 ].bufferIndex = 0;

    vertexElements[ 4 ].type = RENDERER_VERTEX_DATA_TYPE_FLOAT16_2;
    vertexElements[ 4 ].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
    vertexElements[ 4 ].semanticIndex = 0;
    vertexElements[ 4 ].bufferIndex = 0;

    vertexElements[ 5 ].type = RENDERER_VERTEX_DATA_TYPE_FLOAT16_2;
    vertexElements[ 5 ].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
    vertexElements[ 5 ].semanticIndex = 1;
    vertexElements[ 5 ].bufferIndex = 0;

    m_staticMeshVertexDescriptions[ 0 ] = pRenderer->CreateVertexDescription( vertexElements, 5 );
    HELIUM_ASSERT( m_staticMeshVertexDescriptions[ 0 ] );

    m_staticMeshVertexDescriptions[ 1 ] = pRenderer->CreateVertexDescription( vertexElements, 6 );
    HELIUM_ASSERT( m_staticMeshVertexDescriptions[ 1 ] );

    vertexElements[ 1 ].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
    vertexElements[ 1 ].semantic = RENDERER_VERTEX_SEMANTIC_BLENDWEIGHT;
    vertexElements[ 1 ].semanticIndex = 0;
    vertexElements[ 1 ].bufferIndex = 0;

    vertexElements[ 2 ].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4;
    vertexElements[ 2 ].semantic = RENDERER_VERTEX_SEMANTIC_BLENDINDICES;
    vertexElements[ 2 ].semanticIndex = 0;
    vertexElements[ 2 ].bufferIndex = 0;

    vertexElements[ 3 ].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
    vertexElements[ 3 ].semantic = RENDERER_VERTEX_SEMANTIC_NORMAL;
    vertexElements[ 3 ].semanticIndex = 0;
    vertexElements[ 3 ].bufferIndex = 0;

    vertexElements[ 4 ].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
    vertexElements[ 4 ].semantic = RENDERER_VERTEX_SEMANTIC_TANGENT;
    vertexElements[ 4 ].semanticIndex = 0;
    vertexElements[ 4 ].bufferIndex = 0;

    vertexElements[ 5 ].type = RENDERER_VERTEX_DATA_TYPE_FLOAT16_2;
    vertexElements[ 5 ].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
    vertexElements[ 5 ].semanticIndex = 0;
    vertexElements[ 5 ].bufferIndex = 0;

    m_spSkinnedMeshVertexDescription = pRenderer->CreateVertexDescription( vertexElements, 6 );
    HELIUM_ASSERT( m_spSkinnedMeshVertexDescription );

    vertexElements[ 0 ].type = RENDERER_VERTEX_DATA_TYPE_FLOAT32_2;
    vertexElements[ 0 ].semantic = RENDERER_VERTEX_SEMANTIC_POSITION;
    vertexElements[ 0 ].semanticIndex = 0;
    vertexElements[ 0 ].bufferIndex = 0;

    vertexElements[ 1 ].type = RENDERER_VERTEX_DATA_TYPE_UINT8_4_NORM;
    vertexElements[ 1 ].semantic = RENDERER_VERTEX_SEMANTIC_COLOR;
    vertexElements[ 1 ].semanticIndex = 0;
    vertexElements[ 1 ].bufferIndex = 0;

    vertexElements[ 2 ].type = RENDERER_VERTEX_DATA_TYPE_FLOAT16_2;
    vertexElements[ 2 ].semantic = RENDERER_VERTEX_SEMANTIC_TEXCOORD;
    vertexElements[ 2 ].semanticIndex = 0;
    vertexElements[ 2 ].bufferIndex = 0;

    m_spScreenVertexDescription = pRenderer->CreateVertexDescription( vertexElements, 3 );
    HELIUM_ASSERT( m_spScreenVertexDescription );

    // Create configuration-dependent render resources.
    PostConfigUpdate();

    // Attempt to load the depth-only pre-pass shader.
#pragma TODO( "XXX TMC: Migrate to a more data-driven solution." )
    GameObjectLoader* pObjectLoader = GameObjectLoader::GetStaticInstance();
    HELIUM_ASSERT( pObjectLoader );

    GameObjectPath prePassShaderPath;
    HELIUM_VERIFY( prePassShaderPath.Set(
        HELIUM_PACKAGE_PATH_CHAR_STRING TXT( "Shaders" ) HELIUM_OBJECT_PATH_CHAR_STRING TXT( "PrePass.hlsl" ) ) );

    GameObjectPtr spPrePassShader;
    HELIUM_VERIFY( pObjectLoader->LoadObject( prePassShaderPath, spPrePassShader ) );

    Shader* pPrePassShader = Reflect::SafeCast< Shader >( spPrePassShader.Get() );
    HELIUM_ASSERT( pPrePassShader );
    if( pPrePassShader )
    {
        size_t loadId = pPrePassShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 );
        HELIUM_ASSERT( IsValid( loadId ) );
        if( IsValid( loadId ) )
        {
            while( !pPrePassShader->TryFinishLoadVariant( loadId, m_spPrePassVertexShader ) )
            {
                pObjectLoader->Tick();
            }
        }
    }

    // Attempt to load the simple world-space, simple screen-space, and screen-space text shaders.
#pragma TODO( "XXX TMC: Migrate to a more data-driven solution." )
    GameObjectPath shaderPath;
    GameObjectPtr spShader;
    Shader* pShader;

    HELIUM_VERIFY( shaderPath.Set(
        HELIUM_PACKAGE_PATH_CHAR_STRING TXT( "Shaders" ) HELIUM_OBJECT_PATH_CHAR_STRING TXT( "Simple.hlsl" ) ) );

    HELIUM_VERIFY( pObjectLoader->LoadObject( shaderPath, spShader ) );

    pShader = Reflect::SafeCast< Shader >( spShader.Get() );
    HELIUM_ASSERT( pShader );
    if( pShader )
    {
        size_t loadId = pShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 );
        HELIUM_ASSERT( IsValid( loadId ) );
        if( IsValid( loadId ) )
        {
            while( !pShader->TryFinishLoadVariant( loadId, m_spSimpleWorldSpaceVertexShader ) )
            {
                pObjectLoader->Tick();
            }
        }

        loadId = pShader->BeginLoadVariant( RShader::TYPE_PIXEL, 0 );
        HELIUM_ASSERT( IsValid( loadId ) );
        if( IsValid( loadId ) )
        {
            while( !pShader->TryFinishLoadVariant( loadId, m_spSimpleWorldSpacePixelShader ) )
            {
                pObjectLoader->Tick();
            }
        }
    }

    HELIUM_VERIFY( shaderPath.Set(
        HELIUM_PACKAGE_PATH_CHAR_STRING TXT( "Shaders" ) HELIUM_OBJECT_PATH_CHAR_STRING TXT( "ScreenSpaceTexture.hlsl" ) ) );

    HELIUM_VERIFY( pObjectLoader->LoadObject( shaderPath, spShader ) );

    pShader = Reflect::SafeCast< Shader >( spShader.Get() );
    HELIUM_ASSERT( pShader );
    if( pShader )
    {
        size_t loadId = pShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 );
        HELIUM_ASSERT( IsValid( loadId ) );
        if( IsValid( loadId ) )
        {
            while( !pShader->TryFinishLoadVariant( loadId, m_spSimpleScreenSpaceVertexShader ) )
            {
                pObjectLoader->Tick();
            }
        }

        loadId = pShader->BeginLoadVariant( RShader::TYPE_PIXEL, 0 );
        HELIUM_ASSERT( IsValid( loadId ) );
        if( IsValid( loadId ) )
        {
            while( !pShader->TryFinishLoadVariant( loadId, m_spSimpleScreenSpacePixelShader ) )
            {
                pObjectLoader->Tick();
            }
        }
    }

    HELIUM_VERIFY( shaderPath.Set(
        HELIUM_PACKAGE_PATH_CHAR_STRING TXT( "Shaders" ) HELIUM_OBJECT_PATH_CHAR_STRING TXT( "ScreenText.hlsl" ) ) );

    HELIUM_VERIFY( pObjectLoader->LoadObject( shaderPath, spShader ) );

    pShader = Reflect::SafeCast< Shader >( spShader.Get() );
    HELIUM_ASSERT( pShader );
    if( pShader )
    {
        size_t loadId = pShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 );
        HELIUM_ASSERT( IsValid( loadId ) );
        if( IsValid( loadId ) )
        {
            while( !pShader->TryFinishLoadVariant( loadId, m_spScreenTextVertexShader ) )
            {
                pObjectLoader->Tick();
            }
        }

        loadId = pShader->BeginLoadVariant( RShader::TYPE_PIXEL, 0 );
        HELIUM_ASSERT( IsValid( loadId ) );
        if( IsValid( loadId ) )
        {
            while( !pShader->TryFinishLoadVariant( loadId, m_spScreenTextPixelShader ) )
            {
                pObjectLoader->Tick();
            }
        }
    }

    // Attempt to load the debug fonts.
#pragma TODO( "XXX TMC: Migrate to a more data-driven solution." )
    GameObjectPath fontPath;
    GameObjectPtr spFont;

    HELIUM_VERIFY( fontPath.Set(
        HELIUM_PACKAGE_PATH_CHAR_STRING TXT( "Fonts" ) HELIUM_OBJECT_PATH_CHAR_STRING TXT( "DebugSmall" ) ) );
    HELIUM_VERIFY( pObjectLoader->LoadObject( fontPath, spFont ) );
    m_debugFonts[ DEBUG_FONT_SIZE_SMALL ] = Reflect::SafeCast< Font >( spFont.Get() );
    spFont.Release();

    HELIUM_VERIFY( fontPath.Set(
        HELIUM_PACKAGE_PATH_CHAR_STRING TXT( "Fonts" ) HELIUM_OBJECT_PATH_CHAR_STRING TXT( "DebugMedium" ) ) );
    HELIUM_VERIFY( pObjectLoader->LoadObject( fontPath, spFont ) );
    m_debugFonts[ DEBUG_FONT_SIZE_MEDIUM ] = Reflect::SafeCast< Font >( spFont.Get() );
    spFont.Release();

    HELIUM_VERIFY( fontPath.Set(
        HELIUM_PACKAGE_PATH_CHAR_STRING TXT( "Fonts" ) HELIUM_OBJECT_PATH_CHAR_STRING TXT( "DebugLarge" ) ) );
    HELIUM_VERIFY( pObjectLoader->LoadObject( fontPath, spFont ) );
    m_debugFonts[ DEBUG_FONT_SIZE_LARGE ] = Reflect::SafeCast< Font >( spFont.Get() );
    spFont.Release();
}