add tinyxml2 to parse XML resources file

minor
This commit is contained in:
Nomango 2019-08-04 00:11:47 +08:00 committed by Nomango
parent bda157c38a
commit cefabe71ff
13 changed files with 5394 additions and 70 deletions

View File

@ -74,6 +74,7 @@
<ClInclude Include="renderer\render.h" />
<ClInclude Include="renderer\TextRenderer.h" />
<ClInclude Include="third-party\StackWalker\StackWalker.h" />
<ClInclude Include="third-party\tinyxml2\tinyxml2.h" />
<ClInclude Include="ui\Button.h" />
<ClInclude Include="ui\Menu.h" />
<ClInclude Include="utils\DataUtil.h" />
@ -121,6 +122,7 @@
<ClCompile Include="renderer\render.cpp" />
<ClCompile Include="renderer\TextRenderer.cpp" />
<ClCompile Include="third-party\StackWalker\StackWalker.cpp" />
<ClCompile Include="third-party\tinyxml2\tinyxml2.cpp" />
<ClCompile Include="ui\Button.cpp" />
<ClCompile Include="ui\Menu.cpp" />
<ClCompile Include="utils\DataUtil.cpp" />

View File

@ -31,6 +31,9 @@
<Filter Include="third-party\StackWalker">
<UniqueIdentifier>{1fec4835-63a1-4612-80b5-828dadf0ac63}</UniqueIdentifier>
</Filter>
<Filter Include="third-party\tinyxml2">
<UniqueIdentifier>{0cae76f7-7016-4a45-bb26-a130fbce8024}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ui\Button.h">
@ -264,6 +267,9 @@
<ClInclude Include="common\Array.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="third-party\tinyxml2\tinyxml2.h">
<Filter>third-party\tinyxml2</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ui\Button.cpp">
@ -401,5 +407,8 @@
<ClCompile Include="2d\GifSprite.cpp">
<Filter>2d</Filter>
</ClCompile>
<ClCompile Include="third-party\tinyxml2\tinyxml2.cpp">
<Filter>third-party\tinyxml2</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -134,8 +134,6 @@ namespace kiwano
curr_scene_.Reset();
debug_node_.Reset();
OnDestroy();
if (inited_)
{
inited_ = false;
@ -547,6 +545,8 @@ namespace kiwano
app->Dispatch(evt);
}
app->OnDestroy();
::PostQuitMessage(0);
return 0;
}

18
kiwano/third-party/tinyxml2/LICENSE.txt vendored Normal file
View File

@ -0,0 +1,18 @@
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

2837
kiwano/third-party/tinyxml2/tinyxml2.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

