cpp, loading, applying and animating with SFML is working.

This commit is contained in:
NathanSweet 2013-02-22 20:04:32 +01:00
parent 268933242f
commit 6710c1e9c9
18 changed files with 323 additions and 142 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);
};

View File

@ -11,7 +11,6 @@ class Slot;
class Attachment {
public:
std::string name;
float x, y, scaleX, scaleY, rotation, width, height;
virtual ~Attachment () {
}

View File

@ -10,6 +10,7 @@ class Slot;
class BaseRegionAttachment: public Attachment {
public:
float x, y, scaleX, scaleY, rotation, width, height;
float offset[8];
void updateOffset ();

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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 () {

View File

@ -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;

View File

@ -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 */

View File

@ -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.");

View File

@ -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. */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 + ")");
}
}

View File

@ -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;
}
}