/// Initialize this cache. /// /// This will verify the existence of the given files and prepare for cache loading. Note that no file loading is /// performed at this time. /// /// Once initialization is performed, the table of contents must be loaded using BeginLoadToc(). /// /// @param[in] name Name identifying this cache. /// @param[in] platform Cache platform identifier. /// @param[in] pTocFileName Path name of the table of contents file. /// @param[in] pCacheFileName Path name of the cache file. /// /// @return True if initialization was successful, false if not. /// /// @see Shutdown(), BeginLoadToc() bool Cache::Initialize( Name name, EPlatform platform, const tchar_t* pTocFileName, const tchar_t* pCacheFileName ) { HELIUM_ASSERT( !name.IsEmpty() ); HELIUM_ASSERT( static_cast< size_t >( platform ) < static_cast< size_t >( PLATFORM_MAX ) ); HELIUM_ASSERT( pTocFileName ); HELIUM_ASSERT( pCacheFileName ); Shutdown(); m_name = name; m_platform = platform; Path tocFile( pTocFileName ); int64_t tocSize64 = tocFile.Size(); if( tocSize64 != -1 && static_cast< uint64_t >( tocSize64 ) >= UINT32_MAX ) { HELIUM_TRACE( TRACE_ERROR, TXT( "Cache::Initialize(): TOC file \"%s\" exceeds the maximum allowed size for TOC files (2 GB).\n" ), pTocFileName ); return false; } m_tocFileName = pTocFileName; m_cacheFileName = pCacheFileName; m_tocSize = static_cast< uint32_t >( tocSize64 ); HELIUM_ASSERT( !m_pEntryPool ); m_pEntryPool = new ObjectPool< Entry >( ENTRY_POOL_BLOCK_SIZE ); HELIUM_ASSERT( m_pEntryPool ); return true; }
bool Helium::AssetResolver::Resolve( const Name& identity, Reflect::ObjectPtr& pointer, const Reflect::MetaClass* pointerClass ) { // Paths begin with / if (!identity.IsEmpty() && (*identity)[0] == '/') { HELIUM_TRACE( TraceLevels::Info, TXT( "Resolving object [%s]\n" ), identity.Get() ); AssetPath p; p.Set(*identity); size_t loadRequestId = AssetLoader::GetStaticInstance()->BeginLoadObject(p); m_Fixups.Push( Fixup( pointer, pointerClass, loadRequestId ) ); return true; } else { HELIUM_TRACE( TraceLevels::Info, TXT( "Deferring resolution of [%s] to archive\n" ), identity.Get() ); } return false; }
/// Initialize this package loader for loading from the specified cache files. /// /// @param[in] cacheName Name of the cache to use. /// /// @return True if initialization was successful, false if not. /// /// @see Shutdown() bool CachePackageLoader::Initialize( Name cacheName ) { HELIUM_ASSERT( !cacheName.IsEmpty() ); Shutdown(); // Acquire the cache. CacheManager& rCacheManager = CacheManager::GetStaticInstance(); m_pCache = rCacheManager.GetCache( cacheName ); if( !m_pCache ) { HELIUM_TRACE( TraceLevels::Error, TXT( "CachePackageLoader::Initialize(): Failed to initialize cache \"%s\".\n" ), *cacheName ); return false; } return true; }
/// Resolve a dependency on a type reference. /// /// @param[in] typeName Type name. /// /// @return Dependency index. /// /// @see ResolveObjectDependency() uint32_t BinarySerializer::ResolveTypeDependency( Name typeName ) { uint32_t typeIndex; SetInvalid( typeIndex ); if( !typeName.IsEmpty() ) { size_t dependencyCount = m_typeDependencies.GetSize(); for( size_t dependencyIndex = 0; dependencyIndex < dependencyCount; ++dependencyIndex ) { if( m_typeDependencies[ dependencyIndex ] == typeName ) { return static_cast< uint32_t >( dependencyIndex ); } } HELIUM_ASSERT( dependencyCount < UINT32_MAX ); m_typeDependencies.Push( typeName ); typeIndex = static_cast< uint32_t >( dependencyCount ); } return typeIndex; }
bool Helium::AssetResolver::Resolve( const Name& identity, Reflect::ObjectPtr& pointer, const Reflect::MetaClass* pointerClass ) { // Paths begin with / if (!identity.IsEmpty() && (*identity)[0] == '/') { HELIUM_TRACE( TraceLevels::Info, TXT( "Resolving object [%s]\n" ), identity.Get() ); AssetPath p; p.Set(*identity); size_t loadRequestId = AssetLoader::GetStaticInstance()->BeginLoadObject(p); m_Fixups.Push( Fixup( pointer, pointerClass, loadRequestId ) ); return true; } else { #if HELIUM_TOOLS // Some extra checking to make friendly error messages String str ( identity.Get() ); uint32_t index = Invalid< uint32_t >(); int parseSuccessful = str.Parse( "%d", &index ); if (!parseSuccessful) { HELIUM_TRACE( TraceLevels::Warning, "AssetResolver::Resolve - Identity '%s' is not a number, but doesn't start with '/'. If this is a path, it must begin with '/'!\n", *str); } #endif HELIUM_TRACE( TraceLevels::Debug, TXT( "Deferring resolution of [%s] to archive\n" ), identity.Get() ); } return false; }
/// 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 GameObject::Rename( const RenameParameters& rParameters ) { Name name = rParameters.name; GameObject* pOwner = rParameters.spOwner; uint32_t instanceIndex = rParameters.instanceIndex; HELIUM_TRACE( TraceLevels::Debug, TXT("GameObject::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( "GameObject::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( "GameObject::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( "GameObject::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( "GameObject::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( "GameObject::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( "GameObject::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). GameObjectPtr 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. GameObjectWPtr& 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() : GameObjectPath( 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( "GameObject::Rename(): Object already exists with the specified owner (%s), name " ) TXT( "(%s), and instance index (%" ) TPRIu32 TXT( ").\n" ) ), ( pOwner ? *pOwner->GetPath().ToString() : TXT( "none" ) ), *name, instanceIndex ); return false; } } } else { // Check each child of the new owner for a name clash. for( GameObject* pChild = rwpOwnerFirstChild; pChild != NULL; pChild = pChild->m_wpNextSibling ) { if( pChild->m_name == name && pChild->m_instanceIndex == instanceIndex ) { HELIUM_TRACE( TraceLevels::Error, ( TXT( "GameObject::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 ) ) { GameObjectPath ownerPath = ( spOldOwner ? spOldOwner->GetPath() : GameObjectPath( 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() ) { GameObjectWPtr& rwpOldOwnerFirstChild = ( spOldOwner ? spOldOwner->m_wpFirstChild : sm_wpFirstTopLevelObject ); GameObject* pPreviousChild = NULL; GameObject* pChild = rwpOldOwnerFirstChild; while( pChild ) { if( pChild == this ) { ( pPreviousChild ? pPreviousChild->m_wpNextSibling : rwpOldOwnerFirstChild ) = m_wpNextSibling; m_wpNextSibling.Release(); break; } pPreviousChild = pChild; pChild = pChild->m_wpNextSibling; } } 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; }
/// Get a unique index associated with a specific set of shader preprocessor options. /// /// Note that this will always attempt to match up a valid index, even if invalid options are specified or select /// options are missing. /// /// @param[in] shaderType Type of shader. /// @param[in] pOptionPairs Mixed list of shader toggle states and shader selection pair values. /// @param[in] optionPairCount Number of options in the option pair array. /// /// @return Index to use for the specified options. size_t Shader::Options::GetOptionSetIndex( RShader::EType shaderType, const SelectPair* pOptionPairs, size_t optionPairCount ) const { HELIUM_ASSERT( static_cast< size_t >( shaderType ) < static_cast< size_t >( RShader::TYPE_MAX ) ); HELIUM_ASSERT( pOptionPairs || optionPairCount == 0 ); uint32_t shaderTypeMask = ( 1 << shaderType ); size_t optionIndex = 0; size_t optionIndexMultiplier = 1; static const Name disabledToggleValues[] = { Name( NULL_NAME ), Name( TXT( "0" ) ), Name( TXT( "false" ) ) }; size_t shaderToggleCount = m_toggles.GetSize(); for( size_t shaderToggleIndex = 0; shaderToggleIndex < shaderToggleCount; ++shaderToggleIndex ) { const Toggle& rShaderToggle = m_toggles[ shaderToggleIndex ]; if( !( rShaderToggle.shaderTypeFlags & shaderTypeMask ) ) { continue; } Name shaderToggleName = rShaderToggle.name; for( size_t optionPairIndex = 0; optionPairIndex < optionPairCount; ++optionPairIndex ) { const SelectPair& rOptionPair = pOptionPairs[ optionPairIndex ]; if( rOptionPair.name == shaderToggleName ) { Name value = rOptionPair.choice; size_t disabledValueIndex; for( disabledValueIndex = 0; disabledValueIndex < HELIUM_ARRAY_COUNT( disabledToggleValues ); ++disabledValueIndex ) { if( value == disabledToggleValues[ disabledValueIndex ] ) { break; } } if( disabledValueIndex >= HELIUM_ARRAY_COUNT( disabledToggleValues ) ) { optionIndex |= optionIndexMultiplier; } break; } } optionIndexMultiplier <<= 1; } size_t shaderSelectCount = m_selects.GetSize(); for( size_t shaderSelectIndex = 0; shaderSelectIndex < shaderSelectCount; ++shaderSelectIndex ) { const Select& rShaderSelect = m_selects[ shaderSelectIndex ]; if( !( rShaderSelect.shaderTypeFlags & shaderTypeMask ) ) { continue; } Name shaderSelectName = rShaderSelect.name; bool bSetSelectIndex = false; for( size_t optionPairIndex = 0; optionPairIndex < optionPairCount; ++optionPairIndex ) { const SelectPair& rPair = pOptionPairs[ optionPairIndex ]; if( rPair.name == shaderSelectName ) { const DynArray< Name >& rShaderSelectChoices = rShaderSelect.choices; size_t shaderSelectChoiceCount = rShaderSelectChoices.GetSize(); Name targetChoiceName = rPair.choice; if( !targetChoiceName.IsEmpty() ) { for( size_t shaderSelectChoiceIndex = 0; shaderSelectChoiceIndex < shaderSelectChoiceCount; ++shaderSelectChoiceIndex ) { if( rShaderSelectChoices[ shaderSelectChoiceIndex ] == targetChoiceName ) { optionIndex += shaderSelectChoiceIndex * optionIndexMultiplier; bSetSelectIndex = true; break; } } } break; } } if( !bSetSelectIndex ) { optionIndex += ( rShaderSelect.bOptional ? rShaderSelect.choices.GetSize() * optionIndexMultiplier : 0 ); } optionIndexMultiplier *= rShaderSelect.choices.GetSize() + rShaderSelect.bOptional; } return optionIndex; }
/// Get a unique index associated with a specific set of shader preprocessor options. /// /// Note that this will always attempt to match up a valid index, even if invalid options are specified or select /// options are missing. /// /// @param[in] shaderType Type of shader. /// @param[in] pToggleNames List of enabled shader toggles. /// @param[in] toggleNameCount Number of names in the toggle name array. /// @param[in] pSelectPairs List of shader selection pair values. /// @param[in] selectPairCount Number of shader selection pair values in the given array. /// /// @return Index to use for the specified options. size_t Shader::Options::GetOptionSetIndex( RShader::EType shaderType, const Name* pToggleNames, size_t toggleNameCount, const SelectPair* pSelectPairs, size_t selectPairCount ) const { HELIUM_ASSERT( static_cast< size_t >( shaderType ) < static_cast< size_t >( RShader::TYPE_MAX ) ); HELIUM_ASSERT( pToggleNames || toggleNameCount == 0 ); HELIUM_ASSERT( pSelectPairs || selectPairCount == 0 ); uint32_t shaderTypeMask = ( 1 << shaderType ); size_t optionIndex = 0; size_t optionIndexMultiplier = 1; size_t shaderToggleCount = m_toggles.GetSize(); for( size_t shaderToggleIndex = 0; shaderToggleIndex < shaderToggleCount; ++shaderToggleIndex ) { const Toggle& rShaderToggle = m_toggles[ shaderToggleIndex ]; if( !( rShaderToggle.shaderTypeFlags & shaderTypeMask ) ) { continue; } Name shaderToggleName = rShaderToggle.name; for( size_t enabledToggleIndex = 0; enabledToggleIndex < toggleNameCount; ++enabledToggleIndex ) { if( pToggleNames[ enabledToggleIndex ] == shaderToggleName ) { optionIndex |= optionIndexMultiplier; break; } } optionIndexMultiplier <<= 1; } size_t shaderSelectCount = m_selects.GetSize(); for( size_t shaderSelectIndex = 0; shaderSelectIndex < shaderSelectCount; ++shaderSelectIndex ) { const Select& rShaderSelect = m_selects[ shaderSelectIndex ]; if( !( rShaderSelect.shaderTypeFlags & shaderTypeMask ) ) { continue; } Name shaderSelectName = rShaderSelect.name; bool bSetSelectIndex = false; for( size_t selectPairIndex = 0; selectPairIndex < selectPairCount; ++selectPairIndex ) { const SelectPair& rPair = pSelectPairs[ selectPairIndex ]; if( rPair.name == shaderSelectName ) { const DynArray< Name >& rShaderSelectChoices = rShaderSelect.choices; size_t shaderSelectChoiceCount = rShaderSelectChoices.GetSize(); Name targetChoiceName = rPair.choice; if( !targetChoiceName.IsEmpty() ) { for( size_t shaderSelectChoiceIndex = 0; shaderSelectChoiceIndex < shaderSelectChoiceCount; ++shaderSelectChoiceIndex ) { if( rShaderSelectChoices[ shaderSelectChoiceIndex ] == targetChoiceName ) { optionIndex += shaderSelectChoiceIndex * optionIndexMultiplier; bSetSelectIndex = true; break; } } } break; } } if( !bSetSelectIndex ) { optionIndex += ( rShaderSelect.bOptional ? rShaderSelect.choices.GetSize() * optionIndexMultiplier : 0 ); } optionIndexMultiplier *= rShaderSelect.choices.GetSize() + rShaderSelect.bOptional; } return optionIndex; }
/// Synchronize the shader parameter list with those provided by the selected shader variant. /// /// @see SynchronizeFloatVectorParameters(), SynchronizeTextureParameters() void Material::SynchronizeShaderParameters() { Shader* pShader = m_spShader; if( !pShader ) { m_float1Parameters.Clear(); m_float2Parameters.Clear(); m_float3Parameters.Clear(); m_float4Parameters.Clear(); m_textureParameters.Clear(); } // Synchronize floating-point constant parameters. Name parameterConstantBufferName = GetParameterConstantBufferName(); size_t existingFloat1Count = m_float1Parameters.GetSize(); size_t existingFloat2Count = m_float2Parameters.GetSize(); size_t existingFloat3Count = m_float3Parameters.GetSize(); size_t existingFloat4Count = m_float4Parameters.GetSize(); DynamicArray< Float1Parameter > newFloat1Parameters; DynamicArray< Float2Parameter > newFloat2Parameters; DynamicArray< Float3Parameter > newFloat3Parameters; DynamicArray< Float4Parameter > newFloat4Parameters; for( size_t shaderTypeIndex = 0; shaderTypeIndex < HELIUM_ARRAY_COUNT( m_shaderVariants ); ++shaderTypeIndex ) { ShaderVariant* pShaderVariant = m_shaderVariants[ shaderTypeIndex ]; if( !pShaderVariant ) { continue; } const ShaderConstantBufferInfoSet* pBufferSet = pShaderVariant->GetConstantBufferInfoSet( 0 ); if( !pBufferSet ) { continue; } bool bCheckDuplicates = ( !newFloat1Parameters.IsEmpty() || !newFloat2Parameters.IsEmpty() || !newFloat3Parameters.IsEmpty() || !newFloat4Parameters.IsEmpty() ); const DynamicArray< ShaderConstantBufferInfo >& rBuffers = pBufferSet->buffers; size_t bufferCount = rBuffers.GetSize(); for( size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex ) { const ShaderConstantBufferInfo& rBufferInfo = rBuffers[ bufferIndex ]; if( rBufferInfo.name != parameterConstantBufferName ) { continue; } const DynamicArray< ShaderConstantInfo >& rConstants = rBufferInfo.constants; size_t constantCount = rConstants.GetSize(); for( size_t constantIndex = 0; constantIndex < constantCount; ++constantIndex ) { const ShaderConstantInfo& rConstantInfo = rConstants[ constantIndex ]; // Constants must be between 1 and 4 floating-point values. uint16_t constantSize = rConstantInfo.usedSize; if( constantSize < sizeof( float32_t ) || constantSize > sizeof( float32_t ) * 4 ) { continue; } Name constantName = rConstantInfo.name; size_t parameterIndex; if( bCheckDuplicates ) { size_t parameterCount = newFloat1Parameters.GetSize(); for( parameterIndex = 0; parameterIndex < parameterCount; ++parameterIndex ) { if( newFloat1Parameters[ parameterIndex ].name == constantName ) { break; } } if( parameterIndex < parameterCount ) { continue; } parameterCount = newFloat2Parameters.GetSize(); for( parameterIndex = 0; parameterIndex < parameterCount; ++parameterIndex ) { if( newFloat2Parameters[ parameterIndex ].name == constantName ) { break; } } if( parameterIndex < parameterCount ) { continue; } parameterCount = newFloat3Parameters.GetSize(); for( parameterIndex = 0; parameterIndex < parameterCount; ++parameterIndex ) { if( newFloat3Parameters[ parameterIndex ].name == constantName ) { break; } } if( parameterIndex < parameterCount ) { continue; } parameterCount = newFloat4Parameters.GetSize(); for( parameterIndex = 0; parameterIndex < parameterCount; ++parameterIndex ) { if( newFloat4Parameters[ parameterIndex ].name == constantName ) { break; } } if( parameterIndex < parameterCount ) { continue; } } Simd::Vector4 newValue( 0.0f ); for( parameterIndex = 0; parameterIndex < existingFloat1Count; ++parameterIndex ) { const Float1Parameter& rExistingParameter = m_float1Parameters[ parameterIndex ]; if( rExistingParameter.name == constantName ) { newValue.SetElement( 0, rExistingParameter.value ); break; } } if( parameterIndex >= existingFloat1Count ) { for( parameterIndex = 0; parameterIndex < existingFloat2Count; ++parameterIndex ) { const Float2Parameter& rExistingParameter = m_float2Parameters[ parameterIndex ]; if( rExistingParameter.name == constantName ) { newValue.SetElement( 0, rExistingParameter.value.GetX() ); newValue.SetElement( 1, rExistingParameter.value.GetY() ); break; } } if( parameterIndex >= existingFloat2Count ) { for( parameterIndex = 0; parameterIndex < existingFloat3Count; ++parameterIndex ) { const Float3Parameter& rExistingParameter = m_float3Parameters[ parameterIndex ]; if( rExistingParameter.name == constantName ) { newValue.SetElement( 0, rExistingParameter.value.GetElement( 0 ) ); newValue.SetElement( 1, rExistingParameter.value.GetElement( 1 ) ); newValue.SetElement( 2, rExistingParameter.value.GetElement( 2 ) ); break; } } if( parameterIndex >= existingFloat3Count ) { for( parameterIndex = 0; parameterIndex < existingFloat4Count; ++parameterIndex ) { const Float4Parameter& rExistingParameter = m_float4Parameters[ parameterIndex ]; if( rExistingParameter.name == constantName ) { newValue = rExistingParameter.value; break; } } } } } if( constantSize < sizeof( float32_t ) * 2 ) { Float1Parameter* pParameter = newFloat1Parameters.New(); HELIUM_ASSERT( pParameter ); pParameter->name = constantName; pParameter->value = newValue.GetElement( 0 ); } else if( constantSize < sizeof( float32_t ) * 3 ) { Float2Parameter* pParameter = newFloat2Parameters.New(); HELIUM_ASSERT( pParameter ); pParameter->name = constantName; pParameter->value = Simd::Vector2( newValue.GetElement( 0 ), newValue.GetElement( 1 ) ); } else if( constantSize < sizeof( float32_t ) * 4 ) { Float3Parameter* pParameter = newFloat3Parameters.New(); HELIUM_ASSERT( pParameter ); pParameter->name = constantName; pParameter->value = Simd::Vector3( newValue.GetElement( 0 ), newValue.GetElement( 1 ), newValue.GetElement( 2 ) ); } else { Float4Parameter* pParameter = newFloat4Parameters.New(); HELIUM_ASSERT( pParameter ); pParameter->name = constantName; pParameter->value = newValue; } } } } newFloat1Parameters.Trim(); newFloat2Parameters.Trim(); newFloat3Parameters.Trim(); newFloat4Parameters.Trim(); m_float1Parameters.Swap( newFloat1Parameters ); m_float2Parameters.Swap( newFloat2Parameters ); m_float3Parameters.Swap( newFloat3Parameters ); m_float4Parameters.Swap( newFloat4Parameters ); newFloat1Parameters.Clear(); newFloat2Parameters.Clear(); newFloat3Parameters.Clear(); newFloat4Parameters.Clear(); // Synchronize texture parameters. size_t existingTextureCount = m_textureParameters.GetSize(); DynamicArray< TextureParameter > newTextureParameters; for( size_t shaderTypeIndex = 0; shaderTypeIndex < HELIUM_ARRAY_COUNT( m_shaderVariants ); ++shaderTypeIndex ) { ShaderVariant* pShaderVariant = m_shaderVariants[ shaderTypeIndex ]; if( !pShaderVariant ) { continue; } const ShaderTextureInfoSet* pTextureSet = pShaderVariant->GetTextureInfoSet( 0 ); if( !pTextureSet ) { continue; } bool bCheckDuplicates = !newTextureParameters.IsEmpty(); const DynamicArray< ShaderTextureInfo >& rTextureInputs = pTextureSet->inputs; size_t textureInputCount = rTextureInputs.GetSize(); for( size_t textureIndex = 0; textureIndex < textureInputCount; ++textureIndex ) { const ShaderTextureInfo& rTextureInfo = rTextureInputs[ textureIndex ]; // Ignore textures prefixed with an underscore, as they are reserved for system use. Name textureInputName = rTextureInfo.name; if( !textureInputName.IsEmpty() && ( *textureInputName )[ 0 ] == TXT( '_' ) ) { continue; } size_t parameterIndex; if( bCheckDuplicates ) { size_t textureParameterCount = newTextureParameters.GetSize(); for( parameterIndex = 0; parameterIndex < textureParameterCount; ++parameterIndex ) { if( newTextureParameters[ parameterIndex ].name == textureInputName ) { break; } } if( parameterIndex < textureParameterCount ) { continue; } } TextureParameter* pParameter = newTextureParameters.New(); HELIUM_ASSERT( pParameter ); pParameter->name = textureInputName; for( parameterIndex = 0; parameterIndex < existingTextureCount; ++parameterIndex ) { const TextureParameter& rTextureParameter = m_textureParameters[ parameterIndex ]; if( rTextureParameter.name == textureInputName ) { pParameter->value = rTextureParameter.value; break; } } } } newTextureParameters.Trim(); m_textureParameters.Swap( newTextureParameters ); newTextureParameters.Clear(); }
/// Create a type object. /// /// @param[in] name Type name. /// @param[in] pTypePackage Package in which the template object should be stored. /// @param[in] pParent Parent type. /// @param[in] pTemplate Template object. /// @param[in] flags Type flags. /// /// @return Pointer to the type object if created successfully, null if not. /// /// @see Unregister() // PMD: Removing const because: // - Objects must be able to have properties of the same type as the outer type (i.e. Asset has reference to Asset that is the template) // - So, s_MetaClass must be set before calling PopulateMetaType // - So, this function must return a pointer that PopulateMetaType can work on, rather than calling PopulateMetaType directly // - If not for this restriction, I'd want to see if we could call MetaClass::Create and Composite::Create, rather than doing duplicate set-up work here // - To prevent un-consting parameter to PopulateMetaType, making AssetType return non-const AssetType* AssetType::Create( const Reflect::MetaClass* pClass, Package* pTypePackage, const AssetType* pParent, Asset* pTemplate, uint32_t flags ) { HELIUM_ASSERT( pClass ); HELIUM_ASSERT( pTypePackage ); HELIUM_ASSERT( pTemplate ); Name name; name.Set( pClass->m_Name ); HELIUM_ASSERT( !name.IsEmpty() ); // Register the template object with the object system. if( !Asset::RegisterObject( pTemplate ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "AssetType::Initialize(): Failed to register type \"%s\" template object.\n" ), *name ); return NULL; } // Set up the template object name, and set this object as its parent. Asset::RenameParameters nameParameters; nameParameters.name = name; nameParameters.spOwner = pTypePackage; if( !pTemplate->Rename( nameParameters ) ) { HELIUM_TRACE( TraceLevels::Error, TXT( "AssetType::Initialize(): Failed to set type \"%s\" template object name and owner.\n" ), *name ); Asset::UnregisterObject( pTemplate ); return NULL; } // Flag the object as the default template object for the type being created. pTemplate->SetFlags( Asset::FLAG_DEFAULT_TEMPLATE | Asset::FLAG_TRANSIENT | Asset::FLAG_PRELOADED | Asset::FLAG_LINKED | Asset::FLAG_PRECACHED | Asset::FLAG_LOADED); // Create the type object and store its parameters. AssetType* pType = new AssetType; HELIUM_ASSERT( pType ); pType->m_class = pClass; pClass->m_Tag = pType; const_cast< Reflect::MetaClass* >( pType->m_class )->m_Default = pTemplate; const_cast< Reflect::MetaClass* >( pType->m_class )->MetaStruct::m_Default = pTemplate; pType->m_name = name; pType->m_flags = flags; // Lazily initialize the lookup map. Note that this is not inherently thread-safe, but there should always be // at least one type registered before any sub-threads are spawned. if( !sm_pLookupMap ) { sm_pLookupMap = new LookupMap; HELIUM_ASSERT( sm_pLookupMap ); } // Register the type (note that a type with the same name should not already exist in the lookup map). LookupMap::Iterator typeIterator; HELIUM_VERIFY( sm_pLookupMap->Insert( typeIterator, KeyValue< Name, AssetTypePtr >( pType->GetName(), pType ) ) ); return pType; }