diff --git a/spine-cpp/spine-cpp/include/spine/SkeletonBinary.h b/spine-cpp/spine-cpp/include/spine/SkeletonBinary.h index 88af8bd77..af27cb47f 100644 --- a/spine-cpp/spine-cpp/include/spine/SkeletonBinary.h +++ b/spine-cpp/spine-cpp/include/spine/SkeletonBinary.h @@ -45,26 +45,38 @@ namespace spine { class Attachment; class VertexAttachment; class Animation; + class Timeline; class CurveTimeline; + class CurveTimeline1; + class CurveTimeline2; class SP_API SkeletonBinary : public SpineObject { public: - static const int BONE_ROTATE; - static const int BONE_TRANSLATE; - static const int BONE_SCALE; - static const int BONE_SHEAR; + static const int BONE_ROTATE = 0; + static const int BONE_TRANSLATE = 1; + static const int BONE_TRANSLATEX = 2; + static const int BONE_TRANSLATEY = 3; + static const int BONE_SCALE = 4; + static const int BONE_SCALEX = 5; + static const int BONE_SCALEY = 6; + static const int BONE_SHEAR = 7; + static const int BONE_SHEARX = 8; + static const int BONE_SHEARY = 9; - static const int SLOT_ATTACHMENT; - static const int SLOT_COLOR; - static const int SLOT_TWO_COLOR; + static const int SLOT_ATTACHMENT = 0; + static const int SLOT_RGBA = 1; + static const int SLOT_RGB = 2; + static const int SLOT_RGBA2 = 3; + static const int SLOT_RGB2 = 4; + static const int SLOT_ALPHA = 5; - static const int PATH_POSITION; - static const int PATH_SPACING; - static const int PATH_MIX; + static const int PATH_POSITION = 0; + static const int PATH_SPACING = 1; + static const int PATH_MIX = 2; - static const int CURVE_LINEAR; - static const int CURVE_STEPPED; - static const int CURVE_BEZIER; + static const int CURVE_LINEAR = 0; + static const int CURVE_STEPPED = 1; + static const int CURVE_BEZIER = 2; explicit SkeletonBinary(Atlas* atlasArray); @@ -124,7 +136,12 @@ namespace spine { Animation* readAnimation(const String& name, DataInput* input, SkeletonData *skeletonData); - void readCurve(DataInput* input, int frameIndex, CurveTimeline* timeline); + void setBezier(DataInput* input, CurveTimeline* timeline, int bezier, int frame, int value, float time1, float time2, + float value1, float value2, float scale); + + Timeline *readTimeline (DataInput *input, CurveTimeline1 *timeline, float scale); + + Timeline *readTimeline2 (DataInput *input, CurveTimeline2 *timeline, float scale); }; } diff --git a/spine-cpp/spine-cpp/include/spine/TwoColorTimeline.h b/spine-cpp/spine-cpp/include/spine/TwoColorTimeline.h deleted file mode 100644 index 6cc110418..000000000 --- a/spine-cpp/spine-cpp/include/spine/TwoColorTimeline.h +++ /dev/null @@ -1,80 +0,0 @@ -/****************************************************************************** - * Spine Runtimes License Agreement - * Last updated January 1, 2020. Replaces all prior versions. - * - * Copyright (c) 2013-2020, Esoteric Software LLC - * - * Integration of the Spine Runtimes into software or otherwise creating - * derivative works of the Spine Runtimes is permitted under the terms and - * conditions of Section 2 of the Spine Editor License Agreement: - * http://esotericsoftware.com/spine-editor-license - * - * Otherwise, it is permitted to integrate the Spine Runtimes into software - * or otherwise create derivative works of the Spine Runtimes (collectively, - * "Products"), provided that each user of the Products must obtain their own - * Spine Editor license and redistribution of the Products in any form must - * include this license and copyright notice. - * - * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, - * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#ifndef Spine_TwoColorTimeline_h -#define Spine_TwoColorTimeline_h - -#include - -namespace spine { - - class SP_API TwoColorTimeline : public CurveTimeline { - friend class SkeletonBinary; - friend class SkeletonJson; - - RTTI_DECL - - public: - static const int ENTRIES; - - explicit TwoColorTimeline(int frameCount); - - virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector* pEvents, float alpha, MixBlend blend, MixDirection direction); - - virtual int getPropertyId(); - - /// Sets the time and value of the specified keyframe. - void setFrame(int frameIndex, float time, float r, float g, float b, float a, float r2, float g2, float b2); - - int getSlotIndex(); - void setSlotIndex(int inValue); - - private: - static const int PREV_TIME; - static const int PREV_R; - static const int PREV_G; - static const int PREV_B; - static const int PREV_A; - static const int PREV_R2; - static const int PREV_G2; - static const int PREV_B2; - static const int R; - static const int G; - static const int B; - static const int A; - static const int R2; - static const int G2; - static const int B2; - - Vector _frames; // time, r, g, b, a, r2, g2, b2, ... - int _slotIndex; - }; -} - -#endif /* Spine_TwoColorTimeline_h */ diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp index f26398a77..db96bc812 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp @@ -59,7 +59,6 @@ #include #include #include -#include #include #include #include @@ -76,23 +75,6 @@ using namespace spine; -const int SkeletonBinary::BONE_ROTATE = 0; -const int SkeletonBinary::BONE_TRANSLATE = 1; -const int SkeletonBinary::BONE_SCALE = 2; -const int SkeletonBinary::BONE_SHEAR = 3; - -const int SkeletonBinary::SLOT_ATTACHMENT = 0; -const int SkeletonBinary::SLOT_COLOR = 1; -const int SkeletonBinary::SLOT_TWO_COLOR = 2; - -const int SkeletonBinary::PATH_POSITION = 0; -const int SkeletonBinary::PATH_SPACING = 1; -const int SkeletonBinary::PATH_MIX = 2; - -const int SkeletonBinary::CURVE_LINEAR = 0; -const int SkeletonBinary::CURVE_STEPPED = 1; -const int SkeletonBinary::CURVE_BEZIER = 2; - SkeletonBinary::SkeletonBinary(Atlas *atlasArray) : _attachmentLoader( new(__FILE__, __LINE__) AtlasAttachmentLoader(atlasArray)), _error(), _scale(1), _ownsLoader(true) { @@ -123,17 +105,18 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons skeletonData = new(__FILE__, __LINE__) SkeletonData(); - char *skeletonData_hash = readString(input); - skeletonData->_hash.own(skeletonData_hash); + char buffer[8] = { 0 }; + int lowHash = readInt(input); + int hightHash = readInt(input); + String hashString; + sprintf(buffer, "%x", hightHash); + hashString.append(buffer); + sprintf(buffer, "%x", lowHash); + hashString.append(buffer); + skeletonData->_hash = hashString; - char *skeletonData_version = readString(input); - skeletonData->_version.own(skeletonData_version); - if ("3.8.75" == skeletonData->_version) { - delete input; - delete skeletonData; - setError("Unsupported skeleton data, please export with a newer version of Spine.", ""); - return NULL; - } + char *skeletonDataVersion = readString(input); + skeletonData->_version.own(skeletonDataVersion); skeletonData->_x = readFloat(input); skeletonData->_y = readFloat(input); @@ -239,10 +222,12 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons data->_offsetScaleX = readFloat(input); data->_offsetScaleY = readFloat(input); data->_offsetShearY = readFloat(input); - data->_rotateMix = readFloat(input); - data->_translateMix = readFloat(input); - data->_scaleMix = readFloat(input); - data->_shearMix = readFloat(input); + data->_mixRotate = readFloat(input); + data->_mixX = readFloat(input); + data->_mixY = readFloat(input); + data->_mixScaleX = readFloat(input); + data->_mixScaleY = readFloat(input); + data->_mixShearY = readFloat(input); skeletonData->_transformConstraints[i] = data; } @@ -268,8 +253,9 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons data->_spacing = readFloat(input); if (data->_spacingMode == SpacingMode_Length || data->_spacingMode == SpacingMode_Fixed) data->_spacing *= _scale; - data->_rotateMix = readFloat(input); - data->_translateMix = readFloat(input); + data->_mixRotate = readFloat(input); + data->_mixX = readFloat(input); + data->_mixY = readFloat(input); skeletonData->_pathConstraints[i] = data; } @@ -700,69 +686,276 @@ void SkeletonBinary::readShortArray(DataInput *input, Vector &ar } } +void SkeletonBinary::setBezier(DataInput* input, CurveTimeline* timeline, int bezier, int frame, int value, float time1, float time2, + float value1, float value2, float scale) { + float cx1 = readFloat(input); + float cy1 = readFloat(input); + float cx2 = readFloat(input); + float cy2 = readFloat(input); + timeline->setBezier(bezier, frame, value, time1, value1, cx1, cy1 * scale, cx2, cy2 * scale, time2, value2); +} + +Timeline *SkeletonBinary::readTimeline (DataInput *input, CurveTimeline1 *timeline, float scale) { + float time = readFloat(input); + float value = readFloat(input) * scale; + for (int frame = 0, bezier = 0, frameLast = timeline->getFrameCount() - 1;; frame++) { + timeline->setFrame(frame, time, value); + if (frame == frameLast) break; + float time2 = readFloat(input); + float value2 = readFloat(input) * scale; + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, value, value2, 1); + } + time = time2; + value = value2; + } + return timeline; +} + +Timeline *SkeletonBinary::readTimeline2 (DataInput *input, CurveTimeline2 *timeline, float scale) { + float time = readFloat(input); + float value1 = readFloat(input) * scale; + float value2 = readFloat(input) * scale; + for (int frame = 0, bezier = 0, frameLast = timeline->getFrameCount() - 1;; frame++) { + timeline->setFrame(frame, time, value1, value2); + if (frame == frameLast) break; + float time2 = readFloat(input); + float nvalue1 = readFloat(input) * scale; + float nvalue2 = readFloat(input) * scale; + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, value1, nvalue1, scale); + setBezier(input, timeline, bezier++, frame, 1, time, time2, value2, nvalue2, scale); + } + time = time2; + value1 = nvalue1; + value2 = nvalue2; + } + return timeline; +} + Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, SkeletonData *skeletonData) { Vector timelines; float scale = _scale; - float duration = 0; - + int numTimelines = readVarint(input, true); // Slot timelines. - for (int i = 0, n = readVarint(input, true); i < n; ++i) { + for (int i = 0, n = numTimelines; i < n; ++i) { int slotIndex = readVarint(input, true); for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) { unsigned char timelineType = readByte(input); int frameCount = readVarint(input, true); + int frameLast = frameCount - 1; switch (timelineType) { case SLOT_ATTACHMENT: { - AttachmentTimeline *timeline = new(__FILE__, __LINE__) AttachmentTimeline(frameCount); - timeline->_slotIndex = slotIndex; - for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + AttachmentTimeline *timeline = new(__FILE__, __LINE__) AttachmentTimeline(frameCount, slotIndex); + for (int frame = 0; frame < frameCount; ++frame) { float time = readFloat(input); String attachmentName(readStringRef(input, skeletonData)); - timeline->setFrame(frameIndex, time, attachmentName); + timeline->setFrame(frame, time, attachmentName); } timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[frameCount - 1]); break; } - case SLOT_COLOR: { - ColorTimeline *timeline = new(__FILE__, __LINE__) ColorTimeline(frameCount); - timeline->_slotIndex = slotIndex; - for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - int color = readInt(input); - float r = ((color & 0xff000000) >> 24) / 255.0f; - float g = ((color & 0x00ff0000) >> 16) / 255.0f; - float b = ((color & 0x0000ff00) >> 8) / 255.0f; - float a = ((color & 0x000000ff)) / 255.0f; - timeline->setFrame(frameIndex, time, r, g, b, a); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[(frameCount - 1) * ColorTimeline::ENTRIES]); - break; - } - case SLOT_TWO_COLOR: { - TwoColorTimeline *timeline = new(__FILE__, __LINE__) TwoColorTimeline(frameCount); - timeline->_slotIndex = slotIndex; - for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - int color = readInt(input); - float r = ((color & 0xff000000) >> 24) / 255.0f; - float g = ((color & 0x00ff0000) >> 16) / 255.0f; - float b = ((color & 0x0000ff00) >> 8) / 255.0f; - float a = ((color & 0x000000ff)) / 255.0f; - int color2 = readInt(input); // 0x00rrggbb - float r2 = ((color2 & 0x00ff0000) >> 16) / 255.0f; - float g2 = ((color2 & 0x0000ff00) >> 8) / 255.0f; - float b2 = ((color2 & 0x000000ff)) / 255.0f; + case SLOT_RGBA: { + int bezierCount = readVarint(input, true); + RGBATimeline *timeline = new(__FILE__, __LINE__) RGBATimeline(frameCount, bezierCount, slotIndex); - timeline->setFrame(frameIndex, time, r, g, b, a, r2, g2, b2); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[(frameCount - 1) * TwoColorTimeline::ENTRIES]); - break; + float time = readFloat(input); + float r = readByte(input) / 255.0; + float g = readByte(input) / 255.0; + float b = readByte(input) / 255.0; + float a = readByte(input) / 255.0; + + for (int frame = 0, bezier = 0;; frame++) { + timeline->setFrame(frame, time, r, g, b, a); + if (frame == frameLast) break; + + float time2 = readFloat(input); + float r2 = readByte(input) / 255.0; + float g2 = readByte(input) / 255.0; + float b2 = readByte(input) / 255.0; + float a2 = readByte(input) / 255.0; + + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, a, a2, 1); + } + time = time2; + r = r2; + g = g2; + b = b2; + a = a2; + } + timelines.add(timeline); + break; } + case SLOT_RGB: { + int bezierCount = readVarint(input, true); + RGBTimeline *timeline = new(__FILE__, __LINE__) RGBTimeline(frameCount, bezierCount, slotIndex); + + float time = readFloat(input); + float r = readByte(input) / 255.0; + float g = readByte(input) / 255.0; + float b = readByte(input) / 255.0; + + for (int frame = 0, bezier = 0;; frame++) { + timeline->setFrame(frame, time, r, g, b); + if (frame == frameLast) break; + + float time2 = readFloat(input); + float r2 = readByte(input) / 255.0; + float g2 = readByte(input) / 255.0; + float b2 = readByte(input) / 255.0; + + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1); + } + time = time2; + r = r2; + g = g2; + b = b2; + } + timelines.add(timeline); + break; + } + case SLOT_RGBA2: { + int bezierCount = readVarint(input, true); + RGBA2Timeline *timeline = new(__FILE__, __LINE__) RGBA2Timeline(frameCount, bezierCount, slotIndex); + + float time = readFloat(input); + float r = readByte(input) / 255.0; + float g = readByte(input) / 255.0; + float b = readByte(input) / 255.0; + float a = readByte(input) / 255.0; + float r2 = readByte(input) / 255.0; + float g2 = readByte(input) / 255.0; + float b2 = readByte(input) / 255.0; + + for (int frame = 0, bezier = 0;; frame++) { + timeline->setFrame(frame, time, r, g, b, a, r2, g2, b2); + if (frame == frameLast) break; + float time2 = readFloat(input); + float nr = readByte(input) / 255.0; + float ng = readByte(input) / 255.0; + float nb = readByte(input) / 255.0; + float na = readByte(input) / 255.0; + float nr2 = readByte(input) / 255.0; + float ng2 = readByte(input) / 255.0; + float nb2 = readByte(input) / 255.0; + + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, a, na, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, r2, nr2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, g2, ng2, 1); + setBezier(input, timeline, bezier++, frame, 6, time, time2, b2, nb2, 1); + } + time = time2; + r = nr; + g = ng; + b = nb; + a = na; + r2 = nr2; + g2 = ng2; + b2 = nb2; + } + timelines.add(timeline); + break; + } + case SLOT_RGB2: { + int bezierCount = readVarint(input, true); + RGB2Timeline *timeline = new(__FILE__, __LINE__) RGB2Timeline(frameCount, bezierCount, slotIndex); + + float time = readFloat(input); + float r = readByte(input) / 255.0; + float g = readByte(input) / 255.0; + float b = readByte(input) / 255.0; + float r2 = readByte(input) / 255.0; + float g2 = readByte(input) / 255.0; + float b2 = readByte(input) / 255.0; + + for (int frame = 0, bezier = 0;; frame++) { + timeline->setFrame(frame, time, r, g, b, r2, g2, b2); + if (frame == frameLast) break; + float time2 = readFloat(input); + float nr = readByte(input) / 255.0; + float ng = readByte(input) / 255.0; + float nb = readByte(input) / 255.0; + float nr2 = readByte(input) / 255.0; + float ng2 = readByte(input) / 255.0; + float nb2 = readByte(input) / 255.0; + + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, r2, nr2, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, g2, ng2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, b2, nb2, 1); + } + time = time2; + r = nr; + g = ng; + b = nb; + r2 = nr2; + g2 = ng2; + b2 = nb2; + } + timelines.add(timeline); + break; + } + case SLOT_ALPHA: { + int bezierCount = readVarint(input, true); + AlphaTimeline *timeline = new(__FILE__, __LINE__) AlphaTimeline(frameCount, bezierCount, slotIndex); + float time = readFloat(input); + float a = readByte(input) / 255.0; + for (int frame = 0, bezier = 0;; frame++) { + timeline->setFrame(frame, time, a); + if (frame == frameLast) break; + float time2 = readFloat(input); + float a2 = readByte(input) / 255; + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, a, a2, 1); + } + time = time2; + a = a2; + } + timelines.add(timeline); + break; + } default: { ContainerUtil::cleanUpVectorOfPointers(timelines); setError("Invalid timeline type for a slot: ", skeletonData->_slots[slotIndex]->_name.buffer()); @@ -778,144 +971,186 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) { unsigned char timelineType = readByte(input); int frameCount = readVarint(input, true); + int bezierCount = readVarint(input, true); + Timeline *timeline = NULL; switch (timelineType) { - case BONE_ROTATE: { - RotateTimeline *timeline = new(__FILE__, __LINE__) RotateTimeline(frameCount); - timeline->_boneIndex = boneIndex; - for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float degrees = readFloat(input); - timeline->setFrame(frameIndex, time, degrees); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[(frameCount - 1) * RotateTimeline::ENTRIES]); - break; - } - case BONE_TRANSLATE: - case BONE_SCALE: - case BONE_SHEAR: { - TranslateTimeline *timeline; - float timelineScale = 1; - if (timelineType == BONE_SCALE) { - timeline = new(__FILE__, __LINE__) ScaleTimeline(frameCount); - } else if (timelineType == BONE_SHEAR) { - timeline = new(__FILE__, __LINE__) ShearTimeline(frameCount); - } else { - timeline = new(__FILE__, __LINE__) TranslateTimeline(frameCount); - timelineScale = scale; - } - timeline->_boneIndex = boneIndex; - for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float x = readFloat(input) * timelineScale; - float y = readFloat(input) * timelineScale; - timeline->setFrame(frameIndex, time, x, y); - if (frameIndex < frameCount - 1) { - readCurve(input, frameIndex, timeline); - } - } - timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[(frameCount - 1) * TranslateTimeline::ENTRIES]); - break; - } + case BONE_ROTATE: + timeline = readTimeline(input, new(__FILE__, __LINE__) RotateTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_TRANSLATE: + timeline = readTimeline2(input, new(__FILE__, __LINE__) TranslateTimeline(frameCount, bezierCount, boneIndex), scale); + break; + case BONE_TRANSLATEX: + timeline = readTimeline(input, new(__FILE__, __LINE__) TranslateXTimeline(frameCount, bezierCount, boneIndex), scale); + break; + case BONE_TRANSLATEY: + timeline = readTimeline(input, new(__FILE__, __LINE__) TranslateYTimeline(frameCount, bezierCount, boneIndex), scale); + break; + case BONE_SCALE: + timeline = readTimeline2(input, new(__FILE__, __LINE__) ScaleTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_SCALEX: + timeline = readTimeline(input, new(__FILE__, __LINE__) ScaleXTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_SCALEY: + timeline = readTimeline(input, new(__FILE__, __LINE__) ScaleYTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_SHEAR: + timeline = readTimeline2(input, new(__FILE__, __LINE__) ShearTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_SHEARX: + timeline = readTimeline(input, new(__FILE__, __LINE__) ShearXTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_SHEARY: + timeline = readTimeline(input, new(__FILE__, __LINE__) ShearYTimeline(frameCount, bezierCount, boneIndex), 1); + break; default: { ContainerUtil::cleanUpVectorOfPointers(timelines); setError("Invalid timeline type for a bone: ", skeletonData->_bones[boneIndex]->_name.buffer()); return NULL; } } + timelines.add(timeline); } } // IK timelines. for (int i = 0, n = readVarint(input, true); i < n; ++i) { - int index = readVarint(input, true); - int frameCount = readVarint(input, true); - IkConstraintTimeline *timeline = new(__FILE__, __LINE__) IkConstraintTimeline(frameCount); - timeline->_ikConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float mix = readFloat(input); - float softness = readFloat(input) * _scale; - signed char bendDirection = readSByte(input); - bool compress = readBoolean(input); - bool stretch = readBoolean(input); - timeline->setFrame(frameIndex, time, mix, softness, bendDirection, compress, stretch); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } + int index = readVarint(input, true); + int frameCount = readVarint(input, true); + int frameLast = frameCount - 1; + int bezierCount = readVarint(input, true); + IkConstraintTimeline *timeline = new (__FILE__, __LINE__) IkConstraintTimeline(frameCount, bezierCount, index); + float time = readFloat(input); + float mix = readFloat(input); + float softness = readFloat(input) * scale; + for (int frame = 0, bezier = 0;; frame++) { + int bendDirection = readSByte(input); + bool compress = readBoolean(input); + bool stretch = readBoolean(input); + timeline->setFrame(frame, time, mix, softness, bendDirection, compress, stretch); + if (frame == frameLast) break; + float time2 = readFloat(input); + float mix2 = readFloat(input); + float softness2 = readFloat(input) * scale; + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2, scale); + } + time = time2; + mix = mix2; + softness = softness2; + } timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[(frameCount - 1) * IkConstraintTimeline::ENTRIES]); } // Transform constraint timelines. for (int i = 0, n = readVarint(input, true); i < n; ++i) { - int index = readVarint(input, true); - int frameCount = readVarint(input, true); - TransformConstraintTimeline *timeline = new(__FILE__, __LINE__) TransformConstraintTimeline(frameCount); - timeline->_transformConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float rotateMix = readFloat(input); - float translateMix = readFloat(input); - float scaleMix = readFloat(input); - float shearMix = readFloat(input); - timeline->setFrame(frameIndex, time, rotateMix, translateMix, scaleMix, shearMix); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } + int index = readVarint(input, true); + int frameCount = readVarint(input, true); + int frameLast = frameCount - 1; + int bezierCount = readVarint(input, true); + TransformConstraintTimeline *timeline = new TransformConstraintTimeline(frameCount, bezierCount, index); + float time = readFloat(input); + float mixRotate = readFloat(input); + float mixX = readFloat(input); + float mixY = readFloat(input); + float mixScaleX = readFloat(input); + float mixScaleY = readFloat(input); + float mixShearY = readFloat(input); + for (int frame = 0, bezier = 0;; frame++) { + timeline->setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY); + if (frame == frameLast) break; + float time2 = readFloat(input); + float mixRotate2 = readFloat(input); + float mixX2 = readFloat(input); + float mixY2 = readFloat(input); + float mixScaleX2 = readFloat(input); + float mixScaleY2 = readFloat(input); + float mixShearY2 = readFloat(input); + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, mixScaleX, mixScaleX2, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, mixScaleY, mixScaleY2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, mixShearY, mixShearY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + mixScaleX = mixScaleX2; + mixScaleY = mixScaleY2; + mixShearY = mixShearY2; + } timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[(frameCount - 1) * TransformConstraintTimeline::ENTRIES]); } // Path constraint timelines. for (int i = 0, n = readVarint(input, true); i < n; ++i) { - int index = readVarint(input, true); - PathConstraintData *data = skeletonData->_pathConstraints[index]; - for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) { - int timelineType = readSByte(input); - int frameCount = readVarint(input, true); - switch (timelineType) { - case PATH_POSITION: - case PATH_SPACING: { - PathConstraintPositionTimeline *timeline; - float timelineScale = 1; - if (timelineType == PATH_SPACING) { - timeline = new(__FILE__, __LINE__) PathConstraintSpacingTimeline(frameCount); + int index = readVarint(input, true); + PathConstraintData *data = skeletonData->_pathConstraints[index]; + for (int ii = 0, nn = readVarint(input, true); ii < nn; ii++) { + int type = readSByte(input); + int frameCount = readVarint(input, true); + int bezierCount = readVarint(input, true); + switch (type) { + case PATH_POSITION: { + timelines + .add(readTimeline(input, new PathConstraintPositionTimeline(frameCount, bezierCount, index), + data->_positionMode == PositionMode_Fixed ? scale : 1)); + break; + } + case PATH_SPACING: { + timelines + .add(readTimeline(input, + new PathConstraintSpacingTimeline(frameCount, + bezierCount, + index), + data->_spacingMode == SpacingMode_Length || + data->_spacingMode == SpacingMode_Fixed ? scale : 1)); + break; + } + case PATH_MIX: + PathConstraintMixTimeline *timeline = new PathConstraintMixTimeline(frameCount, bezierCount, index); + float time = readFloat(input); + float mixRotate = readFloat(input); + float mixX = readFloat(input); + float mixY = readFloat(input); + for (int frame = 0, bezier = 0, frameLast = timeline->getFrameCount() - 1;; frame++) { + timeline->setFrame(frame, time, mixRotate, mixX, mixY); + if (frame == frameLast) break; + float time2 = readFloat(input); + float mixRotate2 = readFloat(input); + float mixX2 = readFloat(input); + float mixY2 = readFloat(input); + switch (readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1); - if (data->_spacingMode == SpacingMode_Length || data->_spacingMode == SpacingMode_Fixed) timelineScale = scale; - } else { - timeline = new(__FILE__, __LINE__) PathConstraintPositionTimeline(frameCount); - - if (data->_positionMode == PositionMode_Fixed) timelineScale = scale; - } - timeline->_pathConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float value = readFloat(input) * timelineScale; - timeline->setFrame(frameIndex, time, value); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[(frameCount - 1) * PathConstraintPositionTimeline::ENTRIES]); - break; - } - case PATH_MIX: { - PathConstraintMixTimeline *timeline = new(__FILE__, __LINE__) PathConstraintMixTimeline(frameCount); - - timeline->_pathConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float rotateMix = readFloat(input); - float translateMix = readFloat(input); - timeline->setFrame(frameIndex, time, rotateMix, translateMix); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[(frameCount - 1) * PathConstraintMixTimeline::ENTRIES]); - break; - } - } - } + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + } + timelines.add(timeline); + } + } } // Deform timelines. @@ -937,22 +1172,21 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S bool weighted = attachment->_bones.size() > 0; Vector &vertices = attachment->_vertices; - size_t deformLength = weighted ? vertices.size() / 3 * 2 : vertices.size(); + int deformLength = weighted ? vertices.size() / 3 * 2 : vertices.size(); - size_t frameCount = (size_t)readVarint(input, true); + int frameCount = readVarint(input, true); + int frameLast = frameCount -1; + int bezierCount = readVarint(input, true); + DeformTimeline *timeline = new(__FILE__, __LINE__) DeformTimeline(frameCount, bezierCount, slotIndex, attachment); - DeformTimeline *timeline = new(__FILE__, __LINE__) DeformTimeline(frameCount); - timeline->_slotIndex = slotIndex; - timeline->_attachment = attachment; - - for (size_t frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); + float time = readFloat(input); + for (int frame = 0, bezier = 0;; ++frame) { Vector deform; size_t end = (size_t)readVarint(input, true); if (end == 0) { if (weighted) { deform.setSize(deformLength, 0); - for (size_t iiii = 0; iiii < deformLength; ++iiii) + for (int iiii = 0; iiii < deformLength; ++iiii) deform[iiii] = 0; } else { deform.clearAndAddAll(vertices); @@ -975,12 +1209,20 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S } } - timeline->setFrame(frameIndex, time, deform); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); + timeline->setFrame(frame, time, deform); + if (frame == frameLast) break; + float time2 = readFloat(input); + switch(readSByte(input)) { + case CURVE_STEPPED: + timeline->setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1); + } + time = time2; } timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[frameCount - 1]); } } } @@ -1024,7 +1266,6 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S timeline->setFrame(i, time, drawOrder); } timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[drawOrderCount - 1]); } // Event timeline. @@ -1050,27 +1291,12 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S } timeline->setFrame(i, event); } - timelines.add(timeline); - duration = MathUtil::max(duration, timeline->_frames[eventCount - 1]); } + float duration = 0; + for (int i = 0, n = timelines.size(); i < n; i++) { + duration = MathUtil::max(duration, (timelines[i])->getDuration()); + } return new(__FILE__, __LINE__) Animation(String(name), timelines, duration); } - -void SkeletonBinary::readCurve(DataInput *input, int frameIndex, CurveTimeline *timeline) { - switch (readByte(input)) { - case CURVE_STEPPED: { - timeline->setStepped(frameIndex); - break; - } - case CURVE_BEZIER: { - float cx1 = readFloat(input); - float cy1 = readFloat(input); - float cx2 = readFloat(input); - float cy2 = readFloat(input); - timeline->setCurve(frameIndex, cx1, cy1, cx2, cy2); - break; - } - } -} diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp index 18be34c90..035ba5afa 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include diff --git a/spine-cpp/spine-cpp/src/spine/TwoColorTimeline.cpp b/spine-cpp/spine-cpp/src/spine/TwoColorTimeline.cpp deleted file mode 100644 index e06221318..000000000 --- a/spine-cpp/spine-cpp/src/spine/TwoColorTimeline.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/****************************************************************************** - * Spine Runtimes License Agreement - * Last updated January 1, 2020. Replaces all prior versions. - * - * Copyright (c) 2013-2020, Esoteric Software LLC - * - * Integration of the Spine Runtimes into software or otherwise creating - * derivative works of the Spine Runtimes is permitted under the terms and - * conditions of Section 2 of the Spine Editor License Agreement: - * http://esotericsoftware.com/spine-editor-license - * - * Otherwise, it is permitted to integrate the Spine Runtimes into software - * or otherwise create derivative works of the Spine Runtimes (collectively, - * "Products"), provided that each user of the Products must obtain their own - * Spine Editor license and redistribution of the Products in any form must - * include this license and copyright notice. - * - * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, - * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#ifdef SPINE_UE4 -#include "SpinePluginPrivatePCH.h" -#endif - -#include - -#include -#include - -#include -#include -#include -#include -#include - -using namespace spine; - -RTTI_IMPL(TwoColorTimeline, CurveTimeline) - -const int TwoColorTimeline::ENTRIES = 8; -const int TwoColorTimeline::PREV_TIME = -8; -const int TwoColorTimeline::PREV_R = -7; -const int TwoColorTimeline::PREV_G = -6; -const int TwoColorTimeline::PREV_B = -5; -const int TwoColorTimeline::PREV_A = -4; -const int TwoColorTimeline::PREV_R2 = -3; -const int TwoColorTimeline::PREV_G2 = -2; -const int TwoColorTimeline::PREV_B2 = -1; -const int TwoColorTimeline::R = 1; -const int TwoColorTimeline::G = 2; -const int TwoColorTimeline::B = 3; -const int TwoColorTimeline::A = 4; -const int TwoColorTimeline::R2 = 5; -const int TwoColorTimeline::G2 = 6; -const int TwoColorTimeline::B2 = 7; - -TwoColorTimeline::TwoColorTimeline(int frameCount) : CurveTimeline(frameCount), _slotIndex(0) { - _frames.ensureCapacity(frameCount * ENTRIES); - _frames.setSize(frameCount * ENTRIES, 0); -} - -void TwoColorTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector *pEvents, float alpha, - MixBlend blend, MixDirection direction -) { - SP_UNUSED(lastTime); - SP_UNUSED(pEvents); - SP_UNUSED(direction); - - Slot *slotP = skeleton._slots[_slotIndex]; - Slot &slot = *slotP; - if (!slot._bone.isActive()) return; - - if (time < _frames[0]) { - // Time is before first frame. - switch (blend) { - case MixBlend_Setup: - slot.getColor().set(slot.getData().getColor()); - slot.getDarkColor().set(slot.getData().getDarkColor()); - return; - case MixBlend_First: { - Color &color = slot.getColor(); - color.r += (color.r - slot._data.getColor().r) * alpha; - color.g += (color.g - slot._data.getColor().g) * alpha; - color.b += (color.b - slot._data.getColor().b) * alpha; - color.a += (color.a - slot._data.getColor().a) * alpha; - - Color &darkColor = slot.getDarkColor(); - darkColor.r += (darkColor.r - slot._data.getDarkColor().r) * alpha; - darkColor.g += (darkColor.g - slot._data.getDarkColor().g) * alpha; - darkColor.b += (darkColor.b - slot._data.getDarkColor().b) * alpha; - return; - } - default: - return; - } - } - - float r, g, b, a, r2, g2, b2; - if (time >= _frames[_frames.size() - ENTRIES]) { - // Time is after last frame. - size_t i = _frames.size(); - r = _frames[i + PREV_R]; - g = _frames[i + PREV_G]; - b = _frames[i + PREV_B]; - a = _frames[i + PREV_A]; - r2 = _frames[i + PREV_R2]; - g2 = _frames[i + PREV_G2]; - b2 = _frames[i + PREV_B2]; - } else { - // Interpolate between the previous frame and the current frame. - size_t frame = (size_t)Animation::binarySearch(_frames, time, ENTRIES); - r = _frames[frame + PREV_R]; - g = _frames[frame + PREV_G]; - b = _frames[frame + PREV_B]; - a = _frames[frame + PREV_A]; - r2 = _frames[frame + PREV_R2]; - g2 = _frames[frame + PREV_G2]; - b2 = _frames[frame + PREV_B2]; - float frameTime = _frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, - 1 - (time - frameTime) / (_frames[frame + PREV_TIME] - frameTime)); - - r += (_frames[frame + R] - r) * percent; - g += (_frames[frame + G] - g) * percent; - b += (_frames[frame + B] - b) * percent; - a += (_frames[frame + A] - a) * percent; - r2 += (_frames[frame + R2] - r2) * percent; - g2 += (_frames[frame + G2] - g2) * percent; - b2 += (_frames[frame + B2] - b2) * percent; - } - - if (alpha == 1) { - Color &color = slot.getColor(); - color.set(r, g, b, a); - - Color &darkColor = slot.getDarkColor(); - darkColor.set(r2, g2, b2, 1); - } else { - Color &light = slot._color; - Color &dark = slot._darkColor; - if (blend == MixBlend_Setup) { - light.set(slot._data._color); - dark.set(slot._data._darkColor); - } - light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha); - dark.add((r2 - dark.r) * alpha, (g2 - dark.g) * alpha, (b2 - dark.b) * alpha, 0); - } -} - -int TwoColorTimeline::getPropertyId() { - return ((int) TimelineType_TwoColor << 24) + _slotIndex; -} - -void TwoColorTimeline::setFrame(int frameIndex, float time, float r, float g, float b, float a, float r2, float g2, float b2) { - frameIndex *= ENTRIES; - _frames[frameIndex] = time; - _frames[frameIndex + R] = r; - _frames[frameIndex + G] = g; - _frames[frameIndex + B] = b; - _frames[frameIndex + A] = a; - _frames[frameIndex + R2] = r2; - _frames[frameIndex + G2] = g2; - _frames[frameIndex + B2] = b2; -} - -int TwoColorTimeline::getSlotIndex() { - return _slotIndex; -} - -void TwoColorTimeline::setSlotIndex(int inValue) { - assert(inValue >= 0); - _slotIndex = inValue; -}