mirror of https://github.com/axmolengine/axmol.git
2038 lines
70 KiB
C++
2038 lines
70 KiB
C++
|
#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<float>& 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<ArmatureData>();
|
||
|
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<CanvasData>();
|
||
|
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<BoneData>();
|
||
|
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<IKConstraintData>();
|
||
|
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<SlotData>();
|
||
|
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<SkinData>();
|
||
|
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<ImageDisplayData>();
|
||
|
imageDisplay->name = name;
|
||
|
imageDisplay->path = !path.empty() ? path : name;
|
||
|
_parsePivot(rawData, *imageDisplay);
|
||
|
|
||
|
display = imageDisplay;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case dragonBones::DisplayType::Armature:
|
||
|
{
|
||
|
const auto armatureDisplay = BaseObject::borrowObject<ArmatureDisplayData>();
|
||
|
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<MeshDisplayData>();
|
||
|
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<BoundingBoxDisplayData>();
|
||
|
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<unsigned> 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<WeightData>();
|
||
|
|
||
|
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<RectangleBoundingBoxData>();
|
||
|
break;
|
||
|
|
||
|
case BoundingBoxType::Ellipse:
|
||
|
boundingBox = BaseObject::borrowObject<EllipseBoundingBoxData>();
|
||
|
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<PolygonBoundingBoxData>();
|
||
|
|
||
|
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<AnimationData>();
|
||
|
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<TimelineData>();
|
||
|
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<unsigned(const rapidjson::Value& rawData, unsigned frameStart, unsigned frameCount)>& 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<TimelineData>();
|
||
|
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<int> unchanged;
|
||
|
std::vector<int> 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<ActionData*>& JSONDataParser::_parseActionData(const rapidjson::Value& rawData, ActionType type, BoneData* bone, SlotData* slot)
|
||
|
{
|
||
|
static std::vector<ActionData*> actions;
|
||
|
actions.clear();
|
||
|
|
||
|
if (rawData.IsString())
|
||
|
{
|
||
|
const auto action = BaseObject::borrowObject<ActionData>();
|
||
|
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<ActionData>();
|
||
|
|
||
|
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<UserData>();
|
||
|
}
|
||
|
|
||
|
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<UserData>();
|
||
|
}
|
||
|
|
||
|
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<UserData>();
|
||
|
}
|
||
|
|
||
|
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<DragonBonesData>();
|
||
|
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
|