diff --git a/spine-corona/spine/SkeletonJson.lua b/spine-corona/spine/SkeletonJson.lua index a6a5cdb5f..266139275 100644 --- a/spine-corona/spine/SkeletonJson.lua +++ b/spine-corona/spine/SkeletonJson.lua @@ -140,12 +140,12 @@ function SkeletonJson.new (attachmentResolver) if not root then error("Invalid JSON: " .. jsonText, 2) end local bonesMap = root["bones"] - for boneName,propertyMap in pairs(bonesMap) do + for boneName,timelineMap in pairs(bonesMap) do local boneIndex = skeletonData:findBoneIndex(boneName) if boneIndex == -1 then error("Bone not found: " .. boneName) end - for timelineType,values in pairs(propertyMap) do - if timelineType == TIMELINE_ROTATE then + for timelineName,values in pairs(timelineMap) do + if timelineName == TIMELINE_ROTATE then local timeline = Animation.RotateTimeline.new() timeline.boneIndex = boneIndex @@ -159,10 +159,10 @@ function SkeletonJson.new (attachmentResolver) table.insert(timelines, timeline) duration = math.max(duration, timeline:getDuration()) - elseif timelineType == TIMELINE_TRANSLATE or timelineType == TIMELINE_SCALE then + elseif timelineName == TIMELINE_TRANSLATE or timelineName == TIMELINE_SCALE then local timeline local timelineScale = 1 - if timelineType == TIMELINE_SCALE then + if timelineName == TIMELINE_SCALE then timeline = Animation.ScaleTimeline.new() else timeline = Animation.TranslateTimeline.new() @@ -183,18 +183,18 @@ function SkeletonJson.new (attachmentResolver) duration = math.max(duration, timeline:getDuration()) else - error("Invalid timeline type for a bone: " .. timelineType .. " (" .. boneName .. ")") + error("Invalid timeline type for a bone: " .. timelineName .. " (" .. boneName .. ")") end end end local slotsMap = root["slots"] if slotsMap then - for slotName,propertyMap in pairs(slotsMap) do + for slotName,timelineMap in pairs(slotsMap) do local slotIndex = skeletonData:findSlotIndex(slotName) - for timelineType,values in pairs(propertyMap) do - if timelineType == TIMELINE_COLOR then + for timelineName,values in pairs(timelineMap) do + if timelineName == TIMELINE_COLOR then local timeline = Animation.ColorTimeline.new() timeline.slotIndex = slotIndex @@ -215,7 +215,7 @@ function SkeletonJson.new (attachmentResolver) table.insert(timelines, timeline) duration = math.max(duration, timeline:getDuration()) - elseif timelineType == TIMELINE_ATTACHMENT then + elseif timelineName == TIMELINE_ATTACHMENT then local timeline = Animation.AttachmentTimeline.new() timeline.slotName = slotName @@ -231,7 +231,7 @@ function SkeletonJson.new (attachmentResolver) duration = math.max(duration, timeline:getDuration()) else - error("Invalid frame type for a slot: " .. timelineType .. " (" .. slotName .. ")") + error("Invalid frame type for a slot: " .. timelineName .. " (" .. slotName .. ")") end end end diff --git a/spine-cpp/.settings/org.eclipse.cdt.codan.core.prefs b/spine-cpp/.settings/org.eclipse.cdt.codan.core.prefs index b2d528b86..4fa6ad5b7 100644 --- a/spine-cpp/.settings/org.eclipse.cdt.codan.core.prefs +++ b/spine-cpp/.settings/org.eclipse.cdt.codan.core.prefs @@ -19,7 +19,7 @@ org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=-Warning org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true} org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} @@ -65,3 +65,4 @@ org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")} org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +useParentScope=false diff --git a/spine-cpp/includes/spine-sfml/Skeleton.h b/spine-cpp/includes/spine-sfml/Skeleton.h index d298f64c5..522e0d03b 100644 --- a/spine-cpp/includes/spine-sfml/Skeleton.h +++ b/spine-cpp/includes/spine-sfml/Skeleton.h @@ -9,7 +9,7 @@ namespace spine { class Skeleton: public BaseSkeleton, public sf::Drawable { public: sf::VertexArray vertexArray; - sf::Texture *texture; + sf::Texture *texture; // BOZO - This is ugly. Support multiple textures? Skeleton (SkeletonData *skeletonData); diff --git a/spine-cpp/includes/spine/Animation.h b/spine-cpp/includes/spine/Animation.h index 4e243d74a..d9ed84ea8 100644 --- a/spine-cpp/includes/spine/Animation.h +++ b/spine-cpp/includes/spine/Animation.h @@ -15,6 +15,8 @@ public: float duration; Animation (const std::vector &timelines, float duration); + + void apply (BaseSkeleton *skeleton, float time, bool loop); }; // @@ -63,9 +65,9 @@ public: RotateTimeline (int keyframeCount); virtual ~RotateTimeline (); - virtual float getDuration () = 0; - virtual int getKeyframeCount () = 0; - virtual void apply (BaseSkeleton *skeleton, float time, float alpha) = 0; + virtual float getDuration (); + virtual int getKeyframeCount (); + virtual void apply (BaseSkeleton *skeleton, float time, float alpha); void setKeyframe (int keyframeIndex, float time, float value); }; @@ -81,9 +83,9 @@ public: TranslateTimeline (int keyframeCount); virtual ~TranslateTimeline (); - virtual float getDuration () = 0; - virtual int getKeyframeCount () = 0; - virtual void apply (BaseSkeleton *skeleton, float time, float alpha) = 0; + virtual float getDuration (); + virtual int getKeyframeCount (); + virtual void apply (BaseSkeleton *skeleton, float time, float alpha); void setKeyframe (int keyframeIndex, float time, float x, float y); }; @@ -94,9 +96,7 @@ class ScaleTimeline: public TranslateTimeline { public: ScaleTimeline (int keyframeCount); - virtual float getDuration () = 0; - virtual int getKeyframeCount () = 0; - virtual void apply (BaseSkeleton *skeleton, float time, float alpha) = 0; + virtual void apply (BaseSkeleton *skeleton, float time, float alpha); }; // @@ -110,9 +110,9 @@ public: ColorTimeline (int keyframeCount); virtual ~ColorTimeline (); - virtual float getDuration () = 0; - virtual int getKeyframeCount () = 0; - virtual void apply (BaseSkeleton *skeleton, float time, float alpha) = 0; + virtual float getDuration (); + virtual int getKeyframeCount (); + virtual void apply (BaseSkeleton *skeleton, float time, float alpha); void setKeyframe (int keyframeIndex, float time, float r, float g, float b, float a); }; @@ -129,9 +129,9 @@ public: AttachmentTimeline (int keyframeCount); virtual ~AttachmentTimeline (); - virtual float getDuration () = 0; - virtual int getKeyframeCount () = 0; - virtual void apply (BaseSkeleton *skeleton, float time, float alpha) = 0; + virtual float getDuration (); + virtual int getKeyframeCount (); + virtual void apply (BaseSkeleton *skeleton, float time, float alpha); void setKeyframe (int keyframeIndex, float time, std::string *attachmentName); }; diff --git a/spine-cpp/includes/spine/Attachment.h b/spine-cpp/includes/spine/Attachment.h index 5ef4ce128..42347fac8 100644 --- a/spine-cpp/includes/spine/Attachment.h +++ b/spine-cpp/includes/spine/Attachment.h @@ -11,7 +11,6 @@ class Slot; class Attachment { public: std::string name; - float x, y, scaleX, scaleY, rotation, width, height; virtual ~Attachment () { } diff --git a/spine-cpp/includes/spine/BaseRegionAttachment.h b/spine-cpp/includes/spine/BaseRegionAttachment.h index 142b75e4d..86d38c426 100644 --- a/spine-cpp/includes/spine/BaseRegionAttachment.h +++ b/spine-cpp/includes/spine/BaseRegionAttachment.h @@ -10,6 +10,7 @@ class Slot; class BaseRegionAttachment: public Attachment { public: + float x, y, scaleX, scaleY, rotation, width, height; float offset[8]; void updateOffset (); diff --git a/spine-cpp/includes/spine/BaseSkeletonJson.h b/spine-cpp/includes/spine/BaseSkeletonJson.h index 161707e99..242ab8f62 100644 --- a/spine-cpp/includes/spine/BaseSkeletonJson.h +++ b/spine-cpp/includes/spine/BaseSkeletonJson.h @@ -5,8 +5,9 @@ namespace spine { -class SkeletonData; class BaseAttachmentLoader; +class SkeletonData; +class Animation; class BaseSkeletonJson { public: @@ -20,6 +21,11 @@ public: SkeletonData* readSkeletonData (std::istream &file) const; SkeletonData* readSkeletonData (const std::string &json) const; SkeletonData* readSkeletonData (const char *begin, const char *end) const; + + Animation* readAnimation (std::ifstream &file, const SkeletonData *skeletonData) const; + Animation* readAnimation (std::istream &file, const SkeletonData *skeletonData) const; + Animation* readAnimation (const std::string &json, const SkeletonData *skeletonData) const; + Animation* readAnimation (const char *begin, const char *end, const SkeletonData *skeletonData) const; }; } /* namespace spine */ diff --git a/spine-cpp/src/main.cpp b/spine-cpp/src/main.cpp index d4c9e5f5e..1f28c5081 100644 --- a/spine-cpp/src/main.cpp +++ b/spine-cpp/src/main.cpp @@ -7,13 +7,19 @@ using namespace std; using namespace spine; int main () { - ifstream file("../data/spineboy-skeleton.json"); try { - ifstream file2("../data/spineboy.atlas"); - Atlas *atlas = new Atlas(file2); + ifstream atlasFile("../data/spineboy.atlas"); + Atlas *atlas = new Atlas(atlasFile); + SkeletonJson skeletonJson(atlas); - SkeletonData *skeletonData = skeletonJson.readSkeletonData(file); + + ifstream skeletonFile("../data/spineboy-skeleton.json"); + SkeletonData *skeletonData = skeletonJson.readSkeletonData(skeletonFile); + + ifstream animationFile("../data/spineboy-walk.json"); + Animation *animation = skeletonJson.readAnimation(animationFile, skeletonData); + Skeleton *skeleton = new Skeleton(skeletonData); skeleton->setToBindPose(); skeleton->getRootBone()->x = 200; @@ -23,12 +29,24 @@ int main () { sf::RenderWindow window(sf::VideoMode(640, 480), "Spine SFML"); window.setFramerateLimit(60); sf::Event event; + sf::Clock deltaClock; + float animationTime = 0; while (window.isOpen()) { while (window.pollEvent(event)) if (event.type == sf::Event::Closed) window.close(); window.clear(); window.draw(*skeleton); window.display(); + + float delta = deltaClock.getElapsedTime().asSeconds(); + deltaClock.restart(); + animationTime += delta; + + skeleton->setToBindPose(); + skeleton->getRootBone()->x = 200; + skeleton->getRootBone()->y = 420; + animation->apply(skeleton, animationTime, true); + skeleton->updateWorldTransform(); } } catch (exception &ex) { cout << ex.what() << endl << flush; diff --git a/spine-cpp/src/spine-sfml/RegionAttachment.cpp b/spine-cpp/src/spine-sfml/RegionAttachment.cpp index d909f27e2..fe3a7c582 100644 --- a/spine-cpp/src/spine-sfml/RegionAttachment.cpp +++ b/spine-cpp/src/spine-sfml/RegionAttachment.cpp @@ -9,8 +9,7 @@ namespace spine { RegionAttachment::RegionAttachment (AtlasRegion *region) { - texture = region->page->texture; - sf::Vector2u size = texture->getSize(); + texture = region->page->texture; // BOZO - Resolve attachment as late as possible? int u = region->x; int u2 = u + region->width; int v = region->y; diff --git a/spine-cpp/src/spine/Animation.cpp b/spine-cpp/src/spine/Animation.cpp index b024bd209..bdcddcb42 100644 --- a/spine-cpp/src/spine/Animation.cpp +++ b/spine-cpp/src/spine/Animation.cpp @@ -1,3 +1,7 @@ +#include +#include +#include +#include #include #include #include @@ -14,6 +18,15 @@ Animation::Animation (const vector &timelines, float duration) : duration(duration) { } +void Animation::apply (BaseSkeleton *skeleton, float time, bool loop) { + if (!skeleton) throw std::invalid_argument("skeleton cannot be null."); + + if (loop && duration) time = fmodf(time, duration); + + for (int i = 0, n = timelines.size(); i < n; i++) + timelines[i]->apply(skeleton, time, 1); +} + // static const float LINEAR = 0; @@ -22,6 +35,7 @@ static const int BEZIER_SEGMENTS = 10; CurveTimeline::CurveTimeline (int keyframeCount) : curves(new float[(keyframeCount - 1) * 6]) { + memset(curves, 0, sizeof(float) * (keyframeCount - 1) * 6); } CurveTimeline::~CurveTimeline () { @@ -122,7 +136,8 @@ static const int ROTATE_FRAME_VALUE = 1; RotateTimeline::RotateTimeline (int keyframeCount) : CurveTimeline(keyframeCount), framesLength(keyframeCount * 2), - frames(new float[framesLength]) { + frames(new float[framesLength]), + boneIndex(0) { } RotateTimeline::~RotateTimeline () { @@ -159,7 +174,7 @@ void RotateTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) { } // Interpolate between the last frame and the current frame. - int frameIndex = binarySearch(frames, framesLength, time, 2); + int frameIndex = linearSearch(frames, framesLength, time, 2); float lastFrameValue = frames[frameIndex - 1]; float frameTime = frames[frameIndex]; float percent = 1 - (time - frameTime) / (frames[frameIndex + ROTATE_LAST_FRAME_TIME] - frameTime); @@ -191,7 +206,8 @@ static const int TRANSLATE_FRAME_Y = 2; TranslateTimeline::TranslateTimeline (int keyframeCount) : CurveTimeline(keyframeCount), framesLength(keyframeCount * 3), - frames(new float[framesLength]) { + frames(new float[framesLength]), + boneIndex(0) { } TranslateTimeline::~TranslateTimeline () { @@ -286,7 +302,8 @@ static const int COLOR_FRAME_A = 4; ColorTimeline::ColorTimeline (int keyframeCount) : CurveTimeline(keyframeCount), framesLength(keyframeCount * 5), - frames(new float[framesLength]) { + frames(new float[framesLength]), + slotIndex(0) { } ColorTimeline::~ColorTimeline () { @@ -360,7 +377,8 @@ void ColorTimeline::apply (BaseSkeleton *skeleton, float time, float alpha) { AttachmentTimeline::AttachmentTimeline (int keyframeCount) : framesLength(keyframeCount), frames(new float[keyframeCount]), - attachmentNames(new string*[keyframeCount]) { + attachmentNames(new string*[keyframeCount]), + slotIndex(0) { } AttachmentTimeline::~AttachmentTimeline () { diff --git a/spine-cpp/src/spine/BaseAtlas.cpp b/spine-cpp/src/spine/BaseAtlas.cpp index 5d0a7b0a9..c34987f87 100644 --- a/spine-cpp/src/spine/BaseAtlas.cpp +++ b/spine-cpp/src/spine/BaseAtlas.cpp @@ -7,6 +7,7 @@ using std::string; using std::runtime_error; +using std::invalid_argument; namespace spine { @@ -75,11 +76,15 @@ BaseAtlas::~BaseAtlas () { } void BaseAtlas::load (std::ifstream &file) { + if (!file) throw invalid_argument("file cannot be null."); if (!file.is_open()) throw runtime_error("Atlas file is not open."); + load((std::istream&)file); } void BaseAtlas::load (std::istream &input) { + if (!input) throw invalid_argument("input cannot be null."); + string text; std::getline(input, text, (char)EOF); const char *begin = text.c_str(); @@ -94,6 +99,9 @@ void BaseAtlas::load (const string &text) { } void BaseAtlas::load (const char *current, const char *end) { + if (!current) throw invalid_argument("current cannot be null."); + if (!end) throw invalid_argument("end cannot be null."); + string value; string tuple[4]; BaseAtlasPage *page; diff --git a/spine-cpp/src/spine/BaseSkeletonJson.cpp b/spine-cpp/src/spine/BaseSkeletonJson.cpp index 76e80cae0..ebf9fb0a8 100644 --- a/spine-cpp/src/spine/BaseSkeletonJson.cpp +++ b/spine-cpp/src/spine/BaseSkeletonJson.cpp @@ -4,17 +4,30 @@ #include #include #include +#include #include #include #include #include +#include using std::string; using std::vector; using std::runtime_error; +using std::invalid_argument; namespace spine { +static float toColor (const string &value, int index) { + if (value.size() != 8) throw runtime_error("Error parsing color, length must be 8: " + value); + char *p; + int color = strtoul(value.substr(index * 2, 2).c_str(), &p, 16); + if (*p != 0) throw runtime_error("Error parsing color: " + value + ", invalid hex value: " + value.substr(index * 2, 2)); + return color / (float)255; +} + +// + BaseSkeletonJson::BaseSkeletonJson (BaseAttachmentLoader *attachmentLoader) : attachmentLoader(attachmentLoader), scale(1) { @@ -23,20 +36,16 @@ BaseSkeletonJson::BaseSkeletonJson (BaseAttachmentLoader *attachmentLoader) : BaseSkeletonJson::~BaseSkeletonJson () { } -float toColor (const string &value, int index) { - if (value.size() != 8) throw runtime_error("Error parsing color, length must be 8: " + value); - char *p; - int color = strtoul(value.substr(index * 2, 2).c_str(), &p, 16); - if (*p != 0) throw runtime_error("Error parsing color: " + value + ", invalid hex value: " + value.substr(index * 2, 2)); - return color / (float)255; -} - SkeletonData* BaseSkeletonJson::readSkeletonData (std::ifstream &file) const { + if (!file) throw invalid_argument("file cannot be null."); if (!file.is_open()) throw runtime_error("Skeleton file is not open."); + return readSkeletonData((std::istream&)file); } SkeletonData* BaseSkeletonJson::readSkeletonData (std::istream &input) const { + if (!input) throw invalid_argument("input cannot be null."); + string json; std::getline(input, json, (char)EOF); return readSkeletonData(json); @@ -49,6 +58,9 @@ SkeletonData* BaseSkeletonJson::readSkeletonData (const string &json) const { } SkeletonData* BaseSkeletonJson::readSkeletonData (const char *begin, const char *end) const { + if (!begin) throw invalid_argument("begin cannot be null."); + if (!end) throw invalid_argument("end cannot be null."); + static string const ATTACHMENT_REGION = "region"; static string const ATTACHMENT_REGION_SEQUENCE = "regionSequence"; @@ -140,13 +152,17 @@ SkeletonData* BaseSkeletonJson::readSkeletonData (const char *begin, const char Attachment* attachment = attachmentLoader->newAttachment(type, attachmentMap.get("name", attachmentName).asString()); - attachment->x = attachmentMap.get("x", 0).asDouble() * scale; - attachment->y = attachmentMap.get("y", 0).asDouble() * scale; - attachment->scaleX = attachmentMap.get("scaleX", 1).asDouble(); - attachment->scaleY = attachmentMap.get("scaleY", 1).asDouble(); - attachment->rotation = attachmentMap.get("rotation", 0).asDouble(); - attachment->width = attachmentMap.get("width", 32).asDouble() * scale; - attachment->height = attachmentMap.get("height", 32).asDouble() * scale; + + if (type == region || type == regionSequence) { + BaseRegionAttachment *regionAttachment = reinterpret_cast(attachment); + regionAttachment->x = attachmentMap.get("x", 0).asDouble() * scale; + regionAttachment->y = attachmentMap.get("y", 0).asDouble() * scale; + regionAttachment->scaleX = attachmentMap.get("scaleX", 1).asDouble(); + regionAttachment->scaleY = attachmentMap.get("scaleY", 1).asDouble(); + regionAttachment->rotation = attachmentMap.get("rotation", 0).asDouble(); + regionAttachment->width = attachmentMap.get("width", 32).asDouble() * scale; + regionAttachment->height = attachmentMap.get("height", 32).asDouble() * scale; + } skin->addAttachment(slotIndex, attachmentName, attachment); } @@ -157,4 +173,110 @@ SkeletonData* BaseSkeletonJson::readSkeletonData (const char *begin, const char return skeletonData; } +Animation* BaseSkeletonJson::readAnimation (std::ifstream &file, const SkeletonData *skeletonData) const { + if (!file) throw invalid_argument("file cannot be null."); + if (!file.is_open()) throw runtime_error("Animation file is not open."); + + return readAnimation((std::istream&)file, skeletonData); +} + +Animation* BaseSkeletonJson::readAnimation (std::istream &input, const SkeletonData *skeletonData) const { + if (!input) throw invalid_argument("input cannot be null."); + + string json; + std::getline(input, json, (char)EOF); + return readAnimation(json, skeletonData); +} + +Animation* BaseSkeletonJson::readAnimation (const string &json, const SkeletonData *skeletonData) const { + const char *begin = json.c_str(); + const char *end = begin + json.length(); + return readAnimation(begin, end, skeletonData); +} + +Animation* BaseSkeletonJson::readAnimation (const char *begin, const char *end, const SkeletonData *skeletonData) const { + if (!begin) throw invalid_argument("begin cannot be null."); + if (!end) throw invalid_argument("end cannot be null."); + if (!skeletonData) throw invalid_argument("skeletonData cannot be null."); + + static string const TIMELINE_SCALE = "scale"; + static string const TIMELINE_ROTATE = "rotate"; + static string const TIMELINE_TRANSLATE = "translate"; + static string const TIMELINE_ATTACHMENT = "attachment"; + static string const TIMELINE_COLOR = "color"; + + vector timelines; + float duration = 0; + + Json::Value root; + Json::Reader reader; + if (!reader.parse(begin, end, root)) + throw runtime_error("Error parsing animation JSON.\n" + reader.getFormatedErrorMessages()); + + Json::Value bones = root["bones"]; + vector boneNames = bones.getMemberNames(); + for (int i = 0; i < boneNames.size(); i++) { + string boneName = boneNames[i]; + int boneIndex = skeletonData->findBoneIndex(boneName); + if (boneIndex == -1) throw runtime_error("Bone not found: " + boneName); + + Json::Value timelineMap = bones[boneName]; + vector timelineNames = timelineMap.getMemberNames(); + for (int i = 0; i < timelineNames.size(); i++) { + string timelineName = timelineNames[i]; + Json::Value values = timelineMap[timelineName]; + + if (timelineName == TIMELINE_ROTATE) { + RotateTimeline *timeline = new RotateTimeline(values.size()); + timeline->boneIndex = boneIndex; + + int keyframeIndex = 0; + for (int i = 0; i < values.size(); i++) { + Json::Value valueMap = values[i]; + + float time = valueMap["time"].asDouble(); + timeline->setKeyframe(keyframeIndex, time, valueMap["angle"].asDouble()); + // BOZO + // readCurve(timeline, keyframeIndex, valueMap); + keyframeIndex++; + } + timelines.push_back(timeline); + if (timeline->getDuration() > duration) duration = timeline->getDuration(); + + } else if (timelineName == TIMELINE_TRANSLATE || timelineName == TIMELINE_SCALE) { + TranslateTimeline *timeline; + float timelineScale = 1; + if (timelineName == TIMELINE_SCALE) + timeline = new ScaleTimeline(values.size()); + else { + timeline = new TranslateTimeline(values.size()); + timelineScale = scale; + } + timeline->boneIndex = boneIndex; + + int keyframeIndex = 0; + for (int i = 0; i < values.size(); i++) { + Json::Value valueMap = values[i]; + + float time = valueMap["time"].asDouble(); + timeline->setKeyframe(keyframeIndex, // + valueMap["time"].asDouble(), // + valueMap.get("x", 0).asDouble() * timelineScale, // + valueMap.get("y", 0).asDouble() * timelineScale); + // readCurve(timeline, keyframeIndex, valueMap); + keyframeIndex++; + } + timelines.push_back(timeline); + if (timeline->getDuration() > duration) duration = timeline->getDuration(); + + } else { + throw runtime_error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); + } + } + } + + Animation *animation = new Animation(timelines, duration); + return animation; +} + } /* namespace spine */ diff --git a/spine-cpp/src/spine/Slot.cpp b/spine-cpp/src/spine/Slot.cpp index c6f0524b1..6f7734645 100644 --- a/spine-cpp/src/spine/Slot.cpp +++ b/spine-cpp/src/spine/Slot.cpp @@ -12,7 +12,8 @@ Slot::Slot (SlotData *data, BaseSkeleton *skeleton, Bone *bone) : g(1), b(1), a(1), - attachment(0) { + attachment(0), + attachmentTime(0) { if (!data) throw std::invalid_argument("data cannot be null."); if (!skeleton) throw std::invalid_argument("skeleton cannot be null."); if (!bone) throw std::invalid_argument("bone cannot be null."); diff --git a/spine-libgdx/src/com/esotericsoftware/spine/Animation.java b/spine-libgdx/src/com/esotericsoftware/spine/Animation.java index 3148feb2d..418fdd90f 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/Animation.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/Animation.java @@ -35,9 +35,9 @@ public class Animation { if (loop && duration != 0) time %= duration; - Array timeline = this.timelines; - for (int i = 0, n = timeline.size; i < n; i++) - timeline.get(i).apply(skeleton, time, 1); + Array timelines = this.timelines; + for (int i = 0, n = timelines.size; i < n; i++) + timelines.get(i).apply(skeleton, time, 1); } /** Poses the skeleton at the specified time for this animation mixed with the current pose. @@ -47,9 +47,9 @@ public class Animation { if (loop && duration != 0) time %= duration; - Array timeline = this.timelines; - for (int i = 0, n = timeline.size; i < n; i++) - timeline.get(i).apply(skeleton, time, alpha); + Array timelines = this.timelines; + for (int i = 0, n = timelines.size; i < n; i++) + timelines.get(i).apply(skeleton, time, alpha); } /** @param target After the first and before the last entry. */ diff --git a/spine-libgdx/src/com/esotericsoftware/spine/Attachment.java b/spine-libgdx/src/com/esotericsoftware/spine/Attachment.java index aaa7528a2..be35e97b6 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/Attachment.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/Attachment.java @@ -6,7 +6,6 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch; abstract public class Attachment { final String name; boolean resolved; - private float x, y, scaleX, scaleY, rotation, width, height; public Attachment (String name) { if (name == null) throw new IllegalArgumentException("name cannot be null."); @@ -17,62 +16,6 @@ abstract public class Attachment { abstract public void draw (SpriteBatch batch, Slot slot); - public float getX () { - return x; - } - - public void setX (float x) { - this.x = x; - } - - public float getY () { - return y; - } - - public void setY (float y) { - this.y = y; - } - - public float getScaleX () { - return scaleX; - } - - public void setScaleX (float scaleX) { - this.scaleX = scaleX; - } - - public float getScaleY () { - return scaleY; - } - - public void setScaleY (float scaleY) { - this.scaleY = scaleY; - } - - public float getRotation () { - return rotation; - } - - public void setRotation (float rotation) { - this.rotation = rotation; - } - - public float getWidth () { - return width; - } - - public void setWidth (float width) { - this.width = width; - } - - public float getHeight () { - return height; - } - - public void setHeight (float height) { - this.height = height; - } - public boolean isResolved () { return resolved; } diff --git a/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java b/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java index 5480b536b..225c5a346 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java @@ -149,13 +149,17 @@ public class SkeletonBinary { throw new SerializationException("Unknown attachment type: " + type + " (" + name + ")"); } - attachment.setX(input.readFloat() * scale); - attachment.setY(input.readFloat() * scale); - attachment.setScaleX(input.readFloat()); - attachment.setScaleY(input.readFloat()); - attachment.setRotation(input.readFloat()); - attachment.setWidth(input.readFloat() * scale); - attachment.setHeight(input.readFloat() * scale); + if (attachment instanceof RegionAttachment) { + RegionAttachment regionAttachment = (RegionAttachment)attachment; + regionAttachment.setX(input.readFloat() * scale); + regionAttachment.setY(input.readFloat() * scale); + regionAttachment.setScaleX(input.readFloat()); + regionAttachment.setScaleY(input.readFloat()); + regionAttachment.setRotation(input.readFloat()); + regionAttachment.setWidth(input.readFloat() * scale); + regionAttachment.setHeight(input.readFloat() * scale); + } + return attachment; } diff --git a/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java b/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java index 0dcd5f04e..4c441f057 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java @@ -140,13 +140,17 @@ public class SkeletonJson { } else throw new SerializationException("Unknown attachment type: " + type + " (" + name + ")"); - attachment.setX(getFloat(map, "x", 0) * scale); - attachment.setY(getFloat(map, "y", 0) * scale); - attachment.setScaleX(getFloat(map, "scaleX", 1)); - attachment.setScaleY(getFloat(map, "scaleY", 1)); - attachment.setRotation(getFloat(map, "rotation", 0)); - attachment.setWidth(getFloat(map, "width", 32) * scale); - attachment.setHeight(getFloat(map, "height", 32) * scale); + if (attachment instanceof RegionAttachment) { + RegionAttachment regionAttachment = (RegionAttachment)attachment; + regionAttachment.setX(getFloat(map, "x", 0) * scale); + regionAttachment.setY(getFloat(map, "y", 0) * scale); + regionAttachment.setScaleX(getFloat(map, "scaleX", 1)); + regionAttachment.setScaleY(getFloat(map, "scaleY", 1)); + regionAttachment.setRotation(getFloat(map, "rotation", 0)); + regionAttachment.setWidth(getFloat(map, "width", 32) * scale); + regionAttachment.setHeight(getFloat(map, "height", 32) * scale); + } + return attachment; } @@ -170,12 +174,12 @@ public class SkeletonJson { String boneName = entry.key; int boneIndex = skeletonData.findBoneIndex(boneName); if (boneIndex == -1) throw new SerializationException("Bone not found: " + boneName); - OrderedMap propertyMap = (OrderedMap)entry.value; - for (Entry propertyEntry : propertyMap.entries()) { - Array values = (Array)propertyEntry.value; - String timelineType = (String)propertyEntry.key; - if (timelineType.equals(TIMELINE_ROTATE)) { + OrderedMap timelineMap = (OrderedMap)entry.value; + for (Entry timelineEntry : timelineMap.entries()) { + Array values = (Array)timelineEntry.value; + String timelineName = (String)timelineEntry.key; + if (timelineName.equals(TIMELINE_ROTATE)) { RotateTimeline timeline = new RotateTimeline(values.size); timeline.setBoneIndex(boneIndex); @@ -189,10 +193,10 @@ public class SkeletonJson { timelines.add(timeline); duration = Math.max(duration, timeline.getDuration()); - } else if (timelineType.equals(TIMELINE_TRANSLATE) || timelineType.equals(TIMELINE_SCALE)) { + } else if (timelineName.equals(TIMELINE_TRANSLATE) || timelineName.equals(TIMELINE_SCALE)) { TranslateTimeline timeline; float timelineScale = 1; - if (timelineType.equals(TIMELINE_SCALE)) + if (timelineName.equals(TIMELINE_SCALE)) timeline = new ScaleTimeline(values.size); else { timeline = new TranslateTimeline(values.size); @@ -213,7 +217,7 @@ public class SkeletonJson { duration = Math.max(duration, timeline.getDuration()); } else - throw new RuntimeException("Invalid timeline type for a bone: " + timelineType + " (" + boneName + ")"); + throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); } } diff --git a/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java b/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java index a5cf355da..26beb3297 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java @@ -17,6 +17,7 @@ import com.badlogic.gdx.utils.NumberUtils; /** Attachment that displays a texture region. */ public class RegionAttachment extends Attachment { private TextureRegion region; + private float x, y, scaleX, scaleY, rotation, width, height; private final float[] vertices = new float[20]; private final float[] offset = new float[8]; @@ -150,4 +151,60 @@ public class RegionAttachment extends Attachment { public float[] getWorldVertices () { return vertices; } + + public float getX () { + return x; + } + + public void setX (float x) { + this.x = x; + } + + public float getY () { + return y; + } + + public void setY (float y) { + this.y = y; + } + + public float getScaleX () { + return scaleX; + } + + public void setScaleX (float scaleX) { + this.scaleX = scaleX; + } + + public float getScaleY () { + return scaleY; + } + + public void setScaleY (float scaleY) { + this.scaleY = scaleY; + } + + public float getRotation () { + return rotation; + } + + public void setRotation (float rotation) { + this.rotation = rotation; + } + + public float getWidth () { + return width; + } + + public void setWidth (float width) { + this.width = width; + } + + public float getHeight () { + return height; + } + + public void setHeight (float height) { + this.height = height; + } }