2309
kiwano/third-party/tinyxml2/tinyxml2.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -28,17 +28,60 @@
namespace kiwano
{
namespace __res_loader_09
namespace __res_loader_01
{
struct GlobalData
{
String path;
};
void LoadImageFromData(ResLoader* loader, GlobalData const& global_data, Json const& image_data);
bool CompareJsonWithString(Json const& data, const wchar_t* key, const wchar_t* value);
bool LoadImagesFromData(ResLoader* loader, GlobalData* gdata, const String* id, const String* type,
const String* file, const Array<String>* files, int rows, int cols)
{
if (!gdata || !id) return false;
void LoadJsonData(ResLoader* loader, Json const& json_data)
if (file)
{
// Gif image
if (type && (*type) == L"gif")
{
return loader->AddGifImage(*id, Resource(gdata->path + (*file)));
}
if (!(*file).empty())
{
if (rows || cols)
{
// Image slices
return loader->AddFrames(*id, Resource(gdata->path + (*file)), std::max(cols, 1), std::max(rows, 1));
}
else
{
// Simple image
return loader->AddImage(*id, Resource(gdata->path + (*file)));
}
}
}
// Frames
if (files)
{
Array<ImagePtr> images;
images.reserve(files->size());
for (const auto& file : (*files))
{
ImagePtr image = new Image(gdata->path + (file));
if (image->IsValid())
{
images.push_back(image);
}
}
return !!loader->AddFrames(*id, images);
}
return false;
}
bool LoadJsonData(ResLoader* loader, Json const& json_data)
{
GlobalData global_data;
if (json_data.count(L"path"))
@ -50,71 +93,94 @@ namespace kiwano
{
for (const auto& image : json_data[L"images"])
{
LoadImageFromData(loader, global_data, image);
}
}
}
const String* id = nullptr, *type = nullptr, *file = nullptr;
int rows = 0, cols = 0;
void LoadImageFromData(ResLoader* loader, GlobalData const& global_data, Json const& image_data)
{
String id = image_data[L"id"];
if (image.count(L"id")) id = &image[L"id"].as_string();
if (image.count(L"type")) type = &image[L"type"].as_string();
if (image.count(L"file")) file = &image[L"file"].as_string();
if (image.count(L"rows")) rows = image[L"rows"].as_int();
if (image.count(L"cols")) cols = image[L"cols"].as_int();
if (image_data.count(L"file"))
{
String file = image_data[L"file"];
// Gif image
if (CompareJsonWithString(image_data, L"type", L"gif"))
{
loader->AddGifImage(id, Resource(global_data.path + file));
return;
}
if (!file.empty())
{
if (image_data.count(L"rows") || image_data.count(L"cols"))
if (image.count(L"files"))
{
// Image slices
int rows = 1, cols = 1;
if (image_data.count(L"rows")) rows = image_data[L"rows"];
if (image_data.count(L"cols")) cols = image_data[L"cols"];
loader->AddFrames(id, Resource(global_data.path + file), cols, rows);
return;
Array<String> files;
files.reserve(image[L"files"].size());
for (const auto& file : image[L"files"])
{
files.push_back(file.as_string());
}
if (!LoadImagesFromData(loader, &global_data, id, type, file, &files, rows, cols))
return false;
}
else
{
// Simple image
loader->AddImage(id, Resource(global_data.path + file));
return;
if (!LoadImagesFromData(loader, &global_data, id, type, file, nullptr, rows, cols))
return false;
}
}
}
// Frames
if (image_data.count(L"files"))
{
Array<ImagePtr> images;
images.reserve(image_data[L"files"].size());
for (const auto& file : image_data[L"files"])
{
auto filePath = file.as_string();
ImagePtr image = new Image(global_data.path + file.as_string());
if (image->IsValid())
{
images.push_back(image);
}
}
loader->AddFrames(id, images);
}
return true;
}
bool CompareJsonWithString(Json const& data, const wchar_t* key, const wchar_t* value)
bool LoadXmlData(ResLoader* loader, tinyxml2::XMLElement* elem)
{
return data.count(key) && data[key].as_string() == value;
GlobalData global_data;
if (auto path = elem->FirstChildElement("path"))
{
global_data.path = string_to_wide(path->GetText());
}
if (auto images = elem->FirstChildElement("images"))
{
for (auto image = images->FirstChildElement(); image; image = image->NextSiblingElement())
{
String id, type, file;
int rows = 0, cols = 0;
if (auto attr = image->Attribute("id")) id = string_to_wide(attr);
if (auto attr = image->Attribute("type")) type = string_to_wide(attr);
if (auto attr = image->Attribute("file")) file = string_to_wide(attr);
if (auto attr = image->IntAttribute("rows")) rows = attr;
if (auto attr = image->IntAttribute("cols")) cols = attr;
if (file.empty() && !image->NoChildren())
{
Array<String> files_arr;
for (auto file = image->FirstChildElement(); file; file = file->NextSiblingElement())
{
if (auto path = file->Attribute("path"))
{
files_arr.push_back(string_to_wide(path));
}
}
if (!LoadImagesFromData(loader, &global_data, &id, &type, &file, &files_arr, rows, cols))
return false;
}
else
{
if (!LoadImagesFromData(loader, &global_data, &id, &type, &file, nullptr, rows, cols))
return false;
}
}
}
return true;
}
}
namespace
{
Map<String, Closure<bool(ResLoader*, Json const&)>> load_json_funcs = {
{ L"latest", __res_loader_01::LoadJsonData },
{ L"0.1", __res_loader_01::LoadJsonData },
};
Map<String, Closure<bool(ResLoader*, tinyxml2::XMLElement*)>> load_xml_funcs = {
{ L"latest", __res_loader_01::LoadXmlData },
{ L"0.1", __res_loader_01::LoadXmlData },
};
}
bool ResLoader::LoadFromJsonFile(String const& file_path)
{
Json json_data;
@ -145,9 +211,15 @@ namespace kiwano
try
{
String version = json_data[L"version"];
if (version.empty() || version == L"0.9")
auto load = load_json_funcs.find(version);
if (load != load_json_funcs.end())
{
__res_loader_09::LoadJsonData(this, json_data);
return load->second(this, json_data);
}
else if (version.empty())
{
return load_json_funcs[L"latest"](this, json_data);
}
else
{
@ -159,7 +231,56 @@ namespace kiwano
KGE_WARNING_LOG(L"ResLoader::LoadFromJson failed: JSON data is invalid. (%s)", string_to_wide(e.what()).c_str());
return false;
}
return true;
return false;
}
bool ResLoader::LoadFromXmlFile(String const& file_path)
{
tinyxml2::XMLDocument doc;
if (tinyxml2::XML_SUCCESS != doc.LoadFile(kiwano::wide_to_string(file_path).c_str()))
{
KGE_WARNING_LOG(L"ResLoader::LoadFromXmlFile failed: %s",
string_to_wide(tinyxml2::XMLDocument::ErrorIDToName(doc.ErrorID())).c_str());
return false;
}
return LoadFromXml(&doc);
}
bool ResLoader::LoadFromXml(tinyxml2::XMLDocument* doc)
{
if (doc)
{
try
{
auto root = doc->FirstChildElement("resources");
KGE_ASSERT(root);
if (root)
{
kiwano::string version = root->FirstChildElement("version")->GetText();
auto load = load_xml_funcs.find(string_to_wide(version));
if (load != load_xml_funcs.end())
{
load->second(this, root);
}
else if (version.empty())
{
load_xml_funcs[L"latest"](this, root);
}
else
{
throw std::runtime_error("unknown JSON data version");
}
}
}
catch (std::exception& e)
{
KGE_WARNING_LOG(L"ResLoader::LoadFromXml failed: %s", string_to_wide(e.what()).c_str());
return false;
}
}
return false;
}
bool ResLoader::AddImage(String const& id, Resource const& image)
@ -337,11 +458,6 @@ namespace kiwano
return Get<Frames>(id);
}
ObjectPtr ResLoader::GetObj(String const & id) const
{
return Get<Object>(id);
}
void ResLoader::Delete(String const & id)
{
res_.erase(id);

View File

@ -24,6 +24,7 @@
#include "../common/Json.hpp"
#include "../base/Resource.h"
#include "../2d/include-forwards.h"
#include "../third-party/tinyxml2/tinyxml2.h"
namespace kiwano
{
@ -37,6 +38,12 @@ namespace kiwano
// 从 JSON 加载资源信息
bool LoadFromJson(Json const& json_data);
// 从 XML 文件加载资源信息
bool LoadFromXmlFile(String const& file_path);
// 从 XML 文档对象加载资源信息
bool LoadFromXml(tinyxml2::XMLDocument* doc);
// 添加图片
bool AddImage(String const& id, Resource const& image);
@ -78,9 +85,6 @@ namespace kiwano
// 获取序列帧
FramesPtr GetFrames(String const& id) const;
// 获取对象
ObjectPtr GetObj(String const& id) const;
// 删除指定资源
void Delete(String const& id);

View File

@ -216,6 +216,9 @@
<ItemGroup>
<None Include="res\index.json" />
</ItemGroup>
<ItemGroup>
<Xml Include="res\index.xml" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -31,4 +31,7 @@
<UniqueIdentifier>{4460eeec-9e2f-46b6-909a-5ff4443075ce}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Xml Include="res\index.xml" />
</ItemGroup>
</Project>

View File

@ -46,8 +46,11 @@ public:
void OnStart() override
{
// 从 JSON 文件中加载资源
g_Loader.LoadFromJsonFile(L"res/index.json");
// 从 JSON 文件中读取资源信息
//g_Loader.LoadFromJsonFile(L"res/index.json");
// 从 XML 文件中读取资源信息
g_Loader.LoadFromXmlFile(L"res/index.xml");
// 切换到第一个场景
ChangeDemoScene(0);

View File

@ -1,5 +1,5 @@
{
"version": "0.9",
"version": "0.1",
"path": "./res/",
"images": [
{

View File

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<resources>
<version>0.1</version>
<path>./res/</path>
<images>
<image id="man" file="man.png" />
<image id="monster" file="akushu.png" />
<image id="forest_bg" file="spring_forest.jpg" />
<image id="tiger_standing" file="tiger/stand.png" rows="2" cols="3" />
<image id="tiger_running">
<file path="tiger/run/run01.png"/>
<file path="tiger/run/run02.png"/>
<file path="tiger/run/run03.png"/>
<file path="tiger/run/run04.png"/>
<file path="tiger/run/run05.png"/>
<file path="tiger/run/run06.png"/>
</image>
<image id="Kusanagi" file="Kusanagi.gif" type="gif" />
</images>
</resources>