190 auto *dm = eve::data::DataModule::create();
192 std::unique_ptr<data::JsonDocument> doc(dm->decodeJson(json, &err));
193 if (!doc || !doc->isObject()) {
194 if (
error) *
error = err.empty() ?
"invalid json" : err;
197 Poco::JSON::Object::Ptr
root = doc->object();
200 if (
root->has(
"skeleton")) {
201 auto skel =
root->getObject(
"skeleton");
202 if (skel) spineVersion_ = asString(skel->get(
"spine"));
206 if (
root->has(
"bones")) {
207 auto arr =
root->getArray(
"bones");
209 for (
size_t i = 0; i < arr->size(); ++i) {
210 auto obj = arr->getObject(
static_cast<unsigned>(i));
213 b.
name = asString(obj->get(
"name"));
214 if (
b.name.empty())
continue;
215 if (obj->has(
"parent")) {
216 std::string
parent = asString(obj->get(
"parent"));
224 b.x = asFloat(obj->get(
"x"));
225 b.y = asFloat(obj->get(
"y"));
226 b.rotation = asFloat(obj->get(
"rotation"));
227 b.scaleX = obj->has(
"scaleX") ? asFloat(obj->get(
"scaleX"), 1.f) : 1.f;
228 b.scaleY = obj->has(
"scaleY") ? asFloat(obj->get(
"scaleY"), 1.f) : 1.f;
229 boneByName_[
b.name] =
static_cast<int>(bones_.size());
230 bones_.push_back(std::move(
b));
234 if (bones_.empty()) {
236 rootBone.
name =
"root";
237 boneByName_[
"root"] = 0;
238 bones_.push_back(rootBone);
242 if (
root->has(
"slots")) {
243 auto arr =
root->getArray(
"slots");
245 for (
size_t i = 0; i < arr->size(); ++i) {
246 auto obj = arr->getObject(
static_cast<unsigned>(i));
249 s.
name = asString(obj->get(
"name"));
250 std::string boneName = asString(obj->get(
"bone"));
252 if (
s.bone < 0)
s.bone = 0;
253 if (obj->has(
"attachment"))
s.attachment = asString(obj->get(
"attachment"));
254 slotByName_[
s.name] =
static_cast<int>(slots_.size());
255 slots_.push_back(std::move(
s));
260 auto parseRegion = [&](
const std::string &attName, Poco::JSON::Object::Ptr att)
264 r.path = att->has(
"path") ? asString(att->get(
"path")) : attName;
265 r.x = asFloat(att->get(
"x"));
266 r.y = asFloat(att->get(
"y"));
267 r.rotation = asFloat(att->get(
"rotation"));
268 r.width = asFloat(att->get(
"width"));
269 r.height = asFloat(att->get(
"height"));
270 r.scaleX = att->has(
"scaleX") ? asFloat(att->get(
"scaleX"), 1.f) : 1.f;
271 r.scaleY = att->has(
"scaleY") ? asFloat(att->get(
"scaleY"), 1.f) : 1.f;
275 auto addSkinAttachments = [&](
SkinData &
skin, Poco::JSON::Object::Ptr attachmentsRoot) {
276 if (!attachmentsRoot)
return;
279 for (
const auto &slotName : attachmentsRoot->getNames()) {
281 if (slotIndex < 0)
continue;
282 auto slotObj = attachmentsRoot->getObject(slotName);
283 if (!slotObj)
continue;
284 for (
const auto &attName : slotObj->getNames()) {
285 auto attObj = slotObj->getObject(attName);
286 if (!attObj)
continue;
288 std::string
type = attObj->has(
"type") ? asString(attObj->get(
"type")) :
"region";
289 if (!
type.empty() &&
type !=
"region")
continue;
296 if (
root->has(
"skins")) {
297 if (
root->isArray(
"skins")) {
298 auto arr =
root->getArray(
"skins");
299 for (
size_t i = 0; i < arr->size(); ++i) {
300 auto obj = arr->getObject(
static_cast<unsigned>(i));
303 skin.
name = asString(obj->get(
"name"));
305 if (obj->has(
"attachments"))
306 addSkinAttachments(
skin, obj->getObject(
"attachments"));
307 skinByName_[
skin.
name] =
static_cast<int>(skins_.size());
308 skins_.push_back(std::move(
skin));
311 auto obj =
root->getObject(
"skins");
313 for (
const auto &skinName : obj->getNames()) {
316 addSkinAttachments(
skin, obj->getObject(skinName));
317 skinByName_[
skin.
name] =
static_cast<int>(skins_.size());
318 skins_.push_back(std::move(
skin));
323 if (skins_.empty()) {
326 skinByName_[
"default"] = 0;
327 skins_.push_back(
skin);
330 if (defaultSkin_ < 0) defaultSkin_ = 0;
333 if (
root->has(
"animations")) {
334 auto animsObj =
root->getObject(
"animations");
336 for (
const auto &animName : animsObj->getNames()) {
337 auto animObj = animsObj->getObject(animName);
338 if (!animObj)
continue;
340 anim.
name = animName;
343 if (animObj->has(
"bones")) {
344 auto bonesObj = animObj->getObject(
"bones");
346 for (
const auto &boneName : bonesObj->getNames()) {
348 if (bi < 0)
continue;
349 auto btObj = bonesObj->getObject(boneName);
350 if (!btObj)
continue;
354 if (btObj->has(
"rotate")) {
355 auto arr = btObj->getArray(
"rotate");
357 for (
size_t i = 0; i < arr->size(); ++i) {
358 auto k = arr->getObject(
static_cast<unsigned>(i));
361 fk.
time = asFloat(k->get(
"time"));
362 fk.
value = asFloat(k->get(
"value"),
363 asFloat(k->get(
"angle")));
365 maxT = std::max(maxT, fk.
time);
370 if (btObj->has(
"translate")) {
371 auto arr = btObj->getArray(
"translate");
373 for (
size_t i = 0; i < arr->size(); ++i) {
374 auto k = arr->getObject(
static_cast<unsigned>(i));
377 tk.
time = asFloat(k->get(
"time"));
378 tk.
x = asFloat(k->get(
"x"));
379 tk.
y = asFloat(k->get(
"y"));
381 maxT = std::max(maxT, tk.
time);
386 if (btObj->has(
"scale")) {
387 auto arr = btObj->getArray(
"scale");
389 for (
size_t i = 0; i < arr->size(); ++i) {
390 auto k = arr->getObject(
static_cast<unsigned>(i));
393 sk.
time = asFloat(k->get(
"time"));
394 sk.
x = k->has(
"x") ? asFloat(k->get(
"x"), 1.f) : 1.f;
395 sk.
y = k->has(
"y") ? asFloat(k->get(
"y"), 1.f) : 1.f;
397 maxT = std::max(maxT, sk.
time);
398 bt.
scale.push_back(sk);
402 anim.
bones.push_back(std::move(bt));
407 if (animObj->has(
"slots")) {
408 auto slotsObj = animObj->getObject(
"slots");
410 for (
const auto &slotName : slotsObj->getNames()) {
412 if (si < 0)
continue;
413 auto stObj = slotsObj->getObject(slotName);
414 if (!stObj)
continue;
417 if (stObj->has(
"attachment")) {
418 auto arr = stObj->getArray(
"attachment");
420 for (
size_t i = 0; i < arr->size(); ++i) {
421 auto k = arr->getObject(
static_cast<unsigned>(i));
424 ak.
time = asFloat(k->get(
"time"));
425 ak.
name = k->has(
"name") ? asString(k->get(
"name")) :
"";
426 maxT = std::max(maxT, ak.
time);
431 anim.
slots.push_back(std::move(st));
437 animByName_[anim.
name] =
static_cast<int>(anims_.size());
438 anims_.push_back(std::move(anim));
442 }
catch (
const std::exception &ex) {