From 696de0326d19d8dde3fb19a31b85385d5679552c Mon Sep 17 00:00:00 2001 From: Nomango Date: Sun, 26 Jul 2020 11:51:27 +0800 Subject: [PATCH] add ResourceLoader --- projects/kiwano/kiwano.vcxproj | 2 + projects/kiwano/kiwano.vcxproj.filters | 6 + src/kiwano/base/ObjectBase.cpp | 2 +- src/kiwano/base/ObjectBase.h | 8 + src/kiwano/kiwano.h | 1 + src/kiwano/platform/Application.cpp | 2 - src/kiwano/render/DirectX/RendererImpl.cpp | 11 +- src/kiwano/utils/ResourceCache.cpp | 413 +------------------ src/kiwano/utils/ResourceCache.h | 36 +- src/kiwano/utils/ResourceLoader.cpp | 452 +++++++++++++++++++++ src/kiwano/utils/ResourceLoader.h | 55 +++ 11 files changed, 542 insertions(+), 446 deletions(-) create mode 100644 src/kiwano/utils/ResourceLoader.cpp create mode 100644 src/kiwano/utils/ResourceLoader.h diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index fb5ae081..dcb0634a 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -102,6 +102,7 @@ + @@ -179,6 +180,7 @@ + diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index b8ecfc9d..eaef9e8b 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -354,6 +354,9 @@ base + + utils + @@ -578,6 +581,9 @@ base + + utils + diff --git a/src/kiwano/base/ObjectBase.cpp b/src/kiwano/base/ObjectBase.cpp index 90fc2032..b0b3e1c4 100644 --- a/src/kiwano/base/ObjectBase.cpp +++ b/src/kiwano/base/ObjectBase.cpp @@ -183,7 +183,7 @@ void ObjectBase::SetStatus(const ObjectStatus& status) void ObjectBase::Fail(const String& msg, int code) { - SetStatus(ObjectStatus{ code, msg }); + SetStatus(ObjectStatus(code, msg)); } void ObjectBase::ClearStatus() diff --git a/src/kiwano/base/ObjectBase.h b/src/kiwano/base/ObjectBase.h index c73f1205..9705bebf 100644 --- a/src/kiwano/base/ObjectBase.h +++ b/src/kiwano/base/ObjectBase.h @@ -39,6 +39,14 @@ struct ObjectStatus int code = 0; ///< 状态码,等于 0 时为成功状态,否则为失败状态 String msg; ///< 状态信息 + ObjectStatus() = default; + + ObjectStatus(int code, const String& msg) + : code(code) + , msg(msg) + { + } + /// \~chinese /// @brief 对象状态是否成功 inline bool Success() const diff --git a/src/kiwano/kiwano.h b/src/kiwano/kiwano.h index 17a57ea7..a01e941f 100644 --- a/src/kiwano/kiwano.h +++ b/src/kiwano/kiwano.h @@ -128,6 +128,7 @@ #include #include +#include #include #include #include diff --git a/src/kiwano/platform/Application.cpp b/src/kiwano/platform/Application.cpp index 9e643004..3b50e79f 100644 --- a/src/kiwano/platform/Application.cpp +++ b/src/kiwano/platform/Application.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include namespace kiwano @@ -122,7 +121,6 @@ void Application::Destroy() // Clear user resources Director::GetInstance().ClearStages(); - ResourceCache::GetInstance().Clear(); for (auto iter = modules_.rbegin(); iter != modules_.rend(); ++iter) { diff --git a/src/kiwano/render/DirectX/RendererImpl.cpp b/src/kiwano/render/DirectX/RendererImpl.cpp index 7a9eb429..f11e17f7 100644 --- a/src/kiwano/render/DirectX/RendererImpl.cpp +++ b/src/kiwano/render/DirectX/RendererImpl.cpp @@ -168,8 +168,10 @@ void RendererImpl::CreateTexture(Texture& texture, const String& file_path) if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_WARNF("Texture file '%s' not found!", file_path.c_str()); hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + KGE_SET_STATUS_IF_FAILED(hr, texture, + strings::Format("Texture file '%s' not found!", file_path.c_str()).c_str()); + return; } if (SUCCEEDED(hr)) @@ -273,8 +275,10 @@ void RendererImpl::CreateGifImage(GifImage& gif, const String& file_path) if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_WARNF("Gif texture file '%s' not found!", file_path.c_str()); hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + KGE_SET_STATUS_IF_FAILED(hr, gif, + strings::Format("Gif texture file '%s' not found!", file_path.c_str()).c_str()); + return; } if (SUCCEEDED(hr)) @@ -495,8 +499,9 @@ void RendererImpl::CreateFontCollection(Font& font, const String& file_path) { if (!FileSystem::GetInstance().IsFileExists(file_path)) { - KGE_WARNF("Font file '%s' not found!", file_path.c_str()); hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + KGE_SET_STATUS_IF_FAILED(hr, font, strings::Format("Font file '%s' not found!", file_path.c_str()).c_str()); + return; } } diff --git a/src/kiwano/utils/ResourceCache.cpp b/src/kiwano/utils/ResourceCache.cpp index 30728cdb..4ea7c3c3 100644 --- a/src/kiwano/utils/ResourceCache.cpp +++ b/src/kiwano/utils/ResourceCache.cpp @@ -18,35 +18,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include -#include -#include #include namespace kiwano { -namespace resource_cache_01 -{ - -bool LoadJsonData(ResourceCache* loader, const Json& json_data); -bool LoadXmlData(ResourceCache* loader, const XmlNode& elem); - -} // namespace resource_cache_01 - -namespace -{ - -Map> load_json_funcs = { - { "latest", resource_cache_01::LoadJsonData }, - { "0.1", resource_cache_01::LoadJsonData }, -}; - -Map> load_xml_funcs = { - { "latest", resource_cache_01::LoadXmlData }, - { "0.1", resource_cache_01::LoadXmlData }, -}; - -} // namespace ResourceCache::ResourceCache() {} @@ -55,124 +30,9 @@ ResourceCache::~ResourceCache() Clear(); } -bool ResourceCache::LoadFromJsonFile(const String& file_path) +void ResourceCache::AddObject(const String& id, ObjectBasePtr obj) { - if (!FileSystem::GetInstance().IsFileExists(file_path)) - { - KGE_ERRORF("%s failed: File not found.", __FUNCTION__); - return false; - } - - Json json_data; - - std::ifstream ifs; - ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); - - try - { - String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path); - ifs.open(full_path.c_str()); - ifs >> json_data; - ifs.close(); - } - catch (std::ios_base::failure& e) - { - KGE_ERRORF("%s failed: cannot open file. (%s)", __FUNCTION__, e.what()); - return false; - } - catch (Json::exception& e) - { - KGE_ERRORF("%s failed: cannot parse JSON. (%s)", __FUNCTION__, e.what()); - return false; - } - return LoadFromJson(json_data); -} - -bool ResourceCache::LoadFromJson(const Json& json_data) -{ - try - { - String version = json_data["version"]; - - auto load = load_json_funcs.find(version); - if (load != load_json_funcs.end()) - { - return load->second(this, json_data); - } - else if (version.empty()) - { - return load_json_funcs["latest"](this, json_data); - } - else - { - KGE_ERRORF("%s failed: unknown resource data version", __FUNCTION__); - } - } - catch (Json::exception& e) - { - KGE_ERRORF("%s failed: JSON data is invalid. (%s)", __FUNCTION__, e.what()); - return false; - } - return false; -} - -bool ResourceCache::LoadFromXmlFile(const String& file_path) -{ - if (!FileSystem::GetInstance().IsFileExists(file_path)) - { - KGE_ERRORF("%s failed: File not found.", __FUNCTION__); - return false; - } - - String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path); - - XmlDocument doc; - - auto result = doc.load_file(full_path.c_str()); - if (result) - { - return LoadFromXml(doc); - } - else - { - KGE_ERRORF("%s failed: XML [%s] parsed with errors: %s", __FUNCTION__, full_path.c_str(), result.description()); - return false; - } -} - -bool ResourceCache::LoadFromXml(const XmlDocument& doc) -{ - if (XmlNode root = doc.child("resources")) - { - String version; - if (auto version_node = root.child("version")) - version = version_node.child_value(); - - auto load = load_xml_funcs.find(version); - if (load != load_xml_funcs.end()) - { - return load->second(this, root); - } - else if (version.empty()) - { - return load_xml_funcs["latest"](this, root); - } - else - { - KGE_ERRORF("%s failed: unknown resource data version", __FUNCTION__); - } - } - return false; -} - -bool ResourceCache::AddObject(const String& id, ObjectBasePtr obj) -{ - if (obj) - { - object_cache_.insert(std::make_pair(id, obj)); - return true; - } - return false; + object_cache_.insert(std::make_pair(id, obj)); } void ResourceCache::Remove(const String& id) @@ -194,272 +54,3 @@ ObjectBasePtr ResourceCache::Get(const String& id) const } } // namespace kiwano - -namespace kiwano -{ -namespace resource_cache_01 -{ -struct GlobalData -{ - String path; -}; - -bool LoadTexturesFromData(ResourceCache* loader, GlobalData* gdata, const String& id, const String& type, - const String& file) -{ - if (!gdata) - return false; - - if (type == "gif") - { - // GIF image - GifImagePtr gif = MakePtr(); - if (gif && gif->Load(gdata->path + file)) - { - return loader->AddObject(id, gif); - } - } - - if (!file.empty()) - { - // Simple image - FramePtr frame = MakePtr(); - if (frame && frame->Load(gdata->path + file)) - { - return loader->AddObject(id, frame); - } - } - return false; -} - -bool LoadTexturesFromData(ResourceCache* loader, GlobalData* gdata, const String& id, const Vector& files) -{ - if (!gdata) - return false; - - if (files.empty()) - return true; - - // Frames - Vector frames; - frames.reserve(files.size()); - for (const auto& file : files) - { - FramePtr frame = MakePtr(); - if (frame->Load(gdata->path + file)) - { - frames.push_back(frame); - } - } - FrameSequencePtr frame_seq = MakePtr(frames); - if (frame_seq) - { - return !!loader->AddObject(id, frame_seq); - } - return false; -} - -bool LoadTexturesFromData(ResourceCache* loader, GlobalData* gdata, const String& id, const String& file, int rows, - int cols, int max_num, float padding_x, float padding_y) -{ - if (!gdata) - return false; - - if (!file.empty()) - { - if (rows || cols) - { - // Frame slices - FramePtr frame = MakePtr(); - if (frame && frame->Load(gdata->path + file)) - { - FrameSequencePtr frame_seq = MakePtr(); - if (frame_seq) - { - frame_seq->AddFrames(frame, cols, rows, max_num, padding_x, padding_y); - return loader->AddObject(id, frame_seq); - } - } - } - else - { - // Simple image - FramePtr frame = MakePtr(); - if (frame && frame->Load(gdata->path + file)) - { - return loader->AddObject(id, frame); - } - } - } - return false; -} - -bool LoadFontsFromData(ResourceCache* loader, GlobalData* gdata, const String& id, const String& file) -{ - if (!gdata) - return false; - - FontPtr font = MakePtr(); - if (font && font->Load(gdata->path + file)) - { - return loader->AddObject(id, font); - } - return false; -} - -bool LoadJsonData(ResourceCache* loader, const Json& json_data) -{ - GlobalData global_data; - if (json_data.count("path")) - { - global_data.path = json_data["path"].get(); - } - - if (json_data.count("images")) - { - for (const auto& image : json_data["images"]) - { - String id, type, file; - int rows = 0, cols = 0, max_num = -1; - - if (image.count("id")) - id = image["id"].get(); - if (image.count("type")) - type = image["type"].get(); - if (image.count("file")) - file = image["file"].get(); - if (image.count("rows")) - rows = image["rows"].get(); - if (image.count("cols")) - cols = image["cols"].get(); - if (image.count("max_num")) - max_num = image["max_num"].get(); - - if (rows || cols) - { - float padding_x = 0, padding_y = 0; - if (image.count("padding-x")) - padding_x = image["padding-x"].get(); - if (image.count("padding-y")) - padding_y = image["padding-y"].get(); - - if (!LoadTexturesFromData(loader, &global_data, id, file, rows, cols, max_num, padding_x, padding_y)) - return false; - } - - if (image.count("files")) - { - Vector files; - files.reserve(image["files"].size()); - for (const auto& file : image["files"]) - { - files.push_back(file.get()); - } - if (!LoadTexturesFromData(loader, &global_data, id, files)) - return false; - } - else - { - if (!LoadTexturesFromData(loader, &global_data, id, type, file)) - return false; - } - } - } - - if (json_data.count("fonts")) - { - for (const auto& font : json_data["fonts"]) - { - String id, file; - - if (font.count("id")) - id = font["id"].get(); - if (font.count("file")) - file = font["file"].get(); - - if (!LoadFontsFromData(loader, &global_data, id, file)) - return false; - } - } - return true; -} - -bool LoadXmlData(ResourceCache* loader, const XmlNode& elem) -{ - GlobalData global_data; - if (auto path = elem.child("path")) - { - global_data.path = path.child_value(); - } - - if (auto images = elem.child("images")) - { - for (auto image : images.children()) - { - String id, type, file; - int rows = 0, cols = 0, max_num = -1; - - if (auto attr = image.attribute("id")) - id = attr.value(); - if (auto attr = image.attribute("type")) - type = attr.value(); - if (auto attr = image.attribute("file")) - file = attr.value(); - if (auto attr = image.attribute("rows")) - rows = attr.as_int(0); - if (auto attr = image.attribute("cols")) - cols = attr.as_int(0); - if (auto attr = image.attribute("max_num")) - max_num = attr.as_int(-1); - - if (rows || cols) - { - float padding_x = 0, padding_y = 0; - if (auto attr = image.attribute("padding-x")) - padding_x = attr.as_float(0.0f); - if (auto attr = image.attribute("padding-y")) - padding_y = attr.as_float(0.0f); - - if (!LoadTexturesFromData(loader, &global_data, id, file, rows, cols, max_num, padding_x, padding_y)) - return false; - } - - if (file.empty() && !image.empty()) - { - Vector files_arr; - for (auto file : image.children()) - { - if (auto path = file.attribute("path")) - { - files_arr.push_back(path.value()); - } - } - if (!LoadTexturesFromData(loader, &global_data, id, files_arr)) - return false; - } - else - { - if (!LoadTexturesFromData(loader, &global_data, id, type, file)) - return false; - } - } - } - - if (auto fonts = elem.child("fonts")) - { - for (auto font : fonts.children()) - { - String id, file; - if (auto attr = font.attribute("id")) - id = attr.value(); - if (auto attr = font.attribute("file")) - file = attr.value(); - - if (!LoadFontsFromData(loader, &global_data, id, file)) - return false; - } - } - return true; -} -} // namespace resource_cache_01 -} // namespace kiwano diff --git a/src/kiwano/utils/ResourceCache.h b/src/kiwano/utils/ResourceCache.h index feed7bbc..468568a8 100644 --- a/src/kiwano/utils/ResourceCache.h +++ b/src/kiwano/utils/ResourceCache.h @@ -20,8 +20,6 @@ #pragma once #include -#include -#include #include #include #include @@ -29,33 +27,15 @@ namespace kiwano { + +KGE_DECLARE_SMART_PTR(ResourceCache); + /// \~chinese /// @brief 资源缓存 -/// @details 资源缓存 -class KGE_API ResourceCache final : public Singleton +class KGE_API ResourceCache final : public ObjectBase { - friend Singleton; - public: - /// \~chinese - /// @brief 从 JSON 文件加载资源信息 - /// @param file_path JSON文件路径 - bool LoadFromJsonFile(const String& file_path); - - /// \~chinese - /// @brief 从 JSON 加载资源信息 - /// @param json_data JSON对象 - bool LoadFromJson(const Json& json_data); - - /// \~chinese - /// @brief 从 XML 文件加载资源信息 - /// @param file_path XML文件路径 - bool LoadFromXmlFile(const String& file_path); - - /// \~chinese - /// @brief 从 XML 文档对象加载资源信息 - /// @param doc XML文档对象 - bool LoadFromXml(const XmlDocument& doc); + ResourceCache(); /// \~chinese /// @brief 获取资源 @@ -77,7 +57,7 @@ public: /// @brief 将对象放入缓存 /// @param id 对象ID /// @param obj 对象 - bool AddObject(const String& id, ObjectBasePtr obj); + void AddObject(const String& id, ObjectBasePtr obj); /// \~chinese /// @brief 删除指定资源 @@ -90,10 +70,8 @@ public: virtual ~ResourceCache(); -private: - ResourceCache(); - private: UnorderedMap object_cache_; }; + } // namespace kiwano diff --git a/src/kiwano/utils/ResourceLoader.cpp b/src/kiwano/utils/ResourceLoader.cpp new file mode 100644 index 00000000..125882e3 --- /dev/null +++ b/src/kiwano/utils/ResourceLoader.cpp @@ -0,0 +1,452 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include +#include +#include + +namespace kiwano +{ +namespace resource_cache_01 +{ + +void LoadJsonData(ResourceCache* cache, const Json& json_data); +void LoadXmlData(ResourceCache* cache, const XmlNode& elem); + +} // namespace resource_cache_01 + +namespace +{ + +Map> load_json_funcs = { + { "latest", resource_cache_01::LoadJsonData }, + { "0.1", resource_cache_01::LoadJsonData }, +}; + +Map> load_xml_funcs = { + { "latest", resource_cache_01::LoadXmlData }, + { "0.1", resource_cache_01::LoadXmlData }, +}; + +} // namespace + +bool ResourceLoader::LoadFromJsonFile(ResourceCachePtr cache, const String& file_path) +{ + if (!cache) + { + KGE_ERROR("ResourceLoader::LoadFromJsonFile failed, cache is nullptr"); + return false; + } + + if (!FileSystem::GetInstance().IsFileExists(file_path)) + { + cache->Fail( + strings::Format("ResourceLoader::LoadFromJsonFile failed: [%s] file not found.", file_path.c_str())); + return false; + } + + Json json_data; + + std::ifstream ifs; + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + try + { + String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path); + ifs.open(full_path.c_str()); + ifs >> json_data; + ifs.close(); + } + catch (std::ios_base::failure& e) + { + cache->Fail(strings::Format("ResourceLoader::LoadFromJsonFile failed: cannot open file [%s]. %s", + file_path.c_str(), e.what())); + return false; + } + catch (Json::exception& e) + { + cache->Fail(strings::Format("ResourceLoader::LoadFromJsonFile failed: Json file [%s] parsed with errors: %s", + file_path.c_str(), e.what())); + return false; + } + return LoadFromJson(cache, json_data); +} + +bool ResourceLoader::LoadFromJson(ResourceCachePtr cache, const Json& json_data) +{ + if (!cache) + { + KGE_ERROR("ResourceLoader::LoadFromJson failed, cache is nullptr"); + return false; + } + + try + { + String version = json_data["version"]; + + auto load = load_json_funcs.find(version); + if (load != load_json_funcs.end()) + { + load->second(cache.Get(), json_data); + } + else if (version.empty()) + { + load_json_funcs["latest"](cache.Get(), json_data); + } + else + { + cache->Fail("ResourceLoader::LoadFromJson failed: unknown resource data version"); + } + } + catch (Json::exception& e) + { + cache->Fail(String("ResourceLoader::LoadFromJson failed: ") + e.what()); + } + return cache->IsValid(); +} + +bool ResourceLoader::LoadFromXmlFile(ResourceCachePtr cache, const String& file_path) +{ + if (!cache) + { + KGE_ERROR("ResourceLoader::LoadFromXmlFile failed, cache is nullptr"); + return false; + } + + if (!FileSystem::GetInstance().IsFileExists(file_path)) + { + cache->Fail(strings::Format("ResourceLoader::LoadFromXmlFile failed: [%s] file not found.", file_path.c_str())); + return false; + } + + String full_path = FileSystem::GetInstance().GetFullPathForFile(file_path); + + XmlDocument doc; + + auto result = doc.load_file(full_path.c_str()); + if (result) + { + return LoadFromXml(cache, doc); + } + else + { + cache->Fail(strings::Format("ResourceLoader::LoadFromXmlFile failed: XML file [%s] parsed with errors: %s", + file_path.c_str(), result.description())); + return false; + } +} + +bool ResourceLoader::LoadFromXml(ResourceCachePtr cache, const XmlDocument& doc) +{ + if (!cache) + { + KGE_ERROR("ResourceLoader::LoadFromXml failed, cache is nullptr"); + return false; + } + + if (XmlNode root = doc.child("resources")) + { + String version; + if (auto version_node = root.child("version")) + version = version_node.child_value(); + + auto load = load_xml_funcs.find(version); + if (load != load_xml_funcs.end()) + { + load->second(cache.Get(), root); + } + else if (version.empty()) + { + load_xml_funcs["latest"](cache.Get(), root); + } + else + { + cache->Fail("ResourceLoader::LoadFromXml failed: unknown resource data version"); + } + } + else + { + cache->Fail("ResourceLoader::LoadFromXml failed: unknown file format"); + } + return cache->IsValid(); +} + +} // namespace kiwano + +namespace kiwano +{ +namespace resource_cache_01 +{ +struct GlobalData +{ + String path; +}; + +void LoadTexturesFromData(ResourceCache* cache, GlobalData* gdata, const String& id, const String& type, + const String& file) +{ + if (type == "gif") + { + // GIF image + GifImagePtr gif = MakePtr(); + if (gif && gif->Load(gdata->path + file)) + { + cache->AddObject(id, gif); + return; + } + } + else if (!file.empty()) + { + // Simple image + FramePtr frame = MakePtr(); + if (frame && frame->Load(gdata->path + file)) + { + cache->AddObject(id, frame); + return; + } + } + + cache->Fail(strings::Format("%s failed", __FUNCTION__)); +} + +void LoadTexturesFromData(ResourceCache* cache, GlobalData* gdata, const String& id, const Vector& files) +{ + if (files.empty()) + return; + + // Frames + Vector frames; + frames.reserve(files.size()); + for (const auto& file : files) + { + FramePtr frame = MakePtr(); + if (frame->Load(gdata->path + file)) + { + frames.push_back(frame); + } + } + + if (!frames.empty()) + { + FrameSequencePtr frame_seq = MakePtr(frames); + if (frame_seq) + { + cache->AddObject(id, frame_seq); + return; + } + } + + cache->Fail(strings::Format("%s failed", __FUNCTION__)); +} + +void LoadTexturesFromData(ResourceCache* cache, GlobalData* gdata, const String& id, const String& file, int rows, + int cols, int max_num, float padding_x, float padding_y) +{ + if (!file.empty()) + { + if (rows || cols) + { + // Frame slices + FramePtr frame = MakePtr(); + if (frame && frame->Load(gdata->path + file)) + { + FrameSequencePtr frame_seq = MakePtr(); + if (frame_seq) + { + frame_seq->AddFrames(frame, cols, rows, max_num, padding_x, padding_y); + cache->AddObject(id, frame_seq); + return; + } + } + } + else + { + // Simple image + FramePtr frame = MakePtr(); + if (frame && frame->Load(gdata->path + file)) + { + cache->AddObject(id, frame); + return; + } + } + } + + cache->Fail(strings::Format("%s failed", __FUNCTION__)); +} + +void LoadFontsFromData(ResourceCache* cache, GlobalData* gdata, const String& id, const String& file) +{ + FontPtr font = MakePtr(); + if (font && font->Load(gdata->path + file)) + { + cache->AddObject(id, font); + return; + } + cache->Fail(strings::Format("%s failed", __FUNCTION__)); +} + +void LoadJsonData(ResourceCache* cache, const Json& json_data) +{ + GlobalData global_data; + if (json_data.count("path")) + { + global_data.path = json_data["path"].get(); + } + + if (json_data.count("images")) + { + for (const auto& image : json_data["images"]) + { + String id, type, file; + int rows = 0, cols = 0, max_num = -1; + + if (image.count("id")) + id = image["id"].get(); + if (image.count("type")) + type = image["type"].get(); + if (image.count("file")) + file = image["file"].get(); + if (image.count("rows")) + rows = image["rows"].get(); + if (image.count("cols")) + cols = image["cols"].get(); + if (image.count("max_num")) + max_num = image["max_num"].get(); + + if (rows || cols) + { + float padding_x = 0, padding_y = 0; + if (image.count("padding-x")) + padding_x = image["padding-x"].get(); + if (image.count("padding-y")) + padding_y = image["padding-y"].get(); + + LoadTexturesFromData(cache, &global_data, id, file, rows, cols, max_num, padding_x, padding_y); + } + + if (image.count("files")) + { + Vector files; + files.reserve(image["files"].size()); + for (const auto& file : image["files"]) + { + files.push_back(file.get()); + } + LoadTexturesFromData(cache, &global_data, id, files); + } + else + { + LoadTexturesFromData(cache, &global_data, id, type, file); + } + } + } + + if (json_data.count("fonts")) + { + for (const auto& font : json_data["fonts"]) + { + String id, file; + + if (font.count("id")) + id = font["id"].get(); + if (font.count("file")) + file = font["file"].get(); + + LoadFontsFromData(cache, &global_data, id, file); + } + } +} + +void LoadXmlData(ResourceCache* cache, const XmlNode& elem) +{ + GlobalData global_data; + if (auto path = elem.child("path")) + { + global_data.path = path.child_value(); + } + + if (auto images = elem.child("images")) + { + for (auto image : images.children()) + { + String id, type, file; + int rows = 0, cols = 0, max_num = -1; + + if (auto attr = image.attribute("id")) + id = attr.value(); + if (auto attr = image.attribute("type")) + type = attr.value(); + if (auto attr = image.attribute("file")) + file = attr.value(); + if (auto attr = image.attribute("rows")) + rows = attr.as_int(0); + if (auto attr = image.attribute("cols")) + cols = attr.as_int(0); + if (auto attr = image.attribute("max_num")) + max_num = attr.as_int(-1); + + if (rows || cols) + { + float padding_x = 0, padding_y = 0; + if (auto attr = image.attribute("padding-x")) + padding_x = attr.as_float(0.0f); + if (auto attr = image.attribute("padding-y")) + padding_y = attr.as_float(0.0f); + + LoadTexturesFromData(cache, &global_data, id, file, rows, cols, max_num, padding_x, padding_y); + } + + if (file.empty() && !image.empty()) + { + Vector files_arr; + for (auto file : image.children()) + { + if (auto path = file.attribute("path")) + { + files_arr.push_back(path.value()); + } + } + LoadTexturesFromData(cache, &global_data, id, files_arr); + } + else + { + LoadTexturesFromData(cache, &global_data, id, type, file); + } + } + } + + if (auto fonts = elem.child("fonts")) + { + for (auto font : fonts.children()) + { + String id, file; + if (auto attr = font.attribute("id")) + id = attr.value(); + if (auto attr = font.attribute("file")) + file = attr.value(); + + LoadFontsFromData(cache, &global_data, id, file); + } + } +} + +} // namespace resource_cache_01 +} // namespace kiwano diff --git a/src/kiwano/utils/ResourceLoader.h b/src/kiwano/utils/ResourceLoader.h new file mode 100644 index 00000000..7f701e87 --- /dev/null +++ b/src/kiwano/utils/ResourceLoader.h @@ -0,0 +1,55 @@ +// Copyright (c) 2016-2018 Kiwano - Nomango +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include +#include +#include + +namespace kiwano +{ + +/// \~chinese +/// @brief 资源加载器 +class KGE_API ResourceLoader final : Noncopyable +{ +public: + /// \~chinese + /// @brief 从 JSON 文件加载资源信息 + /// @param file_path JSON文件路径 + static bool LoadFromJsonFile(ResourceCachePtr cache, const String& file_path); + + /// \~chinese + /// @brief 从 JSON 加载资源信息 + /// @param json_data JSON对象 + static bool LoadFromJson(ResourceCachePtr cache, const Json& json_data); + + /// \~chinese + /// @brief 从 XML 文件加载资源信息 + /// @param file_path XML文件路径 + static bool LoadFromXmlFile(ResourceCachePtr cache, const String& file_path); + + /// \~chinese + /// @brief 从 XML 文档对象加载资源信息 + /// @param doc XML文档对象 + static bool LoadFromXml(ResourceCachePtr cache, const XmlDocument& doc); +}; + +} // namespace kiwano