mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
cpp, loading, applying and animating with SFML is working.
This commit is contained in:
parent
268933242f
commit
6710c1e9c9
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -15,6 +15,8 @@ public:
|
||||
float duration;
|
||||
|
||||
Animation (const std::vector<Timeline*> &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);
|
||||
};
|
||||
|
||||
@ -11,7 +11,6 @@ class Slot;
|
||||
class Attachment {
|
||||
public:
|
||||
std::string name;
|
||||
float x, y, scaleX, scaleY, rotation, width, height;
|
||||
|
||||
virtual ~Attachment () {
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ class Slot;
|
||||
|
||||
class BaseRegionAttachment: public Attachment {
|
||||
public:
|
||||
float x, y, scaleX, scaleY, rotation, width, height;
|
||||
float offset[8];
|
||||
|
||||
void updateOffset ();
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <math.h>
|
||||
#include <spine/Animation.h>
|
||||
#include <spine/Bone.h>
|
||||
#include <spine/Slot.h>
|
||||
@ -14,6 +18,15 @@ Animation::Animation (const vector<Timeline*> &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 () {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -4,17 +4,30 @@
|
||||
#include <json/json.h>
|
||||
#include <spine/BaseSkeletonJson.h>
|
||||
#include <spine/BaseAttachmentLoader.h>
|
||||
#include <spine/BaseRegionAttachment.h>
|
||||
#include <spine/SkeletonData.h>
|
||||
#include <spine/BoneData.h>
|
||||
#include <spine/SlotData.h>
|
||||
#include <spine/Skin.h>
|
||||
#include <spine/Animation.h>
|
||||
|
||||
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<BaseRegionAttachment*>(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<Timeline*> 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<string> 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<string> 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 */
|
||||
|
||||
@ -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.");
|
||||
|
||||
@ -35,9 +35,9 @@ public class Animation {
|
||||
|
||||
if (loop && duration != 0) time %= duration;
|
||||
|
||||
Array<Timeline> timeline = this.timelines;
|
||||
for (int i = 0, n = timeline.size; i < n; i++)
|
||||
timeline.get(i).apply(skeleton, time, 1);
|
||||
Array<Timeline> 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> timeline = this.timelines;
|
||||
for (int i = 0, n = timeline.size; i < n; i++)
|
||||
timeline.get(i).apply(skeleton, time, alpha);
|
||||
Array<Timeline> 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. */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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<OrderedMap> 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<OrderedMap> 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 + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user