Repository navigation
Expand file tree
/
Copy pathFrameAnimationMsgPack.cpp
More file actions
198 lines (175 loc) · 6.52 KB
/
Copy pathFrameAnimationMsgPack.cpp
File metadata and controls
198 lines (175 loc) · 6.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include "FrameAnimationMsgPack.h"
#include "FrameAnimationData.h"
#include <deki/LogSystem.h>
#include <deki/assets/AssetManager.h>
#include <deki/providers/FileSystem.h>
#include <deki/SceneMessagePack.h>
#include <cstddef>
#include <cstdint>
#include <fstream>
#include <vector>
#ifdef DEKI_EDITOR
#include <nlohmann/json.hpp>
#include <deki/reflection/Serialization.h>
#endif
namespace Deki2D
{
#ifdef DEKI_EDITOR
// Editor only: saving goes through the generated reflection serializer.
using json = nlohmann::json;
#endif
// FrameAnimationData is DEKI_SERIALIZABLE, so the reflection codegen
// generates the editor's JSON Deki::Serialize<T> and DeserializeMsgPack for
// every platform (declared in generated/FrameAnimationData.gen.h, which
// FrameAnimationData.h includes). Load and save both use them.
bool FrameAnimationMsgPackHelper::LoadAnimation(const char* msgpackPath, FrameAnimationData* outData)
{
if (!msgpackPath || !outData)
{
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::LoadAnimation - null parameters");
return false;
}
// Through the filesystem provider, like Sprite and BitmapFont: on a device
// and in the desktop simulator the path starts with a mount such as "S:/",
// which a plain ifstream cannot resolve.
Deki::IFileSystem* fs = Deki::FileSystem::GetFileSystemForPath(msgpackPath);
if (!fs)
{
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::LoadAnimation - no filesystem for: %s", msgpackPath);
return false;
}
Deki::IFileSystem::FileHandle file = fs->OpenFile(msgpackPath, Deki::IFileSystem::OpenMode::ReadBinary);
if (!file)
{
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::LoadAnimation - failed to open: %s", msgpackPath);
return false;
}
const long size = fs->GetFileSize(file);
if (size <= 0)
{
fs->CloseFile(file);
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::LoadAnimation - empty file: %s", msgpackPath);
return false;
}
std::vector<uint8_t> buffer(static_cast<size_t>(size));
const size_t read = fs->ReadFile(file, buffer.data(), static_cast<size_t>(size));
fs->CloseFile(file);
if (read != static_cast<size_t>(size))
{
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::LoadAnimation - failed to read file: %s", msgpackPath);
return false;
}
return LoadAnimationFromMemory(buffer.data(), static_cast<size_t>(size), outData);
}
bool FrameAnimationMsgPackHelper::LoadAnimationFromMemory(const uint8_t* data, size_t size, FrameAnimationData* outData)
{
if (!data || size == 0 || !outData)
{
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::LoadAnimationFromMemory - invalid parameters");
return false;
}
outData->spritesheetGuid.clear();
outData->animations.clear();
// The generated deserializer, keyed by full field names. Desktop and
// device both read through SceneMsgPackParser.
Deki::SceneFormat::SceneMsgPackParser parser(data, size);
uint32_t mapSize = 0;
if (!parser.ReadMapSize(mapSize))
{
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::LoadAnimationFromMemory - root is not a MessagePack map");
return false;
}
if (!DeserializeMsgPack(*outData, parser, mapSize))
{
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::LoadAnimationFromMemory - deserialize failed");
return false;
}
int totalFrames = 0;
for (const auto& anim : outData->animations)
{
totalFrames += static_cast<int>(anim.frames.size());
}
DEKI_LOG_INTERNAL("FrameAnimationMsgPackHelper::LoadAnimation - loaded %d animations with %d total frames",
static_cast<int>(outData->animations.size()), totalFrames);
return true;
}
#ifdef DEKI_EDITOR
bool FrameAnimationMsgPackHelper::SaveAnimation(const char* msgpackPath, const FrameAnimationData* animData)
{
if (!msgpackPath || !animData)
{
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::SaveAnimation - null parameters");
return false;
}
try
{
// The generated serializer, keyed by full field names, then MessagePack.
// Mirrors the load path; nested sequences and frames are included.
json j = Deki::Serialize<FrameAnimationData>(*animData);
std::vector<uint8_t> msgpackData = json::to_msgpack(j);
std::ofstream file(msgpackPath, std::ios::binary);
if (!file.is_open())
{
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::SaveAnimation - failed to open for writing: %s", msgpackPath);
return false;
}
file.write(reinterpret_cast<const char*>(msgpackData.data()), msgpackData.size());
int totalFrames = 0;
for (const auto& seq : animData->animations)
{
totalFrames += static_cast<int>(seq.frames.size());
}
DEKI_LOG_INTERNAL(
"FrameAnimationMsgPackHelper::SaveAnimation - saved %d animations with %d total frames (%zu bytes)",
static_cast<int>(animData->animations.size()), totalFrames, msgpackData.size());
return file.good();
}
catch (const std::exception& e)
{
DEKI_LOG_ERROR("FrameAnimationMsgPackHelper::SaveAnimation - error: %s", e.what());
return false;
}
}
#endif
// Registers the animation loader with AssetManager. memLoader lets a device
// load packed animations straight from a .dpack.
//
// Must be called, not a static registrar: a firmware links the game from an
// archive, and the linker drops an object nothing references, registrar and
// all, which leaves animations unloadable on the device.
namespace
{
bool s_AnimLoaderRegistered = false;
}
void RegisterAnimationLoader()
{
if (s_AnimLoaderRegistered)
{
return;
}
s_AnimLoaderRegistered = true;
auto loader = [](const char* p) -> void*
{
auto* data = new FrameAnimationData();
if (FrameAnimationMsgPackHelper::LoadAnimation(p, data))
{
return data;
}
delete data;
return nullptr;
};
auto unloader = [](void* a) { delete static_cast<FrameAnimationData*>(a); };
auto memLoader = [](const uint8_t* d, size_t n) -> void*
{
auto* data = new FrameAnimationData();
if (FrameAnimationMsgPackHelper::LoadAnimationFromMemory(d, n, data))
{
return data;
}
delete data;
return nullptr;
};
Deki::AssetManager::RegisterLoader("FrameAnimationData", loader, unloader, memLoader);
Deki::AssetManager::RegisterLoader("Animation", loader, unloader, memLoader);
}
} // namespace Deki2D