static duk_ret_t IAssetTransfer_Asset(duk_context* ctx) { IAssetTransfer* thisObj = GetThisWeakObject<IAssetTransfer>(ctx); AssetPtr ret = thisObj->Asset(); PushWeakObject(ctx, ret.Get()); return 1; }
static duk_ret_t IAsset_Clone_String(duk_context* ctx) { IAsset* thisObj = GetThisWeakObject<IAsset>(ctx); String newAssetName = duk_require_string(ctx, 0); AssetPtr ret = thisObj->Clone(newAssetName); PushWeakObject(ctx, ret.Get()); return 1; }
/// Test whether an object load request has completed, getting the result object if so. /// /// Note that after a load request has completed (this function returns true), the request ID should no longer be /// considered valid. /// /// @param[in] id Load request ID. /// @param[out] rspObject Smart pointer set to the loaded object if loading has completed. Note that this will be /// set to the object instance even if the object isn't finished loading (i.e. still being /// linked, etc.). /// /// @return True if the load request has completed, false if it is still being processed. /// /// @see FinishLoad(), BeginLoadObject() bool AssetLoader::TryFinishLoad( size_t id, AssetPtr& rspObject ) { HELIUM_ASSERT( IsValid( id ) ); // Retrieve the load request and test whether it has completed. LoadRequest* pRequest = m_loadRequestPool.GetObject( id ); HELIUM_ASSERT( pRequest ); if( ( pRequest->stateFlags & LOAD_FLAG_FULLY_LOADED ) != LOAD_FLAG_FULLY_LOADED ) { return false; } HELIUM_TRACE( TraceLevels::Debug, "AssetLoader::TryFinishLoad - Completed load for asset %s\n", *pRequest->path.ToString()); HELIUM_ASSERT( !pRequest->spObject.Get() || pRequest->spObject->IsFullyLoaded() || ( pRequest->spObject->GetFlags() & Asset::FLAG_BROKEN ) ); rspObject = pRequest->spObject; // Acquire an exclusive lock to the request entry. AssetPath objectPath = pRequest->path; ConcurrentHashMap< AssetPath, LoadRequest* >::Accessor requestAccessor; HELIUM_VERIFY( m_loadRequestMap.Find( requestAccessor, objectPath ) ); HELIUM_ASSERT( requestAccessor->Second() == pRequest ); // Decrement the reference count on the load request, releasing it if the reference count reaches zero. int32_t newRequestCount = AtomicDecrementRelease( pRequest->requestCount ); if( newRequestCount == 0 ) { pRequest->spObject.Release(); pRequest->resolver.Clear(); m_loadRequestMap.Remove( requestAccessor ); m_loadRequestPool.Release( pRequest ); } requestAccessor.Release(); #if HELIUM_TOOLS if (rspObject) { if ( !(rspObject->SetFlags(Asset::FLAG_LOAD_EVENT_FIRED) & Asset::FLAG_LOAD_EVENT_FIRED) ) { AssetTracker::GetStaticInstance()->NotifyAssetLoaded( rspObject.Get() ); } } #endif return true; }
void OnSignal(AssetPtr param0) { duk_context* ctx = ctx_; duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "_OnSignal"); duk_remove(ctx, -2); duk_push_number(ctx, (size_t)key_); duk_push_array(ctx); PushWeakObject(ctx, param0.Get()); duk_put_prop_index(ctx, -2, 0); bool success = duk_pcall(ctx, 2) == 0; if (!success) LogError("[JavaScript] OnSignal: " + GetErrorString(ctx)); duk_pop(ctx); }
TEST(Engine, PackageObjectTest) { { AssetPath testPath; HELIUM_VERIFY( testPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING TXT( "EngineTest" ) HELIUM_OBJECT_PATH_CHAR_STRING TXT( "TestObject" ) ) ); AssetPtr spObject; HELIUM_VERIFY( gAssetLoader->LoadObject( testPath, spObject ) ); HELIUM_ASSERT( spObject ); Package* pTestPackageCast = Reflect::SafeCast< Package >( spObject.Get() ); HELIUM_ASSERT( !pTestPackageCast ); HELIUM_UNREF( pTestPackageCast ); // The following line should not compile... // Animation* pTestAnimationCast = Reflect::SafeCast< Animation >( pTestPackageCast ); // HELIUM_UNREF( pTestAnimationCast ); Asset* pTestObjectCast = Reflect::SafeCast< Asset >( spObject.Get() ); HELIUM_ASSERT( pTestObjectCast ); HELIUM_UNREF( pTestObjectCast ); } }
void AssetRefListener::OnAssetCreated(AssetPtr assetData) { if (assetData.Get() && !currentWaitingRef.Empty() && currentWaitingRef == assetData->Name()) { /// @todo Remove this logic once a EC_Material + EC_Mesh behaves correctly without failed requests, see generated:// logic in HandleAssetRefChange. /** Log the same message as before for non generated:// refs. This is good to do because AssetAPI has now said the request failed, so user might be confused when it still works. */ if (!currentWaitingRef.ToLower().StartsWith("generated://")) LogInfo("AssetRefListener: Asset \"" + assetData->Name() + "\" was created, applying after it loads."); // The asset we are waiting for has been created, hook to the IAsset::Loaded signal. currentWaitingRef = ""; asset = assetData; assetData->Loaded.Connect(this, &AssetRefListener::OnAssetLoaded); if (myAssetAPI) myAssetAPI->AssetCreated.Disconnect(this, &AssetRefListener::OnAssetCreated); } }
void RigidBody::OnCollisionMeshAssetLoaded(AssetPtr asset) { IMeshAsset* meshAsset = dynamic_cast<IMeshAsset*>(asset.Get()); if (!meshAsset) LogError("RigidBody::OnCollisionMeshAssetLoaded: Mesh asset load finished for asset \"" + asset->Name() + "\", but asset pointer was null!"); if (shapeType.Get() == TriMesh) { impl->triangleMesh = impl->owner->GetTriangleMeshFromMeshAsset(meshAsset); CreateCollisionShape(); } else if (shapeType.Get() == ConvexHull) { impl->convexHullSet = impl->owner->GetConvexHullSetFromMeshAsset(meshAsset); CreateCollisionShape(); } impl->cachedShapeType = shapeType.Get(); impl->cachedSize = size.Get(); }
void Sky::OnMaterialAssetLoaded(AssetPtr asset) { IMaterialAsset* mAsset = dynamic_cast<IMaterialAsset*>(asset.Get()); if (mAsset) { material_.Reset(); material_ = Urho3D::DynamicCast<IMaterialAsset>(asset); if (mAsset->textures_.Size() >= 6) { AssetReferenceList list; for (int i=0 ; i<6 ; ++i) list.Append(mAsset->textures_[i].second_); textureRefs.Set(list, AttributeChange::LocalOnly); // Update call is implicit via OnTextureAssetLoaded() } else Update(); } }
void AssetRefListener::HandleAssetRefChange(AssetAPI *assetApi, String assetRef, const String& assetType) { // Disconnect from any previous transfer we might be listening to if (!currentTransfer.Expired()) { IAssetTransfer* current = currentTransfer.Get(); current->Succeeded.Disconnect(this, &AssetRefListener::OnTransferSucceeded); current->Failed.Disconnect(this, &AssetRefListener::OnTransferFailed); currentTransfer.Reset(); } assert(assetApi); // Store AssetAPI ptr for later signal hooking. if (!myAssetAPI) myAssetAPI = assetApi; // If the ref is empty, don't go any further as it will just trigger the LogWarning below. assetRef = assetRef.Trimmed(); if (assetRef.Empty()) { asset = AssetPtr(); return; } currentWaitingRef = ""; // Resolve the protocol for generated:// assets. These assets are never meant to be // requested from AssetAPI, they cannot be fetched from anywhere. They can only be either // loaded or we must wait for something to load/create them. String protocolPart = ""; assetApi->ParseAssetRef(assetRef, &protocolPart); if (protocolPart.ToLower() == "generated") { AssetPtr loadedAsset = assetApi->FindAsset(assetRef); if (loadedAsset.Get() && loadedAsset->IsLoaded()) { // Asset is loaded, emit Loaded with 1 msec delay to preserve the logic // that HandleAssetRefChange won't emit anything itself as before. // Otherwise existing connection can break/be too late after calling this function. asset = loadedAsset; assetApi->GetFramework()->Frame()->DelayedExecute(0.0f).Connect(this, &AssetRefListener::EmitLoaded); return; } else { // Wait for it to be created. currentWaitingRef = assetRef; myAssetAPI->AssetCreated.Connect(this, &AssetRefListener::OnAssetCreated); } } else { // This is not a generated asset, request normally from asset api. AssetTransferPtr transfer = assetApi->RequestAsset(assetRef, assetType); if (!transfer) { LogWarning("AssetRefListener::HandleAssetRefChange: Asset request for asset \"" + assetRef + "\" failed."); return; } currentWaitingRef = assetRef; transfer->Succeeded.Connect(this, &AssetRefListener::OnTransferSucceeded); transfer->Failed.Connect(this, &AssetRefListener::OnTransferFailed); currentTransfer = transfer; } // Disconnect from the old asset's load signal if (asset) asset->Loaded.Disconnect(this, &AssetRefListener::OnAssetLoaded); asset = AssetPtr(); }
void AssetRefListener::EmitLoaded(float /*time*/) { AssetPtr currentAsset = asset.Lock(); if (currentAsset.Get()) Loaded.Emit(currentAsset); }
int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmdLine*/, int nCmdShow ) { ForceLoadComponentsDll(); #if HELIUM_TOOLS ForceLoadEditorSupportDll(); #endif HELIUM_TRACE_SET_LEVEL( TraceLevels::Debug ); Timer::StaticInitialize(); #if !HELIUM_RELEASE && !HELIUM_PROFILE Helium::InitializeSymbols(); #endif AsyncLoader::GetStaticInstance().Initialize(); FilePath baseDirectory; if ( !FileLocations::GetBaseDirectory( baseDirectory ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "Could not get base directory." ) ); return -1; } HELIUM_VERIFY( CacheManager::InitializeStaticInstance( baseDirectory ) ); Helium::Bullet::Initialize(); int resultCode = -1; { Reflect::Initialize(); Helium::Components::Initialize(); Helium::TaskScheduler::CalculateSchedule(); #if HELIUM_TOOLS #endif InitEngineJobsDefaultHeap(); InitGraphicsJobsDefaultHeap(); InitTestJobsDefaultHeap(); #if HELIUM_TOOLS //HELIUM_VERIFY( LooseAssetLoader::InitializeStaticInstance() ); HELIUM_VERIFY( LooseAssetLoader::InitializeStaticInstance() ); AssetPreprocessor* pAssetPreprocessor = AssetPreprocessor::CreateStaticInstance(); HELIUM_ASSERT( pAssetPreprocessor ); PlatformPreprocessor* pPlatformPreprocessor = new PcPreprocessor; HELIUM_ASSERT( pPlatformPreprocessor ); pAssetPreprocessor->SetPlatformPreprocessor( Cache::PLATFORM_PC, pPlatformPreprocessor ); #else HELIUM_VERIFY( CacheAssetLoader::InitializeStaticInstance() ); #endif #if !GTEST AssetLoader* gAssetLoader = NULL; #endif gAssetLoader = AssetLoader::GetStaticInstance(); HELIUM_ASSERT( gAssetLoader ); Config& rConfig = Config::GetStaticInstance(); rConfig.BeginLoad(); while( !rConfig.TryFinishLoad() ) { gAssetLoader->Tick(); } #if HELIUM_TOOLS ConfigPc::SaveUserConfig(); #endif uint32_t displayWidth; uint32_t displayHeight; //bool bFullscreen; bool bVsync; { StrongPtr< GraphicsConfig > spGraphicsConfig( rConfig.GetConfigObject< GraphicsConfig >( Name( TXT( "GraphicsConfig" ) ) ) ); HELIUM_ASSERT( spGraphicsConfig ); displayWidth = spGraphicsConfig->GetWidth(); displayHeight = spGraphicsConfig->GetHeight(); //bFullscreen = spGraphicsConfig->GetFullscreen(); bVsync = spGraphicsConfig->GetVsync(); } WNDCLASSEXW windowClass; windowClass.cbSize = sizeof( windowClass ); windowClass.style = 0; windowClass.lpfnWndProc = WindowProc; windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; windowClass.hInstance = hInstance; windowClass.hIcon = NULL; windowClass.hCursor = NULL; windowClass.hbrBackground = NULL; windowClass.lpszMenuName = NULL; windowClass.lpszClassName = L"HeliumTestAppClass"; windowClass.hIconSm = NULL; HELIUM_VERIFY( RegisterClassEx( &windowClass ) ); WindowData windowData; windowData.hMainWnd = NULL; windowData.hSubWnd = NULL; windowData.bProcessMessages = true; windowData.bShutdownRendering = false; windowData.resultCode = 0; DWORD dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; RECT windowRect; windowRect.left = 0; windowRect.top = 0; windowRect.right = static_cast< LONG >( displayWidth ); windowRect.bottom = static_cast< LONG >( displayHeight ); HELIUM_VERIFY( AdjustWindowRect( &windowRect, dwStyle, FALSE ) ); HWND hMainWnd = ::CreateWindowW( L"HeliumTestAppClass", L"Helium TestApp", dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, NULL, NULL, hInstance, NULL ); HELIUM_ASSERT( hMainWnd ); windowRect.left = 0; windowRect.top = 0; windowRect.right = static_cast< LONG >( displayWidth ); windowRect.bottom = static_cast< LONG >( displayHeight ); HELIUM_VERIFY( AdjustWindowRect( &windowRect, dwStyle, FALSE ) ); #if MULTI_WINDOW HWND hSubWnd = ::CreateWindowW( L"HeliumTestAppClass", L"Helium TestApp (second view)", dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, NULL, NULL, hInstance, NULL ); HELIUM_ASSERT( hSubWnd ); #endif windowData.hMainWnd = hMainWnd; SetWindowLongPtr( hMainWnd, GWLP_USERDATA, reinterpret_cast< LONG_PTR >( &windowData ) ); ShowWindow( hMainWnd, nCmdShow ); UpdateWindow( hMainWnd ); #if MULTI_WINDOW windowData.hSubWnd = hSubWnd; SetWindowLongPtr( hSubWnd, GWLP_USERDATA, reinterpret_cast< LONG_PTR >( &windowData ) ); ShowWindow( hSubWnd, nCmdShow ); UpdateWindow( hSubWnd ); #endif HELIUM_VERIFY( D3D9Renderer::CreateStaticInstance() ); Renderer* pRenderer = Renderer::GetStaticInstance(); HELIUM_ASSERT( pRenderer ); pRenderer->Initialize(); Renderer::ContextInitParameters contextInitParams; contextInitParams.pWindow = hMainWnd; contextInitParams.displayWidth = displayWidth; contextInitParams.displayHeight = displayHeight; contextInitParams.bVsync = bVsync; HELIUM_VERIFY( pRenderer->CreateMainContext( contextInitParams ) ); #if MULTI_WINDOW contextInitParams.pWindow = hSubWnd; RRenderContextPtr spSubRenderContext = pRenderer->CreateSubContext( contextInitParams ); HELIUM_ASSERT( spSubRenderContext ); #endif Input::Initialize(&hMainWnd, false); { AssetPath prePassShaderPath; HELIUM_VERIFY( prePassShaderPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING TXT( "Shaders" ) HELIUM_OBJECT_PATH_CHAR_STRING TXT( "PrePass.hlsl" ) ) ); AssetPtr spPrePassShader; HELIUM_VERIFY( AssetLoader::GetStaticInstance()->LoadObject( prePassShaderPath, spPrePassShader ) ); HELIUM_ASSERT( spPrePassShader.Get() ); } RenderResourceManager& rRenderResourceManager = RenderResourceManager::GetStaticInstance(); rRenderResourceManager.Initialize(); rRenderResourceManager.UpdateMaxViewportSize( displayWidth, displayHeight ); //// Create a scene definition SceneDefinitionPtr spSceneDefinition; gAssetLoader->LoadObject( AssetPath( TXT( "/ExampleGames/Empty/Scenes/TestScene:SceneDefinition" ) ), spSceneDefinition ); EntityDefinitionPtr spEntityDefinition; gAssetLoader->LoadObject( AssetPath( TXT( "/ExampleGames/Empty/Scenes/TestScene:TestBull_Entity" ) ), spEntityDefinition ); DynamicDrawer& rDynamicDrawer = DynamicDrawer::GetStaticInstance(); HELIUM_VERIFY( rDynamicDrawer.Initialize() ); RRenderContextPtr spMainRenderContext = pRenderer->GetMainContext(); HELIUM_ASSERT( spMainRenderContext ); WorldManager& rWorldManager = WorldManager::GetStaticInstance(); HELIUM_VERIFY( rWorldManager.Initialize() ); // Create a world WorldPtr spWorld( rWorldManager.CreateWorld( spSceneDefinition ) ); HELIUM_ASSERT( spWorld ); HELIUM_TRACE( TraceLevels::Info, TXT( "Created world \"%s\".\n" ), *spSceneDefinition->GetPath().ToString() ); //Slice *pRootSlice = spWorld->GetRootSlice(); //Entity *pEntity = pRootSlice->CreateEntity(spEntityDefinition); GraphicsScene* pGraphicsScene = spWorld->GetComponents().GetFirst<GraphicsManagerComponent>()->GetGraphicsScene(); HELIUM_ASSERT( pGraphicsScene ); GraphicsSceneView* pMainSceneView = NULL; if( pGraphicsScene ) { uint32_t mainSceneViewId = pGraphicsScene->AllocateSceneView(); if( IsValid( mainSceneViewId ) ) { float32_t aspectRatio = static_cast< float32_t >( displayWidth ) / static_cast< float32_t >( displayHeight ); RSurface* pDepthStencilSurface = rRenderResourceManager.GetDepthStencilSurface(); HELIUM_ASSERT( pDepthStencilSurface ); pMainSceneView = pGraphicsScene->GetSceneView( mainSceneViewId ); HELIUM_ASSERT( pMainSceneView ); pMainSceneView->SetRenderContext( spMainRenderContext ); pMainSceneView->SetDepthStencilSurface( pDepthStencilSurface ); pMainSceneView->SetAspectRatio( aspectRatio ); pMainSceneView->SetViewport( 0, 0, displayWidth, displayHeight ); pMainSceneView->SetClearColor( Color( 0x00202020 ) ); //spMainCamera->SetSceneViewId( mainSceneViewId ); #if MULTI_WINDOW uint32_t subSceneViewId = pGraphicsScene->AllocateSceneView(); if( IsValid( subSceneViewId ) ) { GraphicsSceneView* pSubSceneView = pGraphicsScene->GetSceneView( subSceneViewId ); HELIUM_ASSERT( pSubSceneView ); pSubSceneView->SetRenderContext( spSubRenderContext ); pSubSceneView->SetDepthStencilSurface( pDepthStencilSurface ); pSubSceneView->SetAspectRatio( aspectRatio ); pSubSceneView->SetViewport( 0, 0, displayWidth, displayHeight ); pSubSceneView->SetClearColor( Color( 0x00202020 ) ); //spSubCamera->SetSceneViewId( subSceneViewId ); } #endif } #if !HELIUM_RELEASE && !HELIUM_PROFILE BufferedDrawer& rSceneDrawer = pGraphicsScene->GetSceneBufferedDrawer(); rSceneDrawer.DrawScreenText( 20, 20, String( TXT( "CACHING" ) ), Color( 0xff00ff00 ), RenderResourceManager::DEBUG_FONT_SIZE_LARGE ); rSceneDrawer.DrawScreenText( 21, 20, String( TXT( "CACHING" ) ), Color( 0xff00ff00 ), RenderResourceManager::DEBUG_FONT_SIZE_LARGE ); //rSceneDrawer.Draw //Helium::DynamicDrawer &drawer = DynamicDrawer::GetStaticInstance(); //drawer. #endif } rWorldManager.Update(); float time = 0.0f; #if MULTI_WINDOW spSubRenderContext.Release(); #endif spMainRenderContext.Release(); Helium::StrongPtr<Helium::Texture2d> texture; gAssetLoader->LoadObject( AssetPath( TXT( "/Textures:Triangle.png" ) ), texture); Helium::RTexture2d *rTexture2d = texture->GetRenderResource2d(); while( windowData.bProcessMessages ) { #if GRAPHICS_SCENE_BUFFERED_DRAWER BufferedDrawer& rSceneDrawer = pGraphicsScene->GetSceneBufferedDrawer(); rSceneDrawer.DrawScreenText( 20, 20, String( TXT( "RUNNING" ) ), Color( 0xffffffff ), RenderResourceManager::DEBUG_FONT_SIZE_LARGE ); rSceneDrawer.DrawScreenText( 21, 20, String( TXT( "RUNNING" ) ), Color( 0xffffffff ), RenderResourceManager::DEBUG_FONT_SIZE_LARGE ); time += 0.01f; DynamicArray<SimpleVertex> verticesU; verticesU.New( -100.0f, -100.0f, 750.0f ); verticesU.New( 100.0f, -100.0f, 750.0f ); verticesU.New( 100.0f, 100.0f, 750.0f ); verticesU.New( -100.0f, 100.0f, 750.0f ); rSceneDrawer.DrawLineList( verticesU.GetData(), static_cast<uint32_t>( verticesU.GetSize() ) ); DynamicArray<SimpleTexturedVertex> verticesT; verticesT.New( Simd::Vector3( -100.0f, 100.0f, 750.0f ), Simd::Vector2( 0.0f, 0.0f ) ); verticesT.New( Simd::Vector3( 100.0f, 100.0f, 750.0f ), Simd::Vector2( 1.0f, 0.0f ) ); verticesT.New( Simd::Vector3( -100.0f, -100.0f, 750.0f ), Simd::Vector2( 0.0f, 1.0f ) ); verticesT.New( Simd::Vector3( 100.0f, -100.0f, 750.0f ), Simd::Vector2( 1.0f, 1.0f ) ); //rSceneDrawer.DrawTextured( // RENDERER_PRIMITIVE_TYPE_TRIANGLE_STRIP, // verticesT.GetData(), // verticesT.GetSize(), // NULL, // 2, // rTexture2d, Helium::Color(1.0f, 1.0f, 1.0f, 1.0f), Helium::RenderResourceManager::RASTERIZER_STATE_DEFAULT, Helium::RenderResourceManager::DEPTH_STENCIL_STATE_NONE); //rSceneDrawer.DrawTexturedQuad(rTexture2d); Helium::Simd::Matrix44 transform = Helium::Simd::Matrix44::IDENTITY; Simd::Vector3 location(0.0f, 400.0f, 0.0f); Simd::Quat rotation(Helium::Simd::Vector3::BasisZ, time); Simd::Vector3 scale(1000.0f, 1000.0f, 1000.0f); transform.SetRotationTranslationScaling(rotation, location, scale); rSceneDrawer.DrawTexturedQuad(rTexture2d, transform, Simd::Vector2(0.0f, 0.0f), Simd::Vector2(0.5f, 0.5f)); #endif //Helium::Simd::Vector3 up = Simd::Vector3::BasisY; ////Helium::Simd::Vector3 eye(5000.0f * sin(time), 0.0f, 5000.0f * cos(time)); //Helium::Simd::Vector3 eye(0.0f, 0.0f, -1000.0f); //Helium::Simd::Vector3 forward = Simd::Vector3::Zero - eye; //forward.Normalize(); ////pMainSceneView->SetClearColor( Color( 0xffffffff ) ); //pMainSceneView->SetView(eye, forward, up); if (Input::IsKeyDown(Input::KeyCodes::KC_A)) { HELIUM_TRACE( TraceLevels::Info, TXT( "A is down" ) ); } if (Input::IsKeyDown(Input::KeyCodes::KC_ESCAPE)) { HELIUM_TRACE( TraceLevels::Info, TXT( "Exiting" ) ); break; } MSG message; if( PeekMessage( &message, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &message ); DispatchMessage( &message ); if( windowData.bShutdownRendering ) { if( spWorld ) { spWorld->Shutdown(); } spWorld.Release(); WorldManager::DestroyStaticInstance(); spSceneDefinition.Release(); spEntityDefinition.Release(); DynamicDrawer::DestroyStaticInstance(); RenderResourceManager::DestroyStaticInstance(); Renderer::DestroyStaticInstance(); break; } if( message.message == WM_QUIT ) { windowData.bProcessMessages = false; windowData.resultCode = static_cast< int >( message.wParam ); resultCode = static_cast< int >( message.wParam ); break; } } rWorldManager.Update(); #if GRAPHICS_SCENE_BUFFERED_DRAWER if( pGraphicsScene ) { BufferedDrawer& rSceneDrawer = pGraphicsScene->GetSceneBufferedDrawer(); rSceneDrawer.DrawScreenText( 20, 20, String( TXT( "Debug text test!" ) ), Color( 0xffffffff ) ); } #endif } if( spWorld ) { spWorld->Shutdown(); } spWorld.Release(); } WorldManager::DestroyStaticInstance(); DynamicDrawer::DestroyStaticInstance(); RenderResourceManager::DestroyStaticInstance(); Helium::Input::Cleanup(); Renderer::DestroyStaticInstance(); JobManager::DestroyStaticInstance(); Config::DestroyStaticInstance(); #if HELIUM_TOOLS AssetPreprocessor::DestroyStaticInstance(); #endif AssetLoader::DestroyStaticInstance(); CacheManager::DestroyStaticInstance(); Helium::Components::Cleanup(); Reflect::Cleanup(); AssetType::Shutdown(); Asset::Shutdown(); Reflect::ObjectRefCountSupport::Shutdown(); Helium::Bullet::Cleanup(); AssetPath::Shutdown(); Name::Shutdown(); FileLocations::Shutdown(); ThreadLocalStackAllocator::ReleaseMemoryHeap(); #if HELIUM_ENABLE_MEMORY_TRACKING DynamicMemoryHeap::LogMemoryStats(); ThreadLocalStackAllocator::ReleaseMemoryHeap(); #endif return resultCode; }
/// Initialize all resources provided by this manager. /// /// @see Cleanup(), PostConfigUpdate() bool RenderResourceManager::Initialize() { // Release any existing resources. Cleanup(); // Get the renderer and graphics configuration. Renderer* pRenderer = Renderer::GetInstance(); if ( !pRenderer ) { return false; } Config* pConfig = Config::GetInstance(); if ( !HELIUM_VERIFY( pConfig ) ) { return false; } StrongPtr< GraphicsConfig > spGraphicsConfig( pConfig->GetConfigObject< GraphicsConfig >( Name( "GraphicsConfig" ) ) ); if ( !spGraphicsConfig ) { HELIUM_TRACE( TraceLevels::Error, "RenderResourceManager::Initialize(): Initialization failed; missing GraphicsConfig.\n" ); return false; } // 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. // TODO: XXX TMC: Migrate to a more data-driven solution. AssetLoader* pAssetLoader = AssetLoader::GetInstance(); HELIUM_ASSERT( pAssetLoader ); #ifdef HELIUM_DIRECT3D AssetPath prePassShaderPath; HELIUM_VERIFY( prePassShaderPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Shaders" HELIUM_OBJECT_PATH_CHAR_STRING "PrePass.hlsl" ) ); AssetPtr spPrePassShader; HELIUM_VERIFY( pAssetLoader->LoadObject( prePassShaderPath, spPrePassShader ) ); Shader* pPrePassShader = Reflect::SafeCast< Shader >( spPrePassShader.Get() ); if ( HELIUM_VERIFY( pPrePassShader ) ) { size_t loadId = pPrePassShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 ); HELIUM_ASSERT( IsValid( loadId ) ); if ( IsValid( loadId ) ) { while ( !pPrePassShader->TryFinishLoadVariant( loadId, m_spPrePassVertexShader ) ) { pAssetLoader->Tick(); } } } // Attempt to load the simple world-space, simple screen-space, and screen-space text shaders. // TODO: XXX TMC: Migrate to a more data-driven solution. AssetPath shaderPath; HELIUM_VERIFY( shaderPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Shaders" HELIUM_OBJECT_PATH_CHAR_STRING "Simple.hlsl" ) ); AssetPtr spShader; HELIUM_VERIFY( pAssetLoader->LoadObject( shaderPath, spShader ) ); Shader* pShader = Reflect::SafeCast< Shader >( spShader.Get() ); if ( HELIUM_VERIFY( pShader ) ) { size_t loadId = pShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 ); HELIUM_ASSERT( IsValid( loadId ) ); if ( IsValid( loadId ) ) { while ( !pShader->TryFinishLoadVariant( loadId, m_spSimpleWorldSpaceVertexShader ) ) { pAssetLoader->Tick(); } } loadId = pShader->BeginLoadVariant( RShader::TYPE_PIXEL, 0 ); HELIUM_ASSERT( IsValid( loadId ) ); if ( IsValid( loadId ) ) { while ( !pShader->TryFinishLoadVariant( loadId, m_spSimpleWorldSpacePixelShader ) ) { pAssetLoader->Tick(); } } } HELIUM_VERIFY( shaderPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Shaders" HELIUM_OBJECT_PATH_CHAR_STRING "ScreenSpaceTexture.hlsl" ) ); HELIUM_VERIFY( pAssetLoader->LoadObject( shaderPath, spShader ) ); pShader = Reflect::SafeCast< Shader >( spShader.Get() ); if ( HELIUM_VERIFY( pShader ) ) { size_t loadId = pShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 ); HELIUM_ASSERT( IsValid( loadId ) ); if ( IsValid( loadId ) ) { while ( !pShader->TryFinishLoadVariant( loadId, m_spSimpleScreenSpaceVertexShader ) ) { pAssetLoader->Tick(); } } loadId = pShader->BeginLoadVariant( RShader::TYPE_PIXEL, 0 ); HELIUM_ASSERT( IsValid( loadId ) ); if ( IsValid( loadId ) ) { while ( !pShader->TryFinishLoadVariant( loadId, m_spSimpleScreenSpacePixelShader ) ) { pAssetLoader->Tick(); } } } HELIUM_VERIFY( shaderPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Shaders" HELIUM_OBJECT_PATH_CHAR_STRING "ScreenText.hlsl" ) ); HELIUM_VERIFY( pAssetLoader->LoadObject( shaderPath, spShader ) ); pShader = Reflect::SafeCast< Shader >( spShader.Get() ); if ( HELIUM_VERIFY( pShader ) ) { size_t loadId = pShader->BeginLoadVariant( RShader::TYPE_VERTEX, 0 ); HELIUM_ASSERT( IsValid( loadId ) ); if ( IsValid( loadId ) ) { while ( !pShader->TryFinishLoadVariant( loadId, m_spScreenTextVertexShader ) ) { pAssetLoader->Tick(); } } loadId = pShader->BeginLoadVariant( RShader::TYPE_PIXEL, 0 ); HELIUM_ASSERT( IsValid( loadId ) ); if ( IsValid( loadId ) ) { while ( !pShader->TryFinishLoadVariant( loadId, m_spScreenTextPixelShader ) ) { pAssetLoader->Tick(); } } } // Attempt to load the debug fonts. // TODO: XXX TMC: Migrate to a more data-driven solution. AssetPath fontPath; AssetPtr spFont; HELIUM_VERIFY( fontPath.Set( HELIUM_PACKAGE_PATH_CHAR_STRING "Fonts" HELIUM_OBJECT_PATH_CHAR_STRING "DebugSmall" ) ); HELIUM_VERIFY( pAssetLoader->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 "Fonts" HELIUM_OBJECT_PATH_CHAR_STRING "DebugMedium" ) ); HELIUM_VERIFY( pAssetLoader->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 "Fonts" HELIUM_OBJECT_PATH_CHAR_STRING "DebugLarge" ) ); HELIUM_VERIFY( pAssetLoader->LoadObject( fontPath, spFont ) ); m_debugFonts[DEBUG_FONT_SIZE_LARGE] = Reflect::SafeCast< Font >( spFont.Get() ); spFont.Release(); #endif return true; }
/// Modify the name, owner, or instance index of this object. /// /// @param[in] rParameters Object rename parameters. /// /// @return True if this object was renamed successfully, false if not. /// /// @see GetName(), GetOwner(), GetInstanceIndex() bool Asset::Rename( const RenameParameters& rParameters ) { Name name = rParameters.name; Asset* pOwner = rParameters.spOwner; uint32_t instanceIndex = rParameters.instanceIndex; HELIUM_TRACE( TraceLevels::Debug, TXT("Asset::Rename(): Renaming object \"%s\" to \"%s\" (Old Owner: \"%s\". New Owner: \"%s\".)\n"), *m_name, *rParameters.name, m_spOwner.ReferencesObject() ? *m_spOwner->GetPath().ToString() : TXT("[none]"), rParameters.spOwner.ReferencesObject() ? *rParameters.spOwner->GetPath().ToString() : TXT("[none]")); // Only allow setting an empty name if no owner or instance index are given and this object has no children. if( name.IsEmpty() ) { HELIUM_ASSERT( !pOwner ); HELIUM_ASSERT( IsInvalid( instanceIndex ) ); if( pOwner || IsValid( instanceIndex ) ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "Asset::Rename(): Objects cannot have name information cleared if being assigned an " ) TXT( "owner or instance index.\n" ) ) ); return false; } HELIUM_ASSERT( !m_wpFirstChild ); if( m_wpFirstChild ) { HELIUM_TRACE( TraceLevels::Error, TXT( "Asset::Rename(): Cannot clear name information for objects with children.\n" ) ); return false; } } // Don't allow setting the owner to ourself. if( pOwner == this ) { HELIUM_TRACE( TraceLevels::Error, TXT( "Asset::Rename(): Cannot set the owner of an object to itself.\n" ) ); return false; } // Don't allow setting the owner to an object with no name information. if( pOwner && pOwner->m_name.IsEmpty() ) { HELIUM_TRACE( TraceLevels::Error, TXT( "Asset::Rename(): Cannot set the owner of an object to an object with no path information.\n" ) ); return false; } if( IsPackage() ) { // Don't allow package objects to be children of non-package objects. if( pOwner && !pOwner->IsPackage() ) { HELIUM_TRACE( TraceLevels::Error, TXT( "Asset::Rename(): Cannot set a non-package as the owner of a package.\n" ) ); return false; } // Don't allow instance indexing for packages. if( IsValid( instanceIndex ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "Asset::Rename(): Instance indexing not supported for packages.\n" ) ); return false; } } // Don't need to do anything if the name, owner, and instance index are not changing. if( name == m_name && pOwner == m_spOwner && ( instanceIndex == m_instanceIndex || ( instanceIndex == INSTANCE_INDEX_AUTO && IsValid( m_instanceIndex ) ) ) ) { return true; } // Hold onto a reference to the current owner until we return from this function. This is done in case this object // has the last strong reference to it, in which case we would encounter a deadlock if clearing its reference while // we still have a write lock on the object list (object destruction also requires acquiring a write lock). AssetPtr spOldOwner = m_spOwner; { // Acquire a write lock on the object list to prevent objects from being added and removed as well as keep // objects from being renamed while this object is being renamed. ScopeWriteLock scopeLock( sm_objectListLock ); // Get the list of children belonging to the new owner. AssetWPtr& rwpOwnerFirstChild = ( pOwner ? pOwner->m_wpFirstChild : sm_wpFirstTopLevelObject ); // Don't check for name clashes if we're clearing the object path name information. if( !name.IsEmpty() ) { // Resolve name clashes either through the instance index lookup map (if an instance index will be assigned) // or through a child object search (if no instance index will be used). if( IsValid( instanceIndex ) ) { // Get the instance index map for the requested object name. ChildNameInstanceIndexMap& rNameInstanceIndexMap = GetNameInstanceIndexMap(); HELIUM_ASSERT( sm_pEmptyNameInstanceIndexMap ); HELIUM_ASSERT( sm_pEmptyInstanceIndexSet ); sm_pEmptyNameInstanceIndexMap->First() = ( pOwner ? pOwner->GetPath() : AssetPath( NULL_NAME ) ); sm_pEmptyInstanceIndexSet->First() = name; ChildNameInstanceIndexMap::Accessor childNameMapAccessor; rNameInstanceIndexMap.Insert( childNameMapAccessor, *sm_pEmptyNameInstanceIndexMap ); NameInstanceIndexMap::Accessor indexSetAccessor; childNameMapAccessor->Second().Insert( indexSetAccessor, *sm_pEmptyInstanceIndexSet ); InstanceIndexSet& rIndexSet = indexSetAccessor->Second(); InstanceIndexSet::ConstAccessor indexAccessor; if( instanceIndex == INSTANCE_INDEX_AUTO ) { // Pick an unused instance index. instanceIndex = 0; while( !rIndexSet.Insert( indexAccessor, instanceIndex ) ) { ++instanceIndex; HELIUM_ASSERT( instanceIndex < INSTANCE_INDEX_AUTO ); } } else { // Attempt to acquire the specified instance index. if( !rIndexSet.Insert( indexAccessor, instanceIndex ) ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "Asset::Rename(): Object already exists with the specified owner (%s), name " ) TXT( "(%s), and instance index (%" ) PRIu32 ").\n" ), ( pOwner ? *pOwner->GetPath().ToString() : TXT( "none" ) ), *name, instanceIndex ); return false; } } } else { // Check each child of the new owner for a name clash. for( Asset* pChild = rwpOwnerFirstChild; pChild != NULL; pChild = pChild->m_wpNextSibling ) { if( pChild->m_name == name && pChild->m_instanceIndex == instanceIndex ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "Asset::Rename(): Object already exists with the specified owner (%s) and " ) TXT( "name (%s).\n" ) ), ( pOwner ? *pOwner->GetPath().ToString() : TXT( "none" ) ), *name ); return false; } } } } // Remove any old instance index tracking for the old path name. if( IsValid( m_instanceIndex ) ) { AssetPath ownerPath = ( spOldOwner ? spOldOwner->GetPath() : AssetPath( NULL_NAME ) ); ChildNameInstanceIndexMap& rNameInstanceIndexMap = GetNameInstanceIndexMap(); ChildNameInstanceIndexMap::Accessor childMapAccessor; HELIUM_VERIFY( rNameInstanceIndexMap.Find( childMapAccessor, ownerPath ) ); NameInstanceIndexMap& rNameMap = childMapAccessor->Second(); NameInstanceIndexMap::Accessor nameMapAccessor; HELIUM_VERIFY( rNameMap.Find( nameMapAccessor, m_name ) ); InstanceIndexSet& rIndexSet = nameMapAccessor->Second(); HELIUM_VERIFY( rIndexSet.Remove( m_instanceIndex ) ); /* if( rIndexSet.IsEmpty() ) { HELIUM_VERIFY( rNameMap.Remove( nameMapAccessor ) ); if( rNameMap.IsEmpty() ) { HELIUM_VERIFY( rNameInstanceIndexMap.Remove( childMapAccessor ) ); } } */ } // If the owner of this object is changing, remove this object from its old owner's list and add it to the new // owner. if( spOldOwner.Get() != pOwner || ( m_name.IsEmpty() ? !name.IsEmpty() : name.IsEmpty() ) ) { // Object should not be in any child object lists if its name is empty. if( !m_name.IsEmpty() ) { AssetWPtr& rwpOldOwnerFirstChild = ( spOldOwner ? spOldOwner->m_wpFirstChild : sm_wpFirstTopLevelObject ); Asset* pPreviousChild = NULL; Asset* pChild = rwpOldOwnerFirstChild; while( pChild ) { if( pChild == this ) { ( pPreviousChild ? pPreviousChild->m_wpNextSibling : rwpOldOwnerFirstChild ) = m_wpNextSibling; m_wpNextSibling.Release(); break; } pPreviousChild = pChild; pChild = pChild->m_wpNextSibling; } } // If you assert here, it's possible that sm_wpFirstTopLevelObject is null. This can happen if an asset is destroyed // after the asset system is shut down HELIUM_ASSERT( !m_wpNextSibling ); // Only store the object in a child object list if it is being given a valid name. if( !name.IsEmpty() ) { m_wpNextSibling = rwpOwnerFirstChild; rwpOwnerFirstChild = this; } } // Set the new path name. m_name = name; m_spOwner = pOwner; m_instanceIndex = instanceIndex; // Update path information for this object and its children. UpdatePath(); } return true; }