#include "JSONDataParser.h" DRAGONBONES_NAMESPACE_BEGIN void JSONDataParser::_getCurvePoint(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float t, Point& result) { const auto l_t = 1.0f - t; const auto powA = l_t * l_t; const auto powB = t * t; const auto kA = l_t * powA; const auto kB = 3.0f * t * powA; const auto kC = 3.0f * l_t * powB; const auto kD = t * powB; result.x = kA * x1 + kB * x2 + kC * x3 + kD * x4; result.y = kA * y1 + kB * y2 + kC * y3 + kD * y4; } void JSONDataParser::_samplingEasingCurve(const rapidjson::Value& curve, std::vector& samples) { int curveCount = curve.Size(); int stepIndex = -2; for (std::size_t i = 0, l = samples.size(); i < l; ++i) { float t = (float)(i + 1) / (l + 1); // float while ((stepIndex + 6 < curveCount ? curve[stepIndex + 6].GetDouble() : 1) < t) // stepIndex + 3 * 2 { stepIndex += 6; } const auto isInCurve = stepIndex >= 0 && stepIndex + 6 < curveCount; const auto x1 = isInCurve ? curve[stepIndex].GetDouble() : 0.0f; const auto y1 = isInCurve ? curve[stepIndex + 1].GetDouble() : 0.0f; const auto x2 = curve[stepIndex + 2].GetDouble(); const auto y2 = curve[stepIndex + 3].GetDouble(); const auto x3 = curve[stepIndex + 4].GetDouble(); const auto y3 = curve[stepIndex + 5].GetDouble(); const auto x4 = isInCurve ? curve[stepIndex + 6].GetDouble() : 1.0f; const auto y4 = isInCurve ? curve[stepIndex + 7].GetDouble() : 1.0f; float lower = 0.0f; float higher = 1.0f; while (higher - lower > 0.0001f) { const auto percentage = (higher + lower) * 0.5f; _getCurvePoint(x1, y1, x2, y2, x3, y3, x4, y4, percentage, _helpPoint); if (t - _helpPoint.x > 0.0f) { lower = percentage; } else { higher = percentage; } } samples[i] = _helpPoint.y; } } void JSONDataParser::_parseActionDataInFrame(const rapidjson::Value& rawData, unsigned frameStart, BoneData* bone, SlotData* slot) { if (rawData.HasMember(EVENT)) { _mergeActionFrame(rawData[EVENT], frameStart, ActionType::Frame, bone, slot); } if (rawData.HasMember(SOUND)) { _mergeActionFrame(rawData[SOUND], frameStart, ActionType::Sound, bone, slot); } if (rawData.HasMember(ACTION)) { _mergeActionFrame(rawData[ACTION], frameStart, ActionType::Play, bone, slot); } if (rawData.HasMember(EVENTS)) { _mergeActionFrame(rawData[EVENTS], frameStart, ActionType::Frame, bone, slot); } if (rawData.HasMember(ACTIONS)) { _mergeActionFrame(rawData[ACTIONS], frameStart, ActionType::Play, bone, slot); } } void JSONDataParser::_mergeActionFrame(const rapidjson::Value& rawData, unsigned frameStart, ActionType type, BoneData* bone, SlotData* slot) { const auto actionOffset = _armature->actions.size(); const auto& actions = _parseActionData(rawData, type, bone, slot); ActionFrame* frame = nullptr; for (const auto action : actions) { _armature->addAction(action, false); } if (_actionFrames.empty()) // First frame. { _actionFrames.resize(1); _actionFrames[0].frameStart = 0; } for (auto& eachFrame : _actionFrames) // Get same frame. { if (eachFrame.frameStart == frameStart) { frame = &eachFrame; break; } } if (frame == nullptr) // Create and cache frame. { const auto frameCount = _actionFrames.size(); _actionFrames.resize(frameCount + 1); frame = &_actionFrames[frameCount]; frame->frameStart = frameStart; } for (std::size_t i = 0; i < actions.size(); ++i) // Cache action offsets. { frame->actions.push_back(actionOffset + i); } } unsigned JSONDataParser::_parseCacheActionFrame(ActionFrame& frame) { const auto frameOffset = _frameArray.size(); const auto actionCount = frame.actions.size(); _frameArray.resize(_frameArray.size() + 1 + 1 + actionCount); _frameArray[frameOffset + (unsigned)BinaryOffset::FramePosition] = frame.frameStart; _frameArray[frameOffset + (unsigned)BinaryOffset::FramePosition + 1] = actionCount; // Action count. for (std::size_t i = 0; i < actionCount; ++i) // Action offsets. { _frameArray[frameOffset + (unsigned)BinaryOffset::FramePosition + 2 + i] = frame.actions[i]; } return frameOffset; } ArmatureData* JSONDataParser::_parseArmature(const rapidjson::Value& rawData, float scale) { const auto armature = BaseObject::borrowObject(); armature->name = _getString(rawData, NAME, ""); armature->frameRate = _getNumber(rawData, FRAME_RATE, _data->frameRate); armature->scale = scale; if (rawData.HasMember(TYPE) && rawData[TYPE].IsString()) { armature->type = _getArmatureType(rawData[TYPE].GetString()); } else { armature->type = (ArmatureType)_getNumber(rawData, TYPE, (int)ArmatureType::Armature); } if (armature->frameRate == 0) // Data error. { armature->frameRate = 24; } _armature = armature; if (rawData.HasMember(CANVAS)) { const auto& rawCanvas = rawData[CANVAS]; const auto canvas = BaseObject::borrowObject(); canvas->hasBackground = rawCanvas.HasMember(COLOR); canvas->color = _getNumber(rawCanvas, COLOR, 0); canvas->aabb.x = _getNumber(rawCanvas, X, 0.0f) * armature->scale; canvas->aabb.y = _getNumber(rawCanvas, Y, 0.0f) * armature->scale; canvas->aabb.width = _getNumber(rawCanvas, WIDTH, 0.0f) * armature->scale; canvas->aabb.height = _getNumber(rawCanvas, HEIGHT, 0.0f) * armature->scale; // armature->canvas = canvas; } if (rawData.HasMember(AABB)) { const auto& rawAABB = rawData[AABB]; armature->aabb.x = _getNumber(rawAABB, X, 0.0f) * armature->scale; armature->aabb.y = _getNumber(rawAABB, Y, 0.0f) * armature->scale; armature->aabb.width = _getNumber(rawAABB, WIDTH, 0.0f) * armature->scale; armature->aabb.height = _getNumber(rawAABB, HEIGHT, 0.0f) * armature->scale; } if (rawData.HasMember(BONE)) { const auto& rawBones = rawData[BONE]; for (std::size_t i = 0, l = rawBones.Size(); i < l; ++i) { const auto& rawBone = rawBones[i]; const auto& parentName = _getString(rawBone, PARENT, ""); const auto bone = _parseBone(rawBone); if (!parentName.empty()) // Get bone parent. { const auto parent = armature->getBone(parentName); if (parent != nullptr) { bone->parent = parent; } else // Cache. { auto& cacheBones = _cacheBones[parentName]; cacheBones.push_back(bone); } } auto iterator = _cacheBones.find(bone->name); if (iterator != _cacheBones.end()) { for (const auto child : _cacheBones[bone->name]) { child->parent = bone; } _cacheBones.erase(iterator); } armature->addBone(bone); _rawBones.push_back(bone); // Cache raw bones sort. } } if (rawData.HasMember(IK)) { const auto& rawIKS = rawData[IK]; for (std::size_t i = 0, l = rawIKS.Size(); i < l; ++i) { const auto constraint = _parseIKConstraint(rawIKS[i]); if (constraint) { armature->addConstraint(constraint); } } } armature->sortBones(); if (rawData.HasMember(SLOT)) { int zOrder = 0; const auto& rawSlots = rawData[SLOT]; for (std::size_t i = 0, l = rawSlots.Size(); i < l; ++i) { armature->addSlot(_parseSlot(rawSlots[i], zOrder++)); } } if (rawData.HasMember(SKIN)) { const auto& rawSkins = rawData[SKIN]; for (std::size_t i = 0, l = rawSkins.Size(); i < l; ++i) { armature->addSkin(_parseSkin(rawSkins[i])); } } for (std::size_t i = 0, l = _cacheRawMeshes.size(); i < l; ++i) // Link mesh. { const auto rawMeshData = _cacheRawMeshes[i]; const auto& shareName = _getString(*rawMeshData, SHARE, ""); if (shareName.empty()) { continue; } auto skinName = _getString(*rawMeshData, SKIN, DEFAULT_NAME); if (skinName.empty()) // { skinName = DEFAULT_NAME; } const auto shareMesh = armature->getMesh(skinName, "", shareName); // TODO slot; if (shareMesh == nullptr) { continue; // Error. } const auto mesh = _cacheMeshes[i]; mesh->vertices.shareFrom(shareMesh->vertices); } if (rawData.HasMember(ANIMATION)) { const auto& rawAnimations = rawData[ANIMATION]; for (std::size_t i = 0, l = rawAnimations.Size(); i < l; ++i) { armature->addAnimation(_parseAnimation(rawAnimations[i])); } } if (rawData.HasMember(DEFAULT_ACTIONS)) { const auto& actions = _parseActionData(rawData[DEFAULT_ACTIONS], ActionType::Play, nullptr, nullptr); for (const auto action : actions) { armature->addAction(action, true); if (action->type == ActionType::Play) // Set default animation from default action. { const auto animation = armature->getAnimation(action->name); if (animation != nullptr) { armature->defaultAnimation = animation; } } } } if (rawData.HasMember(ACTIONS)) { const auto& actions = _parseActionData(rawData[ACTIONS], ActionType::Play, nullptr, nullptr); for (const auto action : actions) { armature->addAction(action, false); } } // Clear helper. _rawBones.clear(); _cacheRawMeshes.clear(); _cacheMeshes.clear(); _armature = nullptr; _weightSlotPose.clear(); _weightBonePoses.clear(); _cacheBones.clear(); _slotChildActions.clear(); return armature; } BoneData* JSONDataParser::_parseBone(const rapidjson::Value& rawData) { const auto bone = BaseObject::borrowObject(); bone->inheritTranslation = _getBoolean(rawData, INHERIT_TRANSLATION, true); bone->inheritRotation = _getBoolean(rawData, INHERIT_ROTATION, true); bone->inheritScale = _getBoolean(rawData, INHERIT_SCALE, true); bone->inheritReflection = _getBoolean(rawData, INHERIT_REFLECTION, true); bone->length = _getNumber(rawData, LENGTH, 0.0f) * _armature->scale; bone->name = _getString(rawData, NAME, ""); if (rawData.HasMember(TRANSFORM)) { _parseTransform(rawData[TRANSFORM], bone->transform, _armature->scale); } return bone; } ConstraintData* JSONDataParser::_parseIKConstraint(const rapidjson::Value& rawData) { const auto bone = _armature->getBone(_getString(rawData, BONE, "")); if (bone == nullptr) { return nullptr; } const auto target = _armature->getBone(_getString(rawData, TARGET, "")); if (target == nullptr) { return nullptr; } const auto constraint = BaseObject::borrowObject(); constraint->scaleEnabled = _getBoolean(rawData, SCALE, false); constraint->bendPositive = _getBoolean(rawData, BEND_POSITIVE, true); constraint->weight = _getNumber(rawData, WEIGHT, 1.0f); constraint->name = _getString(rawData, NAME, ""); constraint->bone = bone; constraint->target = target; const auto chain = _getNumber(rawData, CHAIN, (unsigned)0); if (chain > 0 && bone->parent != nullptr) { constraint->root = bone->parent; constraint->bone = bone; } else { constraint->root = bone; constraint->bone = nullptr; } return constraint; } SlotData* JSONDataParser::_parseSlot(const rapidjson::Value& rawData, int zOrder) { const auto slot = BaseObject::borrowObject(); slot->displayIndex = _getNumber(rawData, DISPLAY_INDEX, (int)0); slot->zOrder = zOrder; slot->name = _getString(rawData, NAME, ""); slot->parent = _armature->getBone(_getString(rawData, PARENT, "")); 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 (rawData.HasMember(COLOR)) { slot->color = SlotData::createColor(); _parseColorTransform(rawData[COLOR], *slot->color); } else { slot->color = &SlotData::DEFAULT_COLOR; } if (rawData.HasMember(ACTIONS)) { _slotChildActions[slot->name] = _parseActionData(rawData[ACTIONS], ActionType::Play, nullptr, nullptr); } return slot; } SkinData* JSONDataParser::_parseSkin(const rapidjson::Value& rawData) { const auto skin = BaseObject::borrowObject(); skin->name = _getString(rawData, NAME, DEFAULT_NAME); if (skin->name.empty()) { skin->name = DEFAULT_NAME; } if (rawData.HasMember(SLOT)) { const auto& rawSlots = rawData[SLOT]; _skin = skin; for (std::size_t i = 0, l = rawSlots.Size(); i < l; ++i) { const auto& rawSlot = rawSlots[i]; const auto& slotName = _getString(rawSlot, NAME, ""); const auto slot = _armature->getSlot(slotName); if (slot != nullptr) { _slot = slot; if (rawSlot.HasMember(DISPLAY)) { const auto& rawDisplays = rawSlot[DISPLAY]; for (std::size_t j = 0, lJ = rawDisplays.Size(); j < lJ; ++j) { const auto& rawDisplay = rawDisplays[j]; if (!rawDisplay.IsNull()) { skin->addDisplay(slotName, _parseDisplay(rawDisplay)); } else { skin->addDisplay(slotName, nullptr); } } } _slot = nullptr; } } _skin = nullptr; } return skin; } DisplayData* JSONDataParser::_parseDisplay(const rapidjson::Value& rawData) { const auto& name = _getString(rawData, NAME, ""); const auto& path = _getString(rawData, PATH, ""); auto type = DisplayType::Image; DisplayData* display = nullptr; if (rawData.HasMember(TYPE) && rawData[TYPE].IsString()) { type = _getDisplayType(rawData[TYPE].GetString()); } else { type = (DisplayType)_getNumber(rawData, TYPE, (int)DisplayType::Image); } switch (type) { case dragonBones::DisplayType::Image: { const auto imageDisplay = BaseObject::borrowObject(); imageDisplay->name = name; imageDisplay->path = !path.empty() ? path : name; _parsePivot(rawData, *imageDisplay); display = imageDisplay; break; } case dragonBones::DisplayType::Armature: { const auto armatureDisplay = BaseObject::borrowObject(); armatureDisplay->name = name; armatureDisplay->path = !path.empty() ? path : name; armatureDisplay->inheritAnimation = true; if (rawData.HasMember(ACTIONS)) { const auto& actions = _parseActionData(rawData[ACTIONS], ActionType::Play, nullptr, nullptr); for (const auto action : actions) { armatureDisplay->addAction(action); } } else if (_slotChildActions.find(_slot->name) != _slotChildActions.cend()) { const auto displays = _skin->getDisplays(_slot->name); if (displays == nullptr ? _slot->displayIndex == 0 : (std::size_t)_slot->displayIndex == displays->size()) { for (const auto action : _slotChildActions[_slot->name]) { armatureDisplay->addAction(action); } _slotChildActions.erase(_slotChildActions.find(_slot->name)); } } display = armatureDisplay; break; } case dragonBones::DisplayType::Mesh: { const auto meshDisplay = BaseObject::borrowObject(); meshDisplay->vertices.inheritDeform = _getBoolean(rawData, INHERIT_DEFORM, true); meshDisplay->name = name; meshDisplay->path = !path.empty() ? path : name; meshDisplay->vertices.data = _data; if (rawData.HasMember(SHARE)) { _cacheRawMeshes.push_back(&rawData); _cacheMeshes.push_back(meshDisplay); } else { _parseMesh(rawData, *meshDisplay); } display = meshDisplay; break; } case dragonBones::DisplayType::BoundingBox: { const auto boundingBox = _parseBoundingBox(rawData); if (boundingBox != nullptr) { const auto boundingBoxDisplay = BaseObject::borrowObject(); boundingBoxDisplay->name = name; boundingBoxDisplay->path = !path.empty() ? path : name; boundingBoxDisplay->boundingBox = boundingBox; display = boundingBoxDisplay; } break; } } if (display != nullptr && rawData.HasMember(TRANSFORM)) { _parseTransform(rawData[TRANSFORM], display->transform, _armature->scale); } return display; } void JSONDataParser::_parsePivot(const rapidjson::Value& rawData, ImageDisplayData& display) { if (rawData.HasMember(PIVOT)) { const auto& rawPivot = rawData[PIVOT]; display.pivot.x = _getNumber(rawPivot, X, 0.0f); display.pivot.y = _getNumber(rawPivot, Y, 0.0f); } else { display.pivot.x = 0.5f; display.pivot.y = 0.5f; } } void JSONDataParser::_parseMesh(const rapidjson::Value& rawData, MeshDisplayData& mesh) { const auto& rawVertices = rawData[VERTICES]; const auto& rawUVs = rawData[UVS]; const auto& rawTriangles = rawData[TRIANGLES]; const auto vertexCount = rawVertices.Size() / 2; const auto triangleCount = rawTriangles.Size() / 3; const auto vertexOffset = _floatArray.size(); const auto uvOffset = vertexOffset + vertexCount * 2; const auto meshOffset = _intArray.size(); const auto meshName = _skin->name + "_" + _slot->name + "_" + mesh.name; // Cache pose data. mesh.vertices.offset = meshOffset; _intArray.resize(_intArray.size() + 1 + 1 + 1 + 1 + triangleCount * 3); _intArray[meshOffset + (unsigned)BinaryOffset::MeshVertexCount] = vertexCount; _intArray[meshOffset + (unsigned)BinaryOffset::MeshTriangleCount] = triangleCount; _intArray[meshOffset + (unsigned)BinaryOffset::MeshFloatOffset] = vertexOffset; for (std::size_t i = 0, l = triangleCount * 3; i < l; ++i) { _intArray[meshOffset + (unsigned)BinaryOffset::MeshVertexIndices + i] = rawTriangles[i].GetUint(); } _floatArray.resize(_floatArray.size() + vertexCount * 2 + vertexCount * 2); for (std::size_t i = 0, l = vertexCount * 2; i < l; ++i) { _floatArray[vertexOffset + i] = rawVertices[i].GetDouble(); _floatArray[uvOffset + i] = rawUVs[i].GetDouble(); } if (rawData.HasMember(WEIGHTS)) { const auto& rawWeights = rawData[WEIGHTS]; const auto& rawSlotPose = rawData[SLOT_POSE]; const auto& rawBonePoses = rawData[BONE_POSE]; const auto& sortedBones = _armature->sortedBones; std::vector weightBoneIndices; const unsigned weightBoneCount = rawBonePoses.Size() / 7; const auto floatOffset = _floatArray.size(); const auto weightCount = (rawWeights.Size() - vertexCount) / 2; // uint const auto weightOffset = _intArray.size(); const auto weight = BaseObject::borrowObject(); weight->count = weightCount; weight->offset = weightOffset; weightBoneIndices.resize(weightBoneCount); _intArray.resize(_intArray.size() + 1 + 1 + weightBoneCount + vertexCount + weightCount); _intArray[weightOffset + (unsigned)BinaryOffset::WeigthFloatOffset] = floatOffset; for (std::size_t i = 0; i < weightBoneCount; ++i) { const auto rawBoneIndex = rawBonePoses[i * 7].GetUint(); const auto bone = _rawBones[rawBoneIndex]; weight->addBone(bone); weightBoneIndices[i] = rawBoneIndex; _intArray[weightOffset + (unsigned)BinaryOffset::WeigthBoneIndices + i] = indexOf(sortedBones, bone); } _floatArray.resize(_floatArray.size() + weightCount * 3); _helpMatrixA.a = rawSlotPose[0].GetDouble(); _helpMatrixA.b = rawSlotPose[1].GetDouble(); _helpMatrixA.c = rawSlotPose[2].GetDouble(); _helpMatrixA.d = rawSlotPose[3].GetDouble(); _helpMatrixA.tx = rawSlotPose[4].GetDouble(); _helpMatrixA.ty = rawSlotPose[5].GetDouble(); for (std::size_t i = 0, iW = 0, iB = weightOffset + (unsigned)BinaryOffset::WeigthBoneIndices + weightBoneCount, iV = floatOffset; i < vertexCount; ++i) { const auto iD = i * 2; const auto vertexBoneCount = rawWeights[iW++].GetUint(); _intArray[iB++] = vertexBoneCount; auto x = _floatArray[vertexOffset + iD]; auto y = _floatArray[vertexOffset + iD + 1]; _helpMatrixA.transformPoint(x, y, _helpPoint); x = _helpPoint.x; y = _helpPoint.y; for (std::size_t j = 0; j < vertexBoneCount; ++j) { const auto rawBoneIndex = rawWeights[iW++].GetUint(); const auto boneIndex = indexOf(weightBoneIndices, rawBoneIndex); const auto matrixOffset = boneIndex * 7 + 1; _helpMatrixB.a = rawBonePoses[matrixOffset + 0].GetDouble(); _helpMatrixB.b = rawBonePoses[matrixOffset + 1].GetDouble(); _helpMatrixB.c = rawBonePoses[matrixOffset + 2].GetDouble(); _helpMatrixB.d = rawBonePoses[matrixOffset + 3].GetDouble(); _helpMatrixB.tx = rawBonePoses[matrixOffset + 4].GetDouble(); _helpMatrixB.ty = rawBonePoses[matrixOffset + 5].GetDouble(); _helpMatrixB.invert(); _helpMatrixB.transformPoint(x, y, _helpPoint); _intArray[iB++] = boneIndex; _floatArray[iV++] = rawWeights[iW++].GetDouble(); _floatArray[iV++] = _helpPoint.x; _floatArray[iV++] = _helpPoint.y; } } mesh.vertices.weight = weight; _weightSlotPose[meshName] = &rawSlotPose; _weightBonePoses[meshName] = &rawBonePoses; } } BoundingBoxData* JSONDataParser::_parseBoundingBox(const rapidjson::Value& rawData) { BoundingBoxData* boundingBox = nullptr; BoundingBoxType type = BoundingBoxType::Rectangle; if (rawData.HasMember(SUB_TYPE) && rawData[SUB_TYPE].IsString()) { type = _getBoundingBoxType(rawData[SUB_TYPE].GetString()); } else { type = (BoundingBoxType)_getNumber(rawData, SUB_TYPE, (int)type); } switch (type) { case BoundingBoxType::Rectangle: boundingBox = BaseObject::borrowObject(); break; case BoundingBoxType::Ellipse: boundingBox = BaseObject::borrowObject(); break; case BoundingBoxType::Polygon: boundingBox = _parsePolygonBoundingBox(rawData); break; } if (boundingBox != nullptr) { boundingBox->color = _getNumber(rawData, COLOR, 0x000000); if (boundingBox->type == BoundingBoxType::Rectangle || boundingBox->type == BoundingBoxType::Ellipse) { boundingBox->width = _getNumber(rawData, WIDTH, 0.0f); boundingBox->height = _getNumber(rawData, HEIGHT, 0.0f); } } return boundingBox; } PolygonBoundingBoxData* JSONDataParser::_parsePolygonBoundingBox(const rapidjson::Value& rawData) { const auto polygonBoundingBox = BaseObject::borrowObject(); if (rawData.HasMember(VERTICES)) { const auto& rawVertices = rawData[VERTICES]; auto& vertices = polygonBoundingBox->vertices; polygonBoundingBox->vertices.resize(rawVertices.Size()); for (std::size_t i = 0, l = rawVertices.Size(); i < l; i += 2) { const auto x = rawVertices[i].GetDouble(); const auto y = rawVertices[i + 1].GetDouble(); vertices[i] = x; vertices[i + 1] = y; // AABB. if (i == 0) { polygonBoundingBox->x = x; polygonBoundingBox->y = y; polygonBoundingBox->width = x; polygonBoundingBox->height = y; } else { if (x < polygonBoundingBox->x) { polygonBoundingBox->x = x; } else if (x > polygonBoundingBox->width) { polygonBoundingBox->width = x; } if (y < polygonBoundingBox->y) { polygonBoundingBox->y = y; } else if (y > polygonBoundingBox->height) { polygonBoundingBox->height = y; } } } polygonBoundingBox->width -= polygonBoundingBox->x; polygonBoundingBox->height -= polygonBoundingBox->y; } else { DRAGONBONES_ASSERT(false, "Data error.\n Please reexport DragonBones Data to fixed the bug."); } return polygonBoundingBox; } AnimationData* JSONDataParser::_parseAnimation(const rapidjson::Value& rawData) { const auto animation = BaseObject::borrowObject(); animation->frameCount = std::max(_getNumber(rawData, DURATION, (unsigned)1), (unsigned)1); animation->playTimes = _getNumber(rawData, PLAY_TIMES, (unsigned)1); animation->duration = (float)animation->frameCount / _armature->frameRate; // float animation->fadeInTime = _getNumber(rawData, FADE_IN_TIME, 0.0f); animation->scale = _getNumber(rawData, SCALE, 1.0f); animation->name = _getString(rawData, NAME, DEFAULT_NAME); if (animation->name.empty()) { animation->name = DEFAULT_NAME; } animation->frameIntOffset = _frameIntArray.size(); animation->frameFloatOffset = _frameFloatArray.size(); animation->frameOffset = _frameArray.size(); _animation = animation; if (rawData.HasMember(FRAME)) { const auto& rawFrames = rawData[FRAME]; const auto keyFrameCount = rawFrames.Size(); if (keyFrameCount > 0) { for (std::size_t i = 0, frameStart = 0; i < keyFrameCount; ++i) { const auto& rawFrame = rawFrames[i]; _parseActionDataInFrame(rawFrame, frameStart, nullptr, nullptr); frameStart += _getNumber(rawFrame, DURATION, (unsigned)1); } } } if (rawData.HasMember(Z_ORDER)) { _animation->zOrderTimeline = _parseTimeline(rawData[Z_ORDER], FRAME, TimelineType::ZOrder, false, false, 0, std::bind(&JSONDataParser::_parseZOrderFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); } if (rawData.HasMember(BONE)) { const auto& rawTimelines = rawData[BONE]; for (std::size_t i = 0, l = rawTimelines.Size(); i < l; ++i) { _parseBoneTimeline(rawTimelines[i]); } } if (rawData.HasMember(SLOT)) { const auto& rawTimelines = rawData[SLOT]; for (std::size_t i = 0, l = rawTimelines.Size(); i < l; ++i) { _parseSlotTimeline(rawTimelines[i]); } } if (rawData.HasMember(FFD)) { const auto& rawTimelines = rawData[FFD]; for (std::size_t i = 0, l = rawTimelines.Size(); i < l; ++i) { const auto& rawTimeline = rawTimelines[i]; auto skinName = _getString(rawTimeline, SKIN, DEFAULT_NAME); const auto& slotName = _getString(rawTimeline, SLOT, ""); const auto& displayName = _getString(rawTimeline, NAME, ""); if (skinName.empty()) // { skinName = DEFAULT_NAME; } _slot = _armature->getSlot(slotName); _mesh = _armature->getMesh(skinName, slotName, displayName); if (_slot == nullptr || _mesh == nullptr) { continue; } const auto timeline = _parseTimeline(rawTimeline, FRAME, TimelineType::SlotDeform, false, true, 0, std::bind(&JSONDataParser::_parseSlotFFDFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); if (timeline != nullptr) { _animation->addSlotTimeline(_slot, timeline); } _slot = nullptr; _mesh = nullptr; } } if (rawData.HasMember(IK)) { const auto& rawTimelines = rawData[IK]; for (std::size_t i = 0, l = rawTimelines.Size(); i < l; ++i) { const auto& rawTimeline = rawTimelines[i]; const auto& constraintName = _getString(rawTimeline, NAME, ""); const auto constraint = _armature->getConstraint(constraintName); if (constraint == nullptr) { continue; } const auto timeline = _parseTimeline(rawTimeline, FRAME, TimelineType::IKConstraint, true, false, 2, std::bind(&JSONDataParser::_parseIKConstraintFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); if (timeline != nullptr) { _animation->addConstraintTimeline(constraint, timeline); } } } if (_actionFrames.size() > 0) { std::sort(_actionFrames.begin(), _actionFrames.end()); const auto timeline = _animation->actionTimeline = BaseObject::borrowObject(); const auto keyFrameCount = _actionFrames.size(); timeline->type = TimelineType::Action; timeline->offset = _timelineArray.size(); _timelineArray.resize(_timelineArray.size() + 1 + 1 + 1 + 1 + 1 + keyFrameCount); _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineScale] = 100; _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineOffset] = 0; _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineKeyFrameCount] = keyFrameCount; _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineFrameValueCount] = 0; _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineFrameValueOffset] = 0; _timeline = timeline; if (keyFrameCount == 1) { timeline->frameIndicesOffset = -1; _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineFrameOffset + 0] = _parseCacheActionFrame(_actionFrames[0]) - _animation->frameOffset; } else { const auto totalFrameCount = _animation->frameCount + 1; // One more frame than animation. auto& frameIndices = _data->frameIndices; timeline->frameIndicesOffset = frameIndices.size(); frameIndices.resize(frameIndices.size() + totalFrameCount); for (std::size_t i = 0, iK = 0, frameStart = 0, frameCount = 0; i < totalFrameCount; ++i) { if (frameStart + frameCount <= i && iK < keyFrameCount) { auto& frame = _actionFrames[iK]; frameStart = frame.frameStart; if (iK == keyFrameCount - 1) { frameCount = _animation->frameCount - frameStart; } else { frameCount = _actionFrames[iK + 1].frameStart - frameStart; } _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineFrameOffset + iK] = _parseActionFrame(frame, frameStart, frameCount) - _animation->frameOffset; iK++; } frameIndices[timeline->frameIndicesOffset + i] = iK - 1; } } _timeline = nullptr; _actionFrames.clear(); } _animation = nullptr; return animation; } TimelineData* JSONDataParser::_parseTimeline( const rapidjson::Value& rawData, const char* framesKey, TimelineType type, bool addIntOffset, bool addFloatOffset, unsigned frameValueCount, const std::function& frameParser) { if (!rawData.HasMember(framesKey)) { return nullptr; } const auto& rawFrames = rawData[framesKey]; const auto keyFrameCount = rawFrames.Size(); if (keyFrameCount == 0) { return nullptr; } const auto timeline = BaseObject::borrowObject(); timeline->type = type; timeline->offset = _timelineArray.size(); _timelineArray.resize(_timelineArray.size() + 1 + 1 + 1 + 1 + 1 + keyFrameCount); _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineScale] = _getNumber(rawData, SCALE, 1.0f) * 100.f; _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineOffset] = _getNumber(rawData, OFFSET, 0.0f) * 100.f; _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineKeyFrameCount] = keyFrameCount; _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineFrameValueCount] = frameValueCount; if (addIntOffset) { _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineFrameValueOffset] = _frameIntArray.size() - _animation->frameIntOffset; } else if (addFloatOffset) { _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineFrameValueOffset] = _frameFloatArray.size() - _animation->frameFloatOffset; } else { _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineFrameValueOffset] = 0; } _timeline = timeline; if (keyFrameCount == 1) // Only one frame. { timeline->frameIndicesOffset = -1; _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineFrameOffset + 0] = frameParser(rawFrames[0], 0, 0) - _animation->frameOffset; } else { unsigned frameIndicesOffset = 0; auto& frameIndices = _data->frameIndices; const auto totalFrameCount = _animation->frameCount + 1; // One more frame than animation. frameIndicesOffset = frameIndices.size(); frameIndices.resize(frameIndicesOffset + totalFrameCount); timeline->frameIndicesOffset = frameIndicesOffset; for (std::size_t i = 0, iK = 0, frameStart = 0, frameCount = 0; i < totalFrameCount; ++i) { if (frameStart + frameCount <= i && iK < keyFrameCount) { const auto& rawFrame = rawFrames[iK]; frameStart = i; frameCount = _getNumber(rawFrame, DURATION, (unsigned)1); if (iK == keyFrameCount - 1) { frameCount = _animation->frameCount - frameStart; } _timelineArray[timeline->offset + (unsigned)BinaryOffset::TimelineFrameOffset + iK] = frameParser(rawFrame, frameStart, frameCount) - _animation->frameOffset; iK++; } frameIndices[frameIndicesOffset + i] = iK - 1; } } _timeline = nullptr; return timeline; } void JSONDataParser::_parseBoneTimeline(const rapidjson::Value& rawData) { const auto bone = _armature->getBone(_getString(rawData, NAME, "")); if (bone == nullptr) { return; } _bone = bone; _slot = _armature->getSlot(_bone->name); if (rawData.HasMember(TRANSLATE_FRAME)) { const auto timeline = _parseTimeline(rawData, TRANSLATE_FRAME, TimelineType::BoneTranslate, false, true, 2, std::bind(&JSONDataParser::_parseBoneTranslateFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); if (timeline != nullptr) { _animation->addBoneTimeline(bone, timeline); } } if (rawData.HasMember(ROTATE_FRAME)) { const auto timeline = _parseTimeline(rawData, ROTATE_FRAME, TimelineType::BoneRotate, false, true, 2, std::bind(&JSONDataParser::_parseBoneRotateFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); if (timeline != nullptr) { _animation->addBoneTimeline(bone, timeline); } } if (rawData.HasMember(SCALE_FRAME)) { const auto timeline = _parseTimeline(rawData, SCALE_FRAME, TimelineType::BoneScale, false, true, 2, std::bind(&JSONDataParser::_parseBoneScaleFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); if (timeline != nullptr) { _animation->addBoneTimeline(bone, timeline); } } if (rawData.HasMember(FRAME)) { const auto timeline = _parseTimeline(rawData, FRAME, TimelineType::BoneAll, false, true, 6, std::bind(&JSONDataParser::_parseBoneAllFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); if (timeline != nullptr) { _animation->addBoneTimeline(bone, timeline); } } _bone = nullptr; _slot = nullptr; } void JSONDataParser::_parseSlotTimeline(const rapidjson::Value& rawData) { const auto slot = _armature->getSlot(_getString(rawData, NAME, "")); if (slot == nullptr) { return; } TimelineData* displayTimeline = nullptr; TimelineData* colorTimeline = nullptr; _slot = slot; if (rawData.HasMember(DISPLAY_FRAME)) { displayTimeline = _parseTimeline(rawData, DISPLAY_FRAME, TimelineType::SlotDisplay, false, false, 0, std::bind(&JSONDataParser::_parseSlotDisplayFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); } else { displayTimeline = _parseTimeline(rawData, FRAME, TimelineType::SlotDisplay, false, false, 0, std::bind(&JSONDataParser::_parseSlotDisplayFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); } if (rawData.HasMember(COLOR_FRAME)) { colorTimeline = _parseTimeline(rawData, COLOR_FRAME, TimelineType::SlotColor, true, false, 1, std::bind(&JSONDataParser::_parseSlotColorFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); } else { colorTimeline = _parseTimeline(rawData, FRAME, TimelineType::SlotColor, true, false, 1, std::bind(&JSONDataParser::_parseSlotColorFrame, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); } if (displayTimeline != nullptr) { _animation->addSlotTimeline(slot, displayTimeline); } if (colorTimeline != nullptr) { _animation->addSlotTimeline(slot, colorTimeline); } _slot = nullptr; } unsigned JSONDataParser::_parseFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { const auto frameOffset = _frameArray.size(); _frameArray.resize(_frameArray.size() + 1); _frameArray[frameOffset + (unsigned)BinaryOffset::FramePosition] = frameStart; return frameOffset; } unsigned JSONDataParser::_parseTweenFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { const auto frameOffset = _parseFrame(rawData, frameStart, frameCount); if (frameCount > 0) { if (rawData.HasMember(CURVE)) { const auto sampleCount = frameCount + 1; _helpArray.resize(sampleCount); _samplingEasingCurve(rawData[CURVE], _helpArray); _frameArray.resize(_frameArray.size() + 1 + 1 + _helpArray.size()); _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenType] = (int)TweenType::Curve; _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenEasingOrCurveSampleCount] = sampleCount; for (std::size_t i = 0; i < sampleCount; ++i) { _frameArray[frameOffset + (unsigned)BinaryOffset::FrameCurveSamples + i] = _helpArray[i] * 10000.0f; } } else { const auto noTween = -2.0f; auto tweenEasing = noTween; if (rawData.HasMember(TWEEN_EASING)) { tweenEasing = _getNumber(rawData, TWEEN_EASING, noTween); } if (tweenEasing == noTween) { _frameArray.resize(_frameArray.size() + 1); _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenType] = (int16_t)TweenType::None; } else if (tweenEasing == 0.0f) { _frameArray.resize(_frameArray.size() + 1); _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenType] = (int16_t)TweenType::Line; } else if (tweenEasing < 0.0f) { _frameArray.resize(_frameArray.size() + 1 + 1); _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenType] = (int16_t)TweenType::QuadIn; _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenEasingOrCurveSampleCount] = -tweenEasing * 100.0f; } else if (tweenEasing <= 1.0f) { _frameArray.resize(_frameArray.size() + 1 + 1); _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenType] = (int16_t)TweenType::QuadOut; _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenEasingOrCurveSampleCount] = tweenEasing * 100.0f; } else { _frameArray.resize(_frameArray.size() + 1 + 1); _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenType] = (int16_t)TweenType::QuadInOut; _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenEasingOrCurveSampleCount] = tweenEasing * 100.0f - 100.0f; } } } else { _frameArray.resize(_frameArray.size() + 1); _frameArray[frameOffset + (unsigned)BinaryOffset::FrameTweenType] = (int16_t)TweenType::None; } return frameOffset; } unsigned JSONDataParser::_parseActionFrame(const ActionFrame& frame, unsigned frameStart, unsigned frameCount) { const auto frameOffset = _frameArray.size(); const auto actionCount = frame.actions.size(); _frameArray.resize(_frameArray.size() + 1 + 1 + actionCount); _frameArray[frameOffset + (unsigned)BinaryOffset::FramePosition] = frameStart; _frameArray[frameOffset + (unsigned)BinaryOffset::FramePosition + 1] = actionCount; // Action count. for (std::size_t i = 0; i < actionCount; ++i) // Action offsets. { _frameArray[frameOffset + (unsigned)BinaryOffset::FramePosition + 2 + i] = frame.actions[i]; } return frameOffset; } unsigned JSONDataParser::_parseZOrderFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { const auto frameOffset = _parseFrame(rawData, frameStart, frameCount); if (rawData.HasMember(Z_ORDER)) { const auto& rawZOrder = rawData[Z_ORDER]; if (!rawZOrder.Empty()) { const auto slotCount = _armature->sortedSlots.size(); std::vector unchanged; std::vector zOrders; unchanged.resize(slotCount - rawZOrder.Size() / 2); zOrders.resize(slotCount); for (std::size_t i = 0; i < unchanged.size(); ++i) { unchanged[i] = 0; } for (std::size_t i = 0; i < slotCount; ++i) { zOrders[i] = -1; } unsigned originalIndex = 0; unsigned unchangedIndex = 0; for (std::size_t i = 0, l = rawZOrder.Size(); i < l; i += 2) { const auto slotIndex = rawZOrder[i].GetInt(); const auto zOrderOffset = rawZOrder[i + 1].GetInt(); while (originalIndex != (unsigned)slotIndex) { unchanged[unchangedIndex++] = originalIndex++; } unsigned index = originalIndex + zOrderOffset; zOrders[index] = originalIndex++; } while (originalIndex < slotCount) { unchanged[unchangedIndex++] = originalIndex++; } _frameArray.resize(_frameArray.size() + 1 + slotCount); _frameArray[frameOffset + 1] = slotCount; int i = slotCount; while (i--) { if (zOrders[i] == -1) { _frameArray[frameOffset + 2 + i] = unchanged[--unchangedIndex]; } else { _frameArray[frameOffset + 2 + i] = zOrders[i]; } } return frameOffset; } } _frameArray.resize(_frameArray.size() + 1); _frameArray[frameOffset + 1] = 0; return frameOffset; } unsigned JSONDataParser::_parseBoneAllFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { _helpTransform.identity(); if (rawData.HasMember(TRANSFORM)) { _parseTransform(rawData[TRANSFORM], _helpTransform, 1.0f); } // Modify rotation. auto rotation = _helpTransform.rotation; if (frameStart != 0) { if (_prevClockwise == 0) { rotation = _prevRotation + Transform::normalizeRadian(rotation - _prevRotation); } else { if (_prevClockwise > 0 ? rotation >= _prevRotation : rotation <= _prevRotation) { _prevClockwise = _prevClockwise > 0 ? _prevClockwise - 1 : _prevClockwise + 1; } rotation = _prevRotation + rotation - _prevRotation + Transform::PI_D * _prevClockwise; } } _prevClockwise = _getNumber(rawData, TWEEN_ROTATE, 0.0f); _prevRotation = rotation; // const auto frameOffset = _parseTweenFrame(rawData, frameStart, frameCount); auto frameFloatOffset = _frameFloatArray.size(); _frameFloatArray.resize(_frameFloatArray.size() + 6); _frameFloatArray[frameFloatOffset++] = _helpTransform.x; _frameFloatArray[frameFloatOffset++] = _helpTransform.y; _frameFloatArray[frameFloatOffset++] = rotation; _frameFloatArray[frameFloatOffset++] = _helpTransform.skew; _frameFloatArray[frameFloatOffset++] = _helpTransform.scaleX; _frameFloatArray[frameFloatOffset++] = _helpTransform.scaleY; _parseActionDataInFrame(rawData, frameStart, _bone, _slot); return frameOffset; } unsigned JSONDataParser::_parseBoneTranslateFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { const auto frameOffset = _parseTweenFrame(rawData, frameStart, frameCount); auto frameFloatOffset = _frameFloatArray.size(); _frameFloatArray.resize(_frameFloatArray.size() + 2); _frameFloatArray[frameFloatOffset++] = _getNumber(rawData, X, 0.0f); _frameFloatArray[frameFloatOffset++] = _getNumber(rawData, Y, 0.0f); return frameOffset; } unsigned JSONDataParser::_parseBoneRotateFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { // Modify rotation. auto rotation = _getNumber(rawData, ROTATE, 0.0f) * Transform::DEG_RAD; if (frameStart != 0) { if (_prevClockwise == 0) { rotation = _prevRotation + Transform::normalizeRadian(rotation - _prevRotation); } else { if (_prevClockwise > 0 ? rotation >= _prevRotation : rotation <= _prevRotation) { _prevClockwise = _prevClockwise > 0 ? _prevClockwise - 1 : _prevClockwise + 1; } rotation = _prevRotation + rotation - _prevRotation + Transform::PI_D * _prevClockwise; } } _prevClockwise = _getNumber(rawData, CLOCK_WISE, 0.0f); _prevRotation = rotation; // const auto frameOffset = _parseTweenFrame(rawData, frameStart, frameCount); auto frameFloatOffset = _frameFloatArray.size(); _frameFloatArray.resize(_frameFloatArray.size() + 2); _frameFloatArray[frameFloatOffset++] = rotation; _frameFloatArray[frameFloatOffset++] = _getNumber(rawData, SKEW, 0.0f) * Transform::DEG_RAD; return frameOffset; } unsigned JSONDataParser::_parseBoneScaleFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { const auto frameOffset = _parseTweenFrame(rawData, frameStart, frameCount); auto frameFloatOffset = _frameFloatArray.size(); _frameFloatArray.resize(_frameFloatArray.size() + 2); _frameFloatArray[frameFloatOffset++] = _getNumber(rawData, X, 1.0f); _frameFloatArray[frameFloatOffset++] = _getNumber(rawData, Y, 1.0f); return frameOffset; } unsigned JSONDataParser::_parseSlotDisplayFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { const auto frameOffset = _parseFrame(rawData, frameStart, frameCount); _frameArray.resize(_frameArray.size() + 1); if (rawData.HasMember(VALUE)) { _frameArray[frameOffset + 1] = _getNumber(rawData, VALUE, 0); } else { _frameArray[frameOffset + 1] = _getNumber(rawData, DISPLAY_INDEX, 0); } _parseActionDataInFrame(rawData, frameStart, _slot->parent, _slot); return frameOffset; } unsigned JSONDataParser::_parseSlotColorFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { const auto frameOffset = _parseTweenFrame(rawData, frameStart, frameCount); auto colorOffset = -1; if (rawData.HasMember(VALUE) || rawData.HasMember(COLOR)) { const auto& rawColor = rawData.HasMember(VALUE) ? rawData[VALUE] : rawData[COLOR]; if (rawColor.HasMember(ALPHA_MULTIPLIER) || rawColor.HasMember(RED_MULTIPLIER) || rawColor.HasMember(GREEN_MULTIPLIER) || rawColor.HasMember(BLUE_MULTIPLIER) || rawColor.HasMember(ALPHA_OFFSET) || rawColor.HasMember(RED_OFFSET) || rawColor.HasMember(GREEN_OFFSET) || rawColor.HasMember(BLUE_OFFSET)) { _parseColorTransform(rawColor, _helpColorTransform); colorOffset = _intArray.size(); _intArray.resize(_intArray.size() + 8); _intArray[colorOffset++] = _helpColorTransform.alphaMultiplier * 100; _intArray[colorOffset++] = _helpColorTransform.redMultiplier * 100; _intArray[colorOffset++] = _helpColorTransform.greenMultiplier * 100; _intArray[colorOffset++] = _helpColorTransform.blueMultiplier * 100; _intArray[colorOffset++] = _helpColorTransform.alphaOffset; _intArray[colorOffset++] = _helpColorTransform.redOffset; _intArray[colorOffset++] = _helpColorTransform.greenOffset; _intArray[colorOffset++] = _helpColorTransform.blueOffset; colorOffset -= 8; } } if (colorOffset < 0) { if (_defaultColorOffset < 0) { _defaultColorOffset = colorOffset = _intArray.size(); _intArray.resize(_intArray.size() + 8); _intArray[colorOffset++] = 100; _intArray[colorOffset++] = 100; _intArray[colorOffset++] = 100; _intArray[colorOffset++] = 100; _intArray[colorOffset++] = 0; _intArray[colorOffset++] = 0; _intArray[colorOffset++] = 0; _intArray[colorOffset++] = 0; } colorOffset = _defaultColorOffset; } const auto frameIntOffset = _frameIntArray.size(); _frameIntArray.resize(_frameIntArray.size() + 1); _frameIntArray[frameIntOffset] = colorOffset; return frameOffset; } unsigned JSONDataParser::_parseSlotFFDFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { const auto frameFloatOffset = _frameFloatArray.size(); const auto frameOffset = _parseTweenFrame(rawData, frameStart, frameCount); const auto offset = _getNumber(rawData, OFFSET, (unsigned)0); const auto vertexCount = (unsigned)_intArray[_mesh->vertices.offset + (unsigned)BinaryOffset::MeshVertexCount]; const auto meshName = _mesh->parent->name + "_" + _slot->name + "_" + _mesh->name; const auto weight = _mesh->vertices.weight; auto x = 0.0f; auto y = 0.0f; unsigned iB = 0; unsigned iV = 0; if (weight != nullptr) { const auto& rawSlotPose = *(_weightSlotPose[meshName]); _helpMatrixA.a = rawSlotPose[0].GetDouble(); _helpMatrixA.b = rawSlotPose[1].GetDouble(); _helpMatrixA.c = rawSlotPose[2].GetDouble(); _helpMatrixA.d = rawSlotPose[3].GetDouble(); _helpMatrixA.tx = rawSlotPose[4].GetDouble(); _helpMatrixA.ty = rawSlotPose[5].GetDouble(); _frameFloatArray.resize(_frameFloatArray.size() + weight->count * 2); iB = weight->offset + (unsigned)BinaryOffset::WeigthBoneIndices + weight->bones.size(); } else { _frameFloatArray.resize(_frameFloatArray.size() + vertexCount * 2); } for (std::size_t i = 0; i < vertexCount * 2; i += 2) { if (!rawData.HasMember(VERTICES)) // Fill 0. { x = 0.0f; y = 0.0f; } else { if (i < offset || i - offset >= rawData[VERTICES].Size()) { x = 0.0f; } else { x = rawData[VERTICES][i - offset].GetDouble(); } if (i + 1 < offset || i + 1 - offset >= rawData[VERTICES].Size()) { y = 0.0f; } else { y = rawData[VERTICES][i + 1 - offset].GetDouble(); } } if (weight != nullptr) // If mesh is skinned, transform point by bone bind pose. { const auto& rawBonePoses = *(_weightBonePoses[meshName]); const unsigned vertexBoneCount = _intArray[iB++]; _helpMatrixA.transformPoint(x, y, _helpPoint, true); x = _helpPoint.x; y = _helpPoint.y; for (std::size_t j = 0; j < vertexBoneCount; ++j) { const auto boneIndex = _intArray[iB++]; const auto matrixOffset = boneIndex * 7 + 1; _helpMatrixB.a = rawBonePoses[matrixOffset + 0].GetDouble(); _helpMatrixB.b = rawBonePoses[matrixOffset + 1].GetDouble(); _helpMatrixB.c = rawBonePoses[matrixOffset + 2].GetDouble(); _helpMatrixB.d = rawBonePoses[matrixOffset + 3].GetDouble(); _helpMatrixB.tx = rawBonePoses[matrixOffset + 4].GetDouble(); _helpMatrixB.ty = rawBonePoses[matrixOffset + 5].GetDouble(); _helpMatrixB.invert(); _helpMatrixB.transformPoint(x, y, _helpPoint, true); _frameFloatArray[frameFloatOffset + iV++] = _helpPoint.x; _frameFloatArray[frameFloatOffset + iV++] = _helpPoint.y; } } else { _frameFloatArray[frameFloatOffset + i] = x; _frameFloatArray[frameFloatOffset + i + 1] = y; } } if (frameStart == 0) { const auto frameIntOffset = _frameIntArray.size(); _frameIntArray.resize(_frameIntArray.size() + 1 + 1 + 1 + 1 + 1); _frameIntArray[frameIntOffset + (unsigned)BinaryOffset::DeformVertexOffset] = _mesh->vertices.offset; _frameIntArray[frameIntOffset + (unsigned)BinaryOffset::DeformCount] = _frameFloatArray.size() - frameFloatOffset; _frameIntArray[frameIntOffset + (unsigned)BinaryOffset::DeformValueCount] = _frameFloatArray.size() - frameFloatOffset; _frameIntArray[frameIntOffset + (unsigned)BinaryOffset::DeformValueOffset] = 0; _frameIntArray[frameIntOffset + (unsigned)BinaryOffset::DeformFloatOffset] = frameFloatOffset; _timelineArray[_timeline->offset + (unsigned)BinaryOffset::TimelineFrameValueCount] = frameIntOffset - _animation->frameIntOffset; } return frameOffset; } unsigned JSONDataParser::_parseIKConstraintFrame(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount) { const auto frameOffset = _parseTweenFrame(rawData, frameStart, frameCount); auto frameIntOffset = _frameIntArray.size(); _frameIntArray.resize(_frameIntArray.size() + 2); _frameIntArray[frameIntOffset++] = _getBoolean(rawData, BEND_POSITIVE, true) ? 1 : 0; _frameIntArray[frameIntOffset++] = round(_getNumber(rawData, WEIGHT, 1.0f) * 100.0f); return frameOffset; } const std::vector& JSONDataParser::_parseActionData(const rapidjson::Value& rawData, ActionType type, BoneData* bone, SlotData* slot) { static std::vector actions; actions.clear(); if (rawData.IsString()) { const auto action = BaseObject::borrowObject(); action->type = type; action->name = rawData.GetString(); action->bone = bone; action->slot = slot; actions.push_back(action); } else if (rawData.IsArray()) { for (std::size_t iA = 0, lA = rawData.Size(); iA < lA; ++iA) { const auto& rawAction = rawData[iA]; const auto action = BaseObject::borrowObject(); if (rawAction.HasMember(GOTO_AND_PLAY)) { action->type = ActionType::Play; action->name = _getString(rawAction, GOTO_AND_PLAY, ""); } else { if (rawAction.HasMember(TYPE) && rawAction[TYPE].IsString()) { action->type = _getActionType(rawAction[TYPE].GetString()); } else { action->type = (ActionType)_getNumber(rawAction, TYPE, (int)type); } action->name = _getString(rawAction, NAME, ""); } if (rawAction.HasMember(BONE)) { const auto& boneName = _getString(rawAction, BONE, ""); action->bone = _armature->getBone(boneName); } else { action->bone = bone; } if (rawAction.HasMember(SLOT)) { const auto& slotName = _getString(rawAction, SLOT, ""); action->slot = _armature->getSlot(slotName); } else { action->slot = slot; } if (rawAction.HasMember(INTS)) { if (action->data == nullptr) { action->data = BaseObject::borrowObject(); } const auto& rawInts = rawAction[INTS]; for (std::size_t i = 0, l = rawInts.Size(); i < l; ++i) { action->data->addInt(rawInts[i].GetInt()); } } if (rawAction.HasMember(FLOATS)) { if (action->data == nullptr) { action->data = BaseObject::borrowObject(); } const auto& rawFloats = rawAction[FLOATS]; for (std::size_t i = 0, l = rawFloats.Size(); i < l; ++i) { action->data->addFloat(rawFloats[i].GetDouble()); } } if (rawAction.HasMember(STRINGS)) { if (action->data == nullptr) { action->data = BaseObject::borrowObject(); } const auto& rawStrings = rawAction[STRINGS]; for (std::size_t i = 0, l = rawStrings.Size(); i < l; ++i) { action->data->addString(rawStrings[i].GetString()); } } actions.push_back(action); } } return actions; } void JSONDataParser::_parseTransform(const rapidjson::Value& rawData, Transform& transform, float scale) { transform.x = _getNumber(rawData, X, 0.0f) * scale; transform.y = _getNumber(rawData, Y, 0.0f) * scale; if (rawData.HasMember(ROTATE) || rawData.HasMember(SKEW)) { transform.rotation = Transform::normalizeRadian(_getNumber(rawData, ROTATE, 0.0f) * Transform::DEG_RAD); transform.skew = Transform::normalizeRadian(_getNumber(rawData, SKEW, 0.0f) * Transform::DEG_RAD); } else if (rawData.HasMember(SKEW_X) || rawData.HasMember(SKEW_Y)) { transform.rotation = Transform::normalizeRadian(_getNumber(rawData, SKEW_Y, 0.0f) * Transform::DEG_RAD); transform.skew = Transform::normalizeRadian(_getNumber(rawData, SKEW_X, 0.0f) * Transform::DEG_RAD) - transform.rotation; } transform.scaleX = _getNumber(rawData, SCALE_X, 1.0f); transform.scaleY = _getNumber(rawData, SCALE_Y, 1.0f); } void JSONDataParser::_parseColorTransform(const rapidjson::Value& rawData, ColorTransform& color) { 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); } void JSONDataParser::_parseArray(const rapidjson::Value& rawData) { _intArray.clear(); _floatArray.clear(); _frameIntArray.clear(); _frameFloatArray.clear(); _frameArray.clear(); _timelineArray.clear(); } DragonBonesData* JSONDataParser::_parseDragonBonesData(const rapidjson::Value& rawData, float scale) { const auto& version = _getString(rawData, VERSION, ""); const auto& compatibleVersion = _getString(rawData, COMPATIBLE_VERSION, ""); if (indexOf(DATA_VERSIONS, version) >= 0 || indexOf(DATA_VERSIONS, compatibleVersion) >= 0) { const auto data = BaseObject::borrowObject(); data->version = version; data->name = _getString(rawData, NAME, ""); data->frameRate = _getNumber(rawData, FRAME_RATE, 24); if (data->frameRate == 0) // Data error. { data->frameRate = 24; } if (rawData.HasMember(ARMATURE)) { _data = data; _parseArray(rawData); const auto& rawArmatures = rawData[ARMATURE]; for (std::size_t i = 0, l = rawArmatures.Size(); i < l; ++i) { data->addArmature(_parseArmature(rawArmatures[i], scale)); } if (data->binary == nullptr) { // Align. if (fmod(_intArray.size(), 2) != 0) { _intArray.push_back(0); } if (fmod(_frameIntArray.size(), 2) != 0) { _frameIntArray.push_back(0); } if (fmod(_frameArray.size(), 2) != 0) { _frameArray.push_back(0); } if (fmod(_timelineArray.size(), 2) != 0) { _timelineArray.push_back(0); } const auto l1 = _intArray.size() * 2; const auto l2 = _floatArray.size() * 4; const auto l3 = _frameIntArray.size() * 2; const auto l4 = _frameFloatArray.size() * 4; const auto l5 = _frameArray.size() * 2; const auto l6 = _timelineArray.size() * 2; auto binary = new char[l1 + l2 + l3 + l4 + l5 + l6]; auto intArray = (int16_t*)binary; auto floatArray = (float*)(binary + l1); auto frameIntArray = (int16_t*)(binary + l1 + l2); auto frameFloatArray = (float*)(binary + l1 + l2 + l3); auto frameArray = (int16_t*)(binary + l1 + l2 + l3 + l4); auto timelineArray = (uint16_t*)(binary + l1 + l2 + l3 + l4 + l5); for (std::size_t i = 0, l = _intArray.size(); i < l; ++i) { intArray[i] = _intArray[i]; } for (std::size_t i = 0, l = _floatArray.size(); i < l; ++i) { floatArray[i] = _floatArray[i]; } for (std::size_t i = 0, l = _frameIntArray.size(); i < l; ++i) { frameIntArray[i] = _frameIntArray[i]; } for (std::size_t i = 0, l = _frameFloatArray.size(); i < l; ++i) { frameFloatArray[i] = _frameFloatArray[i]; } for (std::size_t i = 0, l = _frameArray.size(); i < l; ++i) { frameArray[i] = _frameArray[i]; } for (std::size_t i = 0, l = _timelineArray.size(); i < l; ++i) { timelineArray[i] = _timelineArray[i]; } data->binary = binary; data->intArray = intArray; data->floatArray = floatArray; data->frameIntArray = frameIntArray; data->frameFloatArray = frameFloatArray; data->frameArray = frameArray; data->timelineArray = timelineArray; } _defaultColorOffset = -1; _data = nullptr; } if (rawData.HasMember(TEXTURE_ATLAS)) { _rawTextureAtlases = (rapidjson::Value*)&(rawData[TEXTURE_ATLAS]); } return data; } else { DRAGONBONES_ASSERT(false, "Nonsupport data version: " + version + "\n" + "Please convert DragonBones data to support version.\n" + "Read more: https://github.com/DragonBones/Tools/"); } return nullptr; } void JSONDataParser::_parseTextureAtlasData(const rapidjson::Value& rawData, TextureAtlasData& textureAtlasData, float scale) { textureAtlasData.format = _getTextureFormat(_getString(rawData, FORMAT, "")); textureAtlasData.width = _getNumber(rawData, WIDTH, (unsigned)0); textureAtlasData.height = _getNumber(rawData, HEIGHT, (unsigned)0); textureAtlasData.scale = scale == 1.0f ? 1.0f / _getNumber(rawData, SCALE, 1.0f) : scale; textureAtlasData.name = _getString(rawData, NAME, ""); textureAtlasData.imagePath = _getString(rawData, IMAGE_PATH, ""); if (rawData.HasMember(SUB_TEXTURE)) { const auto& rawTextures = rawData[SUB_TEXTURE]; for (std::size_t i = 0, l = rawTextures.Size(); i < l; ++i) { const auto& rawTexture = rawTextures[i]; const auto textureData = textureAtlasData.createTexture(); textureData->rotated = _getBoolean(rawTexture, ROTATED, false); textureData->name = _getString(rawTexture, NAME, ""); textureData->region.x = _getNumber(rawTexture, X, 0.0f); textureData->region.y = _getNumber(rawTexture, Y, 0.0f); textureData->region.width = _getNumber(rawTexture, WIDTH, 0.0f); textureData->region.height = _getNumber(rawTexture, HEIGHT, 0.0f); const auto frameWidth = _getNumber(rawTexture, FRAME_WIDTH, -1.0f); const auto frameHeight = _getNumber(rawTexture, FRAME_HEIGHT, -1.0f); if (frameWidth > 0.0f && frameHeight > 0.0f) { textureData->frame = TextureData::createRectangle(); textureData->frame->x = _getNumber(rawTexture, FRAME_X, 0.0f); textureData->frame->y = _getNumber(rawTexture, FRAME_Y, 0.0f); textureData->frame->width = frameWidth; textureData->frame->height = frameHeight; } textureAtlasData.addTexture(textureData); } } } DragonBonesData* JSONDataParser::parseDragonBonesData(const char* rawData, float scale) { DRAGONBONES_ASSERT(rawData != nullptr, ""); rapidjson::Document document; document.Parse(rawData); return _parseDragonBonesData(document, scale); } bool JSONDataParser::parseTextureAtlasData(const char* rawData, TextureAtlasData& textureAtlasData, float scale) { if (rawData == nullptr) { if (_rawTextureAtlases == nullptr || _rawTextureAtlases->Empty()) { return false; } const auto& rawTextureAtlas = (*_rawTextureAtlases)[_rawTextureAtlasIndex++]; _parseTextureAtlasData(rawTextureAtlas, textureAtlasData, scale); if (_rawTextureAtlasIndex >= _rawTextureAtlases->Size()) { _rawTextureAtlasIndex = 0; _rawTextureAtlases = nullptr; } return true; } rapidjson::Document document; document.Parse(rawData); _parseTextureAtlasData(document, textureAtlasData, scale); return true; } DRAGONBONES_NAMESPACE_END