/// 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; }
/// Get the path to the package containing all world instances. /// /// @return World package path. GameObjectPath WorldManager::GetWorldPackagePath() const { static GameObjectPath worldPackagePath; if( worldPackagePath.IsEmpty() ) { HELIUM_VERIFY( worldPackagePath.Set( TXT( "/Worlds" ) ) ); } return worldPackagePath; }
/// 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; }
/// Finalize the TOC loading process. /// /// Note that this does not free any resources on a failed load (the caller is responsible for such clean-up work). /// /// @return True if the TOC load was successful, false if not. bool Cache::FinalizeTocLoad() { HELIUM_ASSERT( m_pTocBuffer ); const uint8_t* pTocCurrent = m_pTocBuffer; const uint8_t* pTocMax = pTocCurrent + m_tocSize; StackMemoryHeap<>& rStackHeap = ThreadLocalStackAllocator::GetMemoryHeap(); // Validate the TOC header. uint32_t magic; if( !CheckedTocRead( MemoryCopy, magic, TXT( "the header magic" ), pTocCurrent, pTocMax ) ) { return false; } LOAD_VALUE_CALLBACK* pLoadFunction = NULL; if( magic == TOC_MAGIC ) { HELIUM_TRACE( TraceLevels::Info, TXT( "Cache::FinalizeTocLoad(): TOC \"%s\" identified (no byte swapping).\n" ), *m_tocFileName ); pLoadFunction = MemoryCopy; } else if( magic == TOC_MAGIC_SWAPPED ) { HELIUM_TRACE( TraceLevels::Info, TXT( "Cache::FinalizeTocLoad(): TOC \"%s\" identified (byte swapping is necessary).\n" ), *m_tocFileName ); HELIUM_TRACE( TraceLevels::Warning, ( TXT( "Cache::TryFinishLoadToc(): Cache for TOC \"%s\" uses byte swapping, which may incur " ) TXT( "performance penalties.\n" ) ), *m_tocFileName ); pLoadFunction = ReverseByteOrder; } else { HELIUM_TRACE( TraceLevels::Error, TXT( "Cache::FinalizeTocLoad(): TOC \"%s\" has invalid file magic.\n" ), *m_tocFileName ); return false; } uint32_t version; if( !CheckedTocRead( pLoadFunction, version, TXT( "the cache version number" ), pTocCurrent, pTocMax ) ) { return false; } if( version > sm_Version ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "Cache::FinalizeTocLoad(): Cache version number (%" ) TPRIu32 TXT( ") exceeds the maximum " ) TXT( "supported version (%" ) TPRIu32 TXT( ").\n" ) ), version, sm_Version ); return false; } // Read the numbers of entries in the cache. uint32_t entryCount; bool bReadResult = CheckedTocRead( pLoadFunction, entryCount, TXT( "the number of entries in the cache" ), pTocCurrent, pTocMax ); if( !bReadResult ) { return false; } // Load the entry information. EntryKey key; uint_fast32_t entryCountFast = entryCount; m_entries.Reserve( entryCountFast ); for( uint_fast32_t entryIndex = 0; entryIndex < entryCountFast; ++entryIndex ) { uint16_t entryPathSize; bReadResult = CheckedTocRead( pLoadFunction, entryPathSize, TXT( "entry GameObjectPath string size" ), pTocCurrent, pTocMax ); if( !bReadResult ) { return false; } uint_fast16_t entryPathSizeFast = entryPathSize; StackMemoryHeap<>::Marker stackMarker( rStackHeap ); tchar_t* pPathString = static_cast< tchar_t* >( rStackHeap.Allocate( sizeof( tchar_t ) * ( entryPathSizeFast + 1 ) ) ); HELIUM_ASSERT( pPathString ); pPathString[ entryPathSizeFast ] = TXT( '\0' ); for( uint_fast16_t characterIndex = 0; characterIndex < entryPathSizeFast; ++characterIndex ) { #if HELIUM_WCHAR_T bReadResult = CheckedTocRead( pLoadFunction, pPathString[ characterIndex ], TXT( "entry GameObjectPath string character" ), pTocCurrent, pTocMax ); if( !bReadResult ) { return false; } #else wchar_t character; bReadResult = CheckedTocRead( pLoadFunction, character, TXT( "entry GameObjectPath string character" ), pTocCurrent, pTocMax ); if( !bReadResult ) { return false; } // TODO: Implement locale-specific conversion from Unicode to MBCS. pPathString[ characterIndex ] = ( character >= 0x80 ? '?' : static_cast< char >( character ) ); #endif } GameObjectPath entryPath; if( !entryPath.Set( pPathString ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "Cache::FinalizeTocLoad(): Failed to set GameObjectPath for entry %" ) TPRIuFAST16 TXT( ".\n" ), entryIndex ); return false; } uint32_t entrySubDataIndex; bReadResult = CheckedTocRead( pLoadFunction, entrySubDataIndex, TXT( "entry sub-data index" ), pTocCurrent, pTocMax ); if( !bReadResult ) { return false; } key.path = entryPath; key.subDataIndex = entrySubDataIndex; EntryMapType::ConstAccessor entryAccessor; if( m_entryMap.Find( entryAccessor, key ) ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "Cache::FinalizeTocLoad(): Duplicate entry found for GameObjectPath \"%s\", sub-data %" ) TPRIu32 TXT( ".\n" ) ), pPathString, entrySubDataIndex ); return false; } uint64_t entryOffset; if( !CheckedTocRead( pLoadFunction, entryOffset, TXT( "entry offset" ), pTocCurrent, pTocMax ) ) { return false; } int64_t entryTimestamp; if( !CheckedTocRead( pLoadFunction, entryTimestamp, TXT( "entry timestamp" ), pTocCurrent, pTocMax ) ) { return false; } uint32_t entrySize; if( !CheckedTocRead( pLoadFunction, entrySize, TXT( "entry size" ), pTocCurrent, pTocMax ) ) { return false; } Entry* pEntry = m_pEntryPool->Allocate(); HELIUM_ASSERT( pEntry ); pEntry->path = entryPath; pEntry->subDataIndex = entrySubDataIndex; pEntry->offset = entryOffset; pEntry->timestamp = entryTimestamp; pEntry->size = entrySize; m_entries.Add( pEntry ); HELIUM_VERIFY( m_entryMap.Insert( entryAccessor, KeyValue< EntryKey, Entry* >( key, pEntry ) ) ); } return true; }
/// 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(); }