int32_t RogueSD::cardInfo(uint8_t getSize) { int32_t datum = 0; print(_prefix); print('Q'); print('\r'); while (!_commAvailable()); if (_commPeek() != 'E') { datum = _getNumber(10); // Free space (in KiB) _readBlocked(); // consume '/' or ' ' if (getSize) datum = _getNumber(10); // Card size else _getNumber(10); _readBlocked(); // consume prompt } else { _getResponse(); // if we have an error, return -1 // error code is actually in .lastErrorCode datum = -1; } return datum; }
fileInfo RogueSD::getFileInfo(int8_t handle) { fileInfo fi; print(_prefix); print('I'); print((char)('0' + handle)); print('\r'); while (!_commAvailable()); if (_commPeek() != 'E') { fi.position = _getNumber(10); // current file position _readBlocked(); // consume '/' or ' ' fi.size = _getNumber(10); // file size _readBlocked(); // consume prompt } else { _getResponse(); // if we have an error, just return 0's // error code is actually in .lastErrorCode fi.position = 0; fi.size = 0; } return fi; }
DisplayData * JSONDataParser::_parseDisplay(const rapidjson::Value & rawData) { const auto display = BaseObject::borrowObject<DisplayData>(); display->name = _getString(rawData, NAME, ""); if (rawData.HasMember(TYPE) && rawData[TYPE].IsString()) { display->type = _getDisplayType(rawData[TYPE].GetString()); } else { display->type = (DisplayType)_getNumber(rawData, TYPE, (int)DisplayType::Image); } display->isRelativePivot = true; if (rawData.HasMember(PIVOT)) { const auto& pivotObject = rawData[PIVOT]; display->pivot.x = _getNumber(pivotObject, X, 0.f); display->pivot.y = _getNumber(pivotObject, Y, 0.f); } else if (this->_isParentCooriinate) { const auto& transformObject = rawData[TRANSFORM]; display->isRelativePivot = false; display->pivot.x = _getNumber(transformObject, PIVOT_X, 0.f) * this->_armatureScale; display->pivot.y = _getNumber(transformObject, PIVOT_Y, 0.f) * this->_armatureScale; } else { display->pivot.x = 0.5f; display->pivot.y = 0.5f; } if (rawData.HasMember(TRANSFORM)) { _parseTransform(rawData[TRANSFORM], display->transform); } switch (display->type) { case DisplayType::Image: break; case DisplayType::Armature: break; case DisplayType::Mesh: display->meshData = _parseMesh(rawData); break; } return display; }
void JSONDataParser::parseTextureAtlasData(const char* rawData, TextureAtlasData& textureAtlasData, float scale) { if (rawData) { rapidjson::Document document; document.Parse(rawData); textureAtlasData.format = _getTextureFormat(_getString(document, FORMAT, "")); textureAtlasData.name = _getString(document, NAME, ""); textureAtlasData.imagePath = _getString(document, IMAGE_PATH, ""); if (scale > 0.f) { textureAtlasData.scale = scale; } else { scale = textureAtlasData.scale = _getNumber(document, SCALE, textureAtlasData.scale); } scale = 1.f / scale; if (document.HasMember(SUB_TEXTURE)) { for (const auto& textureObject : document[SUB_TEXTURE].GetArray()) { const auto textureData = textureAtlasData.generateTexture(); textureData->name = _getString(textureObject, NAME, ""); textureData->rotated = _getBoolean(textureObject, ROTATED, false); textureData->region.x = _getNumber(textureObject, X, 0.f) * scale; textureData->region.y = _getNumber(textureObject, Y, 0.f) * scale; textureData->region.width = _getNumber(textureObject, WIDTH, 0.f) * scale; textureData->region.height = _getNumber(textureObject, HEIGHT, 0.f) * scale; const auto frameWidth = _getNumber(textureObject, FRAME_WIDTH, -1.f); const auto frameHeight = _getNumber(textureObject, FRAME_HEIGHT, -1.f); if (frameWidth > 0.f && frameHeight > 0.f) { textureData->frame = TextureData::generateRectangle(); textureData->frame->x = _getNumber(textureObject, FRAME_X, 0.f) * scale; textureData->frame->y = _getNumber(textureObject, FRAME_Y, 0.f) * scale; textureData->frame->width = frameWidth * scale; textureData->frame->height = frameHeight * scale; } textureAtlasData.addTexture(textureData); } } } else { DRAGONBONES_ASSERT(false, "Argument error."); } }
int8_t RogueSD::_getResponse(void) { // looking for a response // If we get a space " ", we return as good and the remaining data can be retrieved // " ", ">", "Exx>" types only uint8_t r; uint8_t resp = 0; // we will return 1 if all is good, 0 otherwise (lastErrorCode contains the response from the module) r = _readBlocked(); if (r == ' ' || r == _promptChar) resp = 1; else if (r == 'E') { lastErrorCode = _getNumber(16); // get our error code _readBlocked(); // consume prompt resp = 0; } else { lastErrorCode = 0xFF; // something got messed up, a resync would be nice resp = 0; } return resp; }
int8_t RogueSD::getFreeHandle(void) { uint8_t resp; print(_prefix); print('F'); print('\r'); resp = _readBlocked(); if (resp != 'E') resp -= '0'; // got our handle else { lastErrorCode = _getNumber(16); if (lastErrorCode == ERROR_NO_FREE_FILES) resp = 0; else resp = -1; } _readBlocked(); // consume prompt return resp; }
SlotFrameData * JSONDataParser::_parseSlotFrame(const rapidjson::Value & rawData, unsigned frameStart, unsigned frameCount) const { const auto frame = BaseObject::borrowObject<SlotFrameData>(); frame->displayIndex = _getNumber(rawData, DISPLAY_INDEX, (int)0); _parseTweenFrame<SlotFrameData>(rawData, *frame, frameStart, frameCount); if (rawData.HasMember(COLOR)) { frame->color = SlotFrameData::generateColor(); _parseColorTransform(rawData[COLOR], *frame->color); } else { frame->color = &SlotFrameData::DEFAULT_COLOR; } if (this->_isParentCooriinate) { if (_getBoolean(rawData, HIDE, false)) { frame->displayIndex = -1; } } else if (rawData.HasMember(ACTION)) { const auto slot = static_cast<SlotTimelineData*>(this->_timeline)->slot; _parseActionData(rawData, frame->actions, slot->parent, slot); } return frame; }
BoneFrameData * JSONDataParser::_parseBoneFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) const { const auto frame = BaseObject::borrowObject<BoneFrameData>(); frame->parent = this->_armature->getBone(_getString(rawData, PARENT, "")); frame->tweenRotate = _getNumber(rawData, TWEEN_ROTATE, (int)0); frame->tweenScale = _getBoolean(rawData, TWEEN_SCALE, true); _parseTweenFrame<BoneFrameData>(rawData, *frame, frameStart, frameCount); if (rawData.HasMember(TRANSFORM)) { _parseTransform(rawData[TRANSFORM], frame->transform); } const auto bone = static_cast<BoneTimelineData*>(this->_timeline)->bone; if ((rawData.HasMember(EVENT) || rawData.HasMember(SOUND))) { _parseEventData(rawData, frame->events, bone, nullptr); this->_animation->hasBoneTimelineEvent = true; } if (rawData.HasMember(ACTION)) { const auto slot = this->_armature->getSlot(bone->name); _parseActionData(rawData, frame->actions, bone, slot); this->_animation->hasBoneTimelineEvent = true; } return frame; }
ExtensionFrameData * JSONDataParser::_parseFFDFrame(const rapidjson::Value & rawData, unsigned frameStart, unsigned frameCount) const { const auto frame = BaseObject::borrowObject<ExtensionFrameData>(); frame->type = (ExtensionType)_getNumber(rawData, TYPE, (int)ExtensionType::FFD); _parseTweenFrame<ExtensionFrameData>(rawData, *frame, frameStart, frameCount); const auto& rawVertices = rawData[VERTICES].GetArray(); const auto offset = _getNumber(rawData, OFFSET, (unsigned)0); auto x = 0.f; auto y = 0.f; for (std::size_t i = 0, l = this->_mesh->vertices.size(); i < l; i += 2) { if (i < offset || i - offset >= rawVertices.Size()) { x = 0.f; y = 0.f; } else { x = rawVertices[i - offset].GetFloat() * this->_armatureScale; y = rawVertices[i + 1 - offset].GetFloat() * this->_armatureScale; } if (this->_mesh->skinned) { this->_mesh->slotPose.transformPoint(x, y, _helpPoint, true); x = _helpPoint.x; y = _helpPoint.y; const auto& boneIndices = this->_mesh->boneIndices[(std::size_t)(i / 2)]; for (const auto boneIndex : boneIndices) { this->_mesh->inverseBindPose[boneIndex].transformPoint(x, y, _helpPoint, true); frame->tweens.push_back(_helpPoint.x); frame->tweens.push_back(_helpPoint.y); } } else { frame->tweens.push_back(x); frame->tweens.push_back(y); } } return frame; }
int16_t RogueSD::_getVersion(void) { // get the version, and module type print('V'); print('\r'); // Version format: mmm.nn[-bxxx] SN:TTTT-ssss... // get first portion mmm.nn _fwVersion = _getNumber(10); _readBlocked(); // consume '.' _fwVersion *= 100; _fwVersion += _getNumber(10); // ignore beta version (-bxxx), if it's there if (_readBlocked() == '-') { for (char i = 0; i < 5; i++) // drop bxxx plus space _readBlocked(); } // otherwise, it was a space // now drop the SN: _readBlocked(); _readBlocked(); _readBlocked(); if (_readBlocked() == 'R') _moduleType = rMP3; else { // either UMM1 or UMP1 // so drop the M following the U _readBlocked(); if (_readBlocked() == 'M') _moduleType = uMMC; else _moduleType = uMP3; } // ignore the rest while (_readBlocked() != '-'); // consume up to and including prompt while (isalnum(_readBlocked())); return _fwVersion; }
void JSONDataParser::_parseColorTransform(const rapidjson::Value& rawData, ColorTransform& color) const { color.alphaMultiplier = _getNumber(rawData, ALPHA_MULTIPLIER, (int)100) * 0.01f; color.redMultiplier = _getNumber(rawData, RED_MULTIPLIER, (int)100) * 0.01f; color.greenMultiplier = _getNumber(rawData, GREEN_MULTIPLIER, (int)100) * 0.01f; color.blueMultiplier = _getNumber(rawData, BLUE_MULTIPLIER, (int)100) * 0.01f; color.alphaOffset = _getNumber(rawData, ALPHA_OFFSET, (int)0); color.redOffset = _getNumber(rawData, RED_OFFSET, (int)0); color.greenOffset = _getNumber(rawData, GREEN_OFFSET, (int)0); color.blueOffset = _getNumber(rawData, BLUE_OFFSET, (int)0); }
int32_t RogueSD::size(const char *path) { char c; uint32_t filesize = 0; int8_t resp; if (_fwLevel == 0) { // old lastErrorCode = ERROR_NOT_SUPPORTED; return -1; } resp = exists(path); if (resp == TYPE_FOLDER) { // path is a folder lastErrorCode = ERROR_NOT_A_FILE; return -1; } else if (resp == TYPE_FILE) { print(_prefix); print("L "); print(path); print('\r'); if (_getResponse()) { // we have the file info next while (!_commAvailable()); filesize = _getNumber(10); // clear the rest while ((c = _readBlocked()) != '\r'); _readBlocked(); // consume prompt return (int32_t) filesize; } else { // had an error return -1; } } else { // path does not exist lastErrorCode = ERROR_FILE_DOES_NOT_EXIST; return -1; } }
SlotData * JSONDataParser::_parseSlot(const rapidjson::Value & rawData) { const auto slot = BaseObject::borrowObject<SlotData>(); slot->name = _getString(rawData, NAME, ""); slot->parent = this->_armature->getBone(_getString(rawData, PARENT, "")); slot->displayIndex = _getNumber(rawData, DISPLAY_INDEX, (int)0); slot->zOrder = _getNumber(rawData, Z_ORDER, (unsigned)this->_armature->getSortedSlots().size()); if (rawData.HasMember(COLOR)) { slot->color = SlotData::generateColor(); _parseColorTransform(rawData[COLOR], *slot->color); } else { slot->color = &SlotData::DEFAULT_COLOR; } if (rawData.HasMember(BLEND_MODE) && rawData[BLEND_MODE].IsString()) { slot->blendMode = _getBlendMode(rawData[BLEND_MODE].GetString()); } else { slot->blendMode = (BlendMode)_getNumber(rawData, BLEND_MODE, (int)BlendMode::Normal); } if (this->_isParentCooriinate) { if (rawData.HasMember(COLOR_TRANSFORM)) { slot->color = SlotData::generateColor(); _parseColorTransform(rawData[COLOR_TRANSFORM], *slot->color); } else { slot->color = &SlotData::DEFAULT_COLOR; } } return slot; }
void JSONDataParser::_parseTransform(const rapidjson::Value& rawData, Transform& transform) const { transform.x = _getNumber(rawData, X, 0.f) * this->_armatureScale; transform.y = _getNumber(rawData, Y, 0.f) * this->_armatureScale; transform.skewX = _getNumber(rawData, SKEW_X, 0.f) * ANGLE_TO_RADIAN; transform.skewY = _getNumber(rawData, SKEW_Y, 0.f) * ANGLE_TO_RADIAN; transform.scaleX = _getNumber(rawData, SCALE_X, 1.f); transform.scaleY = _getNumber(rawData, SCALE_Y, 1.f); }
void JSONDataParser::_parseIK(const rapidjson::Value & rawData) { const auto bone = this->_armature->getBone(_getString(rawData, rawData.HasMember(BONE) ? BONE : NAME, "")); if (bone) { bone->ik = this->_armature->getBone(_getString(rawData, TARGET, "")); bone->bendPositive = _getBoolean(rawData, BEND_POSITIVE, true); bone->chain = _getNumber(rawData, CHAIN, (unsigned)0); bone->weight = _getNumber(rawData, WEIGHT, 1.f); if (bone->chain > 0 && bone->parent && !bone->parent->ik) { bone->parent->ik = bone->ik; bone->parent->chainIndex = 0; bone->parent->chain = 0; bone->chainIndex = 1; } else { bone->chain = 0; bone->chainIndex = 0; } } }
void RogueSD::getTime(uint16_t *rtc) { if (_fwLevel > 0) { print('T'); print('\r'); for (uint8_t i = 0; i < 7; i++) { rtc[i] = _getNumber(10); _readBlocked(); // consume separators, and command prompt (at end) } } else { // old return; } }
DragonBonesData * JSONDataParser::parseDragonBonesData(const char* rawData, float scale) { if (rawData) { rapidjson::Document document; document.Parse(rawData); std::string version = _getString(document, VERSION, ""); this->_isParentCooriinate = version == DATA_VERSION_2_3 || version == DATA_VERSION_3_0; this->_armatureScale = scale; if (version == DATA_VERSION || version == DATA_VERSION_4_0 || this->_isParentCooriinate) { const auto data = BaseObject::borrowObject<DragonBonesData>(); data->name = _getString(document, NAME, ""); data->frameRate = _getNumber(document, FRAME_RATE, (unsigned)24); if (document.HasMember(ARMATURE)) { this->_data = data; for (const auto& armatureObject : document[ARMATURE].GetArray()) { data->addArmature(_parseArmature(armatureObject)); } this->_data = nullptr; } return data; } else { DRAGONBONES_ASSERT(false, "Nonsupport data version."); } } else { DRAGONBONES_ASSERT(false, "Argument error."); } return nullptr; }
int32_t RogueSD::fileCount(const char *path, const char *filemask) { int32_t fcount = 0; if (_fwLevel > 0) { print(_prefix); print("LC "); if (path != NULL) print(path); if (filemask != NULL && strlen(filemask) > 0) { if (strlen(path) && path[strlen(path) - 1] != '/') { print('/'); } print(filemask); } print('\r'); if (_getResponse()) { fcount = _getNumber(10); _readBlocked(); // consume prompt return fcount; } else { // error occurred with "LC" command return -1; } } else { // old lastErrorCode = ERROR_NOT_SUPPORTED; return -1; } }
int16_t RogueSD::getSetting(char setting) { uint8_t value; print('S'); if (_moduleType != uMMC) print('T'); print(setting); print('\r'); while (!_commAvailable()); if (_commPeek() != 'E') { value = _getNumber(10); _readBlocked(); // consume prompt } else { value = _getResponse(); // get the error } return value; }
BoneData * JSONDataParser::_parseBone(const rapidjson::Value & rawData) { const auto bone = BaseObject::borrowObject<BoneData>(); bone->name = _getString(rawData, NAME, ""); bone->inheritTranslation = _getBoolean(rawData, INHERIT_TRANSLATION, true); bone->inheritRotation = _getBoolean(rawData, INHERIT_ROTATION, true); bone->inheritScale = _getBoolean(rawData, INHERIT_SCALE, true); bone->length = _getNumber(rawData, LENGTH, 0.f) * _armatureScale; if (rawData.HasMember(TRANSFORM)) { _parseTransform(rawData[TRANSFORM], bone->transform); } if (this->_isParentCooriinate) { bone->inheritRotation = true; bone->inheritScale = false; } return bone; }
int8_t RogueSD::sync(bool blocking) { // procedure: // 1. sync (send ESC, clear prompt) // 2. get version ("v"), and module type // 3. change settings as needed // 4. close files // 0. empty any data in the serial buffer _comms->flush(); // 1. sync print((char)ASCII_ESC); // send ESC to clear buffer on uMMC if (blocking) { _readBlocked(); // consume prompt } else { if (_readTimeout(ROGUESD_DEFAULT_READ_TIMEOUT) < 0) { return 0; } } // 2. get version (ignore prompt - just drop it) _getVersion(); if (_moduleType == uMMC) _prefix = ""; else _prefix = "FC"; // 3. change settings as needed // OLD: write timeout setting = 10 ms timeout // NEW: listing style = old style (0) if ((_moduleType == uMMC && _fwVersion < UMMC_MIN_FW_VERSION_FOR_NEW_COMMANDS) || (_moduleType == uMP3 && _fwVersion < UMP3_MIN_FW_VERSION_FOR_NEW_COMMANDS)) { // we need to set the write timeout to allow us to control when a line is finished // in writeln. changeSetting('1', 1); // 10 ms timeout _fwLevel = 0; } else { // we're using the new version _fwLevel = 1; // Let's make sure the Listing Style setting is set to the old style if (getSetting('L') != 0) { changeSetting('L', 0); } // get the prompt char print('S'); if (_moduleType != uMMC) print('T'); print('P'); print('\r'); // get our prompt (if possible) _promptChar = _getNumber(10); _readBlocked(); // consume prompt } // 4. close files closeAll(); // ensure all handles are closed return 1; }
int8_t RogueSD::entryToFilename(char *dest, uint8_t count, uint16_t entrynum, const char *path, const char *filemask) { char c; int8_t entrytype = TYPE_FILE; if (_fwLevel > 0) { // new print(_prefix); print("LE "); print(entrynum, DEC); print(' '); if (path != NULL) print(path); if (filemask != NULL && strlen(filemask) > 0) { if (strlen(path) == 0 || path[strlen(path) - 1] != '/') { print('/'); } print(filemask); } print('\r'); if (_getResponse()) { // we have the file info next while (!_commAvailable()); if (_commPeek() == 'D') { // we have a directory _commRead(); // consume 'D' entrytype = TYPE_FOLDER; } else { // it's a file, with a file size _getNumber(10); // discard (for now) entrytype = TYPE_FILE; } _readBlocked(); // consume separator ' ' // now get filename while ((c = _readBlocked()) != '\r') { if (count > 0) { count--; *dest++ = c; } } *dest = 0; // terminate string _readBlocked(); // consume prompt return entrytype; } else { // had an error return 0; } } else { // old lastErrorCode = ERROR_NOT_SUPPORTED; return -1; } }
int8_t RogueSD::readDir(char *dest, const char *filemask) { // retrieve the next entry from the directory // returns: // 0 when no more files/folders (EOF) // -1 on failure // 1 if entry is a file // 2 if entry is a folder/directory // currently using the original file listing style, i.e. D/fs filename char c; int8_t entrytype = TYPE_FILE; if (_fwLevel > 0) { print(_prefix); print("LI "); if (filemask) print(filemask); else print('*'); print('\r'); if (_getResponse()) { // we have the file info next while (!_commAvailable()); if (_commPeek() == 'D') { // we have a directory _commRead(); // consume 'D' entrytype = TYPE_FOLDER; } else { // it's a file, with a file size _getNumber(10); // discard (for now) entrytype = TYPE_FILE; } _readBlocked(); // consume separator ' ' // now get filename while ((c = _readBlocked()) != '\r') { *dest++ = c; } *dest = 0; // terminate string _readBlocked(); // consume prompt return entrytype; } else { // had an error if (lastErrorCode == ERROR_EOF) return 0; else return -1; } } else { // old lastErrorCode = ERROR_NOT_SUPPORTED; return -1; } }
AnimationData * JSONDataParser::_parseAnimation(const rapidjson::Value & rawData) const { const auto animation = BaseObject::borrowObject<AnimationData>(); animation->name = _getString(rawData, NAME, "__default"); if (animation->name.empty()) { animation->name = "__default"; } animation->frameCount = std::max(_getNumber(rawData, DURATION, (unsigned)1), (unsigned)1); animation->position = _getNumber(rawData, POSITION, 0.f) / this->_armature->frameRate; animation->duration = (float)animation->frameCount / this->_armature->frameRate; animation->playTimes = _getNumber(rawData, PLAY_TIMES, (unsigned)1); animation->fadeInTime = _getNumber(rawData, FADE_IN_TIME, 0.f); this->_animation = animation; std::string animationName = _getString(rawData, ANIMATION, ""); if (!animationName.empty()) { animation->animation = this->_armature->getAnimation(animationName); if (!animation->animation) { } return animation; } _parseTimeline<AnimationFrameData>(rawData, *animation, std::bind(&JSONDataParser::_parseAnimationFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); if (rawData.HasMember(BONE)) { for (const auto& boneTimelineObject : rawData[BONE].GetArray()) { animation->addBoneTimeline(_parseBoneTimeline(boneTimelineObject)); } } if (rawData.HasMember(SLOT)) { for (const auto& slotTimelineObject : rawData[SLOT].GetArray()) { animation->addSlotTimeline(_parseSlotTimeline(slotTimelineObject)); } } if (rawData.HasMember(FFD)) { for (const auto& ffdTimelineObject : rawData[FFD].GetArray()) { animation->addFFDTimeline(_parseFFDTimeline(ffdTimelineObject)); } } if (this->_isParentCooriinate) { this->_isAutoTween = _getBoolean(rawData, AUTO_TWEEN, true); this->_animationTweenEasing = _getNumber(rawData, TWEEN_EASING, 0.f) || 0.f; animation->playTimes = _getNumber(rawData, LOOP, (unsigned)1); if (rawData.HasMember(TIMELINE)) { const auto timelines = rawData[TIMELINE].GetArray(); for (const auto& timeline : timelines) { animation->addBoneTimeline(_parseBoneTimeline(timeline)); } for (const auto& timeline : timelines) { animation->addSlotTimeline(_parseSlotTimeline(timeline)); } } } else { this->_isAutoTween = false; this->_animationTweenEasing = 0.f; } for (const auto& pair : this->_armature->bones) { if (!animation->getBoneTimeline(pair.second->name)) { const auto boneTimeline = BaseObject::borrowObject<BoneTimelineData>(); const auto boneFrame = BaseObject::borrowObject<BoneFrameData>(); boneTimeline->bone = pair.second; boneTimeline->frames.reserve(1); boneTimeline->frames.push_back(boneFrame); animation->addBoneTimeline(boneTimeline); } } for (const auto& pair : this->_armature->slots) { if (!animation->getSlotTimeline(pair.second->name)) { const auto slotTimeline = BaseObject::borrowObject<SlotTimelineData>(); const auto slotFrame = BaseObject::borrowObject<SlotFrameData>(); slotTimeline->slot = pair.second; slotFrame->displayIndex = pair.second->displayIndex; if (pair.second->color == &SlotData::DEFAULT_COLOR) { slotFrame->color = &SlotFrameData::DEFAULT_COLOR; } else { slotFrame->color = SlotFrameData::generateColor(); *slotFrame->color = *pair.second->color; // copy } slotTimeline->frames.reserve(1); slotTimeline->frames.push_back(slotFrame); animation->addSlotTimeline(slotTimeline); if (this->_isParentCooriinate) { slotFrame->displayIndex = -1; } } } this->_animation = nullptr; return animation; }
ArmatureData * JSONDataParser::_parseArmature(const rapidjson::Value & rawData) { const auto armature = BaseObject::borrowObject<ArmatureData>(); armature->name = _getString(rawData, NAME, ""); armature->frameRate = _getNumber(rawData, FRAME_RATE, this->_data->frameRate); if (rawData.HasMember(TYPE) && rawData[TYPE].IsString()) { armature->type = _getArmatureType(rawData[TYPE].GetString()); } else { armature->type = (ArmatureType)_getNumber(rawData, TYPE, (int)ArmatureType::Armature); } this->_armature = armature; this->_rawBones.clear(); if (rawData.HasMember(BONE)) { for (const auto& boneObject : rawData[BONE].GetArray()) { const auto bone = _parseBone(boneObject); armature->addBone(bone, _getString(boneObject, PARENT, "")); this->_rawBones.push_back(bone); } } if (rawData.HasMember(IK)) { for (const auto& ikObject : rawData[IK].GetArray()) { _parseIK(ikObject); } } if (rawData.HasMember(SLOT)) { for (const auto& slotObject : rawData[SLOT].GetArray()) { armature->addSlot(_parseSlot(slotObject)); } } if (rawData.HasMember(SKIN)) { for (const auto& skinObject : rawData[SKIN].GetArray()) { armature->addSkin(_parseSkin(skinObject)); } } if (rawData.HasMember(ANIMATION)) { for (const auto& animationObject : rawData[ANIMATION].GetArray()) { armature->addAnimation(_parseAnimation(animationObject)); } } this->_armature = nullptr; this->_rawBones.clear(); if (this->_isParentCooriinate && _getBoolean(rawData, IS_GLOBAL, true)) { this->_globalToLocal(armature); } return armature; }