18bf80f4bSopenharmony_ci/* 28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License. 58bf80f4bSopenharmony_ci * You may obtain a copy of the License at 68bf80f4bSopenharmony_ci * 78bf80f4bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88bf80f4bSopenharmony_ci * 98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and 138bf80f4bSopenharmony_ci * limitations under the License. 148bf80f4bSopenharmony_ci */ 158bf80f4bSopenharmony_ci 168bf80f4bSopenharmony_ci#include "asset_manager.h" 178bf80f4bSopenharmony_ci 188bf80f4bSopenharmony_ci#include <core/intf_engine.h> 198bf80f4bSopenharmony_ci#include <core/io/intf_file_manager.h> 208bf80f4bSopenharmony_ci#include <core/log.h> 218bf80f4bSopenharmony_ci#include <render/intf_render_context.h> 228bf80f4bSopenharmony_ci 238bf80f4bSopenharmony_ci#include "asset_loader.h" 248bf80f4bSopenharmony_ci#include "entity_collection.h" 258bf80f4bSopenharmony_ci#include "json.h" 268bf80f4bSopenharmony_ci 278bf80f4bSopenharmony_ciusing namespace BASE_NS; 288bf80f4bSopenharmony_ciusing namespace CORE_NS; 298bf80f4bSopenharmony_ciusing namespace RENDER_NS; 308bf80f4bSopenharmony_ciusing namespace CORE3D_NS; 318bf80f4bSopenharmony_ci 328bf80f4bSopenharmony_ciSCENE_BEGIN_NAMESPACE() 338bf80f4bSopenharmony_ci 348bf80f4bSopenharmony_ciAssetManager::AssetManager(IRenderContext& renderContext, IGraphicsContext& graphicsContext) 358bf80f4bSopenharmony_ci : renderContext_(renderContext), graphicsContext_(graphicsContext), ecsSerializer_(renderContext_) 368bf80f4bSopenharmony_ci{ 378bf80f4bSopenharmony_ci ecsSerializer_.SetDefaultSerializers(); 388bf80f4bSopenharmony_ci ecsSerializer_.SetListener(this); 398bf80f4bSopenharmony_ci} 408bf80f4bSopenharmony_ci 418bf80f4bSopenharmony_ciAssetManager::~AssetManager() {} 428bf80f4bSopenharmony_ci 438bf80f4bSopenharmony_ciAssetManager::ExtensionType AssetManager::GetExtensionType(string_view ext) const 448bf80f4bSopenharmony_ci{ 458bf80f4bSopenharmony_ci // Ignore case. 468bf80f4bSopenharmony_ci // Better type recognition 478bf80f4bSopenharmony_ci if (ext == "collection") { 488bf80f4bSopenharmony_ci return ExtensionType::COLLECTION; 498bf80f4bSopenharmony_ci } else if (ext == "scene") { 508bf80f4bSopenharmony_ci return ExtensionType::SCENE; 518bf80f4bSopenharmony_ci } else if (ext == "animation") { 528bf80f4bSopenharmony_ci return ExtensionType::ANIMATION; 538bf80f4bSopenharmony_ci } else if (ext == "material") { 548bf80f4bSopenharmony_ci return ExtensionType::MATERIAL; 558bf80f4bSopenharmony_ci } else if (ext == "gltf") { 568bf80f4bSopenharmony_ci return ExtensionType::GLTF; 578bf80f4bSopenharmony_ci } else if (ext == "glb") { 588bf80f4bSopenharmony_ci return ExtensionType::GLB; 598bf80f4bSopenharmony_ci } else if (ext == "png") { 608bf80f4bSopenharmony_ci return ExtensionType::PNG; 618bf80f4bSopenharmony_ci } else if (ext == "jpg" || ext == "jpeg") { 628bf80f4bSopenharmony_ci return ExtensionType::JPG; 638bf80f4bSopenharmony_ci } else if (ext == "ktx") { 648bf80f4bSopenharmony_ci return ExtensionType::KTX; 658bf80f4bSopenharmony_ci } else { 668bf80f4bSopenharmony_ci return ExtensionType::NOT_SUPPORTED; 678bf80f4bSopenharmony_ci } 688bf80f4bSopenharmony_ci} 698bf80f4bSopenharmony_ci 708bf80f4bSopenharmony_ciIAssetLoader::Ptr AssetManager::CreateAssetLoader(IEntityCollection& ec, string_view src, string_view contextUri) 718bf80f4bSopenharmony_ci{ 728bf80f4bSopenharmony_ci return SCENE_NS::CreateAssetLoader(*this, renderContext_, graphicsContext_, ec, src, contextUri); 738bf80f4bSopenharmony_ci} 748bf80f4bSopenharmony_ci 758bf80f4bSopenharmony_cibool AssetManager::LoadAsset(IEntityCollection& ec, string_view uri, string_view contextUri) 768bf80f4bSopenharmony_ci{ 778bf80f4bSopenharmony_ci auto assetLoader = CreateAssetLoader(ec, uri, contextUri); 788bf80f4bSopenharmony_ci if (assetLoader) { 798bf80f4bSopenharmony_ci // Use syncronous asset loading. 808bf80f4bSopenharmony_ci assetLoader->LoadAsset(); 818bf80f4bSopenharmony_ci auto result = assetLoader->GetResult(); 828bf80f4bSopenharmony_ci return result.success; 838bf80f4bSopenharmony_ci } 848bf80f4bSopenharmony_ci return false; 858bf80f4bSopenharmony_ci} 868bf80f4bSopenharmony_ci 878bf80f4bSopenharmony_cibool SaveTextFile(string_view fileUri, string_view fileContents, CORE_NS::IFileManager& fileManager) 888bf80f4bSopenharmony_ci{ 898bf80f4bSopenharmony_ci // TODO: the safest way to save files would be to save to a temp file and rename. 908bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG("Save file: '%s'", string(fileUri).c_str()); 918bf80f4bSopenharmony_ci auto file = fileManager.CreateFile(fileUri); 928bf80f4bSopenharmony_ci if (file) { 938bf80f4bSopenharmony_ci file->Write(fileContents.data(), fileContents.length()); 948bf80f4bSopenharmony_ci file->Close(); 958bf80f4bSopenharmony_ci return true; 968bf80f4bSopenharmony_ci } 978bf80f4bSopenharmony_ci 988bf80f4bSopenharmony_ci return false; 998bf80f4bSopenharmony_ci} 1008bf80f4bSopenharmony_ci 1018bf80f4bSopenharmony_cibool AssetManager::SaveJsonEntityCollection(const IEntityCollection& ec, string_view uri, string_view contextUri) const 1028bf80f4bSopenharmony_ci{ 1038bf80f4bSopenharmony_ci const auto resolvedUri = PathUtil::ResolveUri(contextUri, uri); 1048bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG("SaveJsonEntityCollection: '%s'", resolvedUri.c_str()); 1058bf80f4bSopenharmony_ci 1068bf80f4bSopenharmony_ci json::standalone_value jsonOut; 1078bf80f4bSopenharmony_ci auto result = ecsSerializer_.WriteEntityCollection(ec, jsonOut); 1088bf80f4bSopenharmony_ci if (result) { 1098bf80f4bSopenharmony_ci const string jsonString = CORE_NS::to_formatted_string(jsonOut, 4); 1108bf80f4bSopenharmony_ci if (SaveTextFile( 1118bf80f4bSopenharmony_ci resolvedUri, { jsonString.data(), jsonString.size() }, renderContext_.GetEngine().GetFileManager())) { 1128bf80f4bSopenharmony_ci return true; 1138bf80f4bSopenharmony_ci } 1148bf80f4bSopenharmony_ci } 1158bf80f4bSopenharmony_ci return false; 1168bf80f4bSopenharmony_ci} 1178bf80f4bSopenharmony_ci 1188bf80f4bSopenharmony_ciIEntityCollection* AssetManager::LoadAssetToCache( 1198bf80f4bSopenharmony_ci IEcs& ecs, string_view cacheUri, string_view uri, string_view contextUri, bool active, bool forceReload) 1208bf80f4bSopenharmony_ci{ 1218bf80f4bSopenharmony_ci // Check if this collection was already loaded. 1228bf80f4bSopenharmony_ci const auto resolvedUri = PathUtil::ResolveUri(contextUri, uri); 1238bf80f4bSopenharmony_ci const auto& cacheId = cacheUri; 1248bf80f4bSopenharmony_ci 1258bf80f4bSopenharmony_ci if (!forceReload) { 1268bf80f4bSopenharmony_ci auto it = cacheCollections_.find(cacheId); 1278bf80f4bSopenharmony_ci if (it != cacheCollections_.cend()) { 1288bf80f4bSopenharmony_ci return it->second.get(); 1298bf80f4bSopenharmony_ci } 1308bf80f4bSopenharmony_ci } 1318bf80f4bSopenharmony_ci 1328bf80f4bSopenharmony_ci // Need to first remove the possible cached collection because otherwise gltf importer will not reload the resources 1338bf80f4bSopenharmony_ci // like meshes if they have the same names. 1348bf80f4bSopenharmony_ci cacheCollections_.erase(cacheId); 1358bf80f4bSopenharmony_ci 1368bf80f4bSopenharmony_ci // Load the entity collection. 1378bf80f4bSopenharmony_ci 1388bf80f4bSopenharmony_ci auto ec = EntityCollection::Ptr { new EntityCollection(ecs, uri, contextUri) }; 1398bf80f4bSopenharmony_ci if (LoadAsset(*ec, uri, contextUri)) { 1408bf80f4bSopenharmony_ci // Something was loaded. Set all loaded entities as inactive if requested. 1418bf80f4bSopenharmony_ci if (!active) { 1428bf80f4bSopenharmony_ci ec->SetActive(false); 1438bf80f4bSopenharmony_ci } 1448bf80f4bSopenharmony_ci // Add loaded collection to cache map. 1458bf80f4bSopenharmony_ci return (cacheCollections_[cacheId] = move(ec)).get(); 1468bf80f4bSopenharmony_ci } else { 1478bf80f4bSopenharmony_ci return nullptr; 1488bf80f4bSopenharmony_ci } 1498bf80f4bSopenharmony_ci} 1508bf80f4bSopenharmony_ci 1518bf80f4bSopenharmony_cibool AssetManager::IsCachedCollection(string_view uri, string_view contextUri) const 1528bf80f4bSopenharmony_ci{ 1538bf80f4bSopenharmony_ci const auto resolvedUri = PathUtil::ResolveUri(contextUri, uri); 1548bf80f4bSopenharmony_ci const auto& cacheId = resolvedUri; 1558bf80f4bSopenharmony_ci 1568bf80f4bSopenharmony_ci return cacheCollections_.find(cacheId) != cacheCollections_.cend(); 1578bf80f4bSopenharmony_ci} 1588bf80f4bSopenharmony_ci 1598bf80f4bSopenharmony_ciIEntityCollection* AssetManager::CreateCachedCollection( 1608bf80f4bSopenharmony_ci IEcs& ecs, BASE_NS::string_view uri, BASE_NS::string_view contextUri) 1618bf80f4bSopenharmony_ci{ 1628bf80f4bSopenharmony_ci auto ec = EntityCollection::Ptr { new EntityCollection(ecs, uri, contextUri) }; 1638bf80f4bSopenharmony_ci ec->SetActive(false); 1648bf80f4bSopenharmony_ci 1658bf80f4bSopenharmony_ci const auto resolvedUri = PathUtil::ResolveUri(contextUri, uri); 1668bf80f4bSopenharmony_ci const auto& cacheId = resolvedUri; 1678bf80f4bSopenharmony_ci 1688bf80f4bSopenharmony_ci // Add the created collection to the cache map. 1698bf80f4bSopenharmony_ci return (cacheCollections_[cacheId] = move(ec)).get(); 1708bf80f4bSopenharmony_ci} 1718bf80f4bSopenharmony_ci 1728bf80f4bSopenharmony_ciIEntityCollection* AssetManager::GetCachedCollection(string_view uri, string_view contextUri) const 1738bf80f4bSopenharmony_ci{ 1748bf80f4bSopenharmony_ci const auto resolvedUri = PathUtil::ResolveUri(contextUri, uri); 1758bf80f4bSopenharmony_ci const auto& cacheId = resolvedUri; 1768bf80f4bSopenharmony_ci 1778bf80f4bSopenharmony_ci auto collection = cacheCollections_.find(cacheId); 1788bf80f4bSopenharmony_ci return collection != cacheCollections_.cend() ? collection->second.get() : nullptr; 1798bf80f4bSopenharmony_ci} 1808bf80f4bSopenharmony_ci 1818bf80f4bSopenharmony_civoid AssetManager::RemoveFromCache(string_view uri, string_view contextUri) 1828bf80f4bSopenharmony_ci{ 1838bf80f4bSopenharmony_ci const auto resolvedUri = PathUtil::ResolveUri(contextUri, uri); 1848bf80f4bSopenharmony_ci const auto& cacheId = resolvedUri; 1858bf80f4bSopenharmony_ci 1868bf80f4bSopenharmony_ci cacheCollections_.erase(cacheId); 1878bf80f4bSopenharmony_ci} 1888bf80f4bSopenharmony_ci 1898bf80f4bSopenharmony_civoid AssetManager::ClearCache() 1908bf80f4bSopenharmony_ci{ 1918bf80f4bSopenharmony_ci // NOTE: not removing any active collections. 1928bf80f4bSopenharmony_ci for (auto it = cacheCollections_.begin(); it != cacheCollections_.end();) { 1938bf80f4bSopenharmony_ci if (!it->second->IsActive()) { 1948bf80f4bSopenharmony_ci it = cacheCollections_.erase(it); 1958bf80f4bSopenharmony_ci } else { 1968bf80f4bSopenharmony_ci ++it; 1978bf80f4bSopenharmony_ci } 1988bf80f4bSopenharmony_ci } 1998bf80f4bSopenharmony_ci} 2008bf80f4bSopenharmony_ci 2018bf80f4bSopenharmony_civoid AssetManager::RefreshAsset(IEntityCollection& ec, bool active) 2028bf80f4bSopenharmony_ci{ 2038bf80f4bSopenharmony_ci json::standalone_value json; 2048bf80f4bSopenharmony_ci if (!ecsSerializer_.WriteEntityCollection(ec, json)) { 2058bf80f4bSopenharmony_ci return; 2068bf80f4bSopenharmony_ci } 2078bf80f4bSopenharmony_ci 2088bf80f4bSopenharmony_ci if (json) { 2098bf80f4bSopenharmony_ci ec.Clear(); 2108bf80f4bSopenharmony_ci // Set the active state when the collection empty to not iterate all the contents. 2118bf80f4bSopenharmony_ci ec.SetActive(active); 2128bf80f4bSopenharmony_ci // NOTE: This does conversion from standalone json to read only json. 2138bf80f4bSopenharmony_ci ecsSerializer_.ReadEntityCollection(ec, json, ec.GetContextUri()); 2148bf80f4bSopenharmony_ci } 2158bf80f4bSopenharmony_ci} 2168bf80f4bSopenharmony_ci 2178bf80f4bSopenharmony_ciIEntityCollection* AssetManager::InstantiateCollection(IEntityCollection& ec, string_view uri, string_view contextUri) 2188bf80f4bSopenharmony_ci{ 2198bf80f4bSopenharmony_ci#ifdef VERBOSE_LOGGING 2208bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG( 2218bf80f4bSopenharmony_ci "InstantiateCollection: uri='%s' context='%s'", string(uri).c_str(), string(contextUri).c_str()); 2228bf80f4bSopenharmony_ci#endif 2238bf80f4bSopenharmony_ci auto& ecs = ec.GetEcs(); 2248bf80f4bSopenharmony_ci auto externalCollection = LoadAssetToCache(ecs, uri, uri, contextUri, false, false); 2258bf80f4bSopenharmony_ci if (externalCollection) { 2268bf80f4bSopenharmony_ci auto& newCollection = ec.AddSubCollectionClone(*externalCollection, {}); 2278bf80f4bSopenharmony_ci newCollection.SetSrc(uri); 2288bf80f4bSopenharmony_ci newCollection.MarkModified(false); 2298bf80f4bSopenharmony_ci return &newCollection; 2308bf80f4bSopenharmony_ci } 2318bf80f4bSopenharmony_ci 2328bf80f4bSopenharmony_ci CORE_LOG_E("Loading collection failed: '%s'", string(uri).c_str()); 2338bf80f4bSopenharmony_ci return nullptr; 2348bf80f4bSopenharmony_ci} 2358bf80f4bSopenharmony_ci 2368bf80f4bSopenharmony_ciIEcsSerializer& AssetManager::GetEcsSerializer() 2378bf80f4bSopenharmony_ci{ 2388bf80f4bSopenharmony_ci return ecsSerializer_; 2398bf80f4bSopenharmony_ci} 2408bf80f4bSopenharmony_ci 2418bf80f4bSopenharmony_ciIEntityCollection* AssetManager::GetExternalCollection(IEcs& ecs, string_view uri, string_view contextUri) 2428bf80f4bSopenharmony_ci{ 2438bf80f4bSopenharmony_ci // NOTE: Does not automatically try to load external dependencies. 2448bf80f4bSopenharmony_ci return GetCachedCollection(uri, contextUri); 2458bf80f4bSopenharmony_ci} 2468bf80f4bSopenharmony_ci 2478bf80f4bSopenharmony_civoid AssetManager::Destroy() 2488bf80f4bSopenharmony_ci{ 2498bf80f4bSopenharmony_ci delete this; 2508bf80f4bSopenharmony_ci} 2518bf80f4bSopenharmony_ci 2528bf80f4bSopenharmony_ciSCENE_END_NAMESPACE() 253