2011-08-03 20:05:33 +00:00
|
|
|
|
/*
|
|
|
|
|
Copyright (C) 2007, 2010 - Bit-Blot
|
|
|
|
|
|
|
|
|
|
This file is part of Aquaria.
|
|
|
|
|
|
|
|
|
|
Aquaria is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
*/
|
|
|
|
|
#include "SkeletalSprite.h"
|
|
|
|
|
#include "Core.h"
|
|
|
|
|
#include "Particles.h"
|
|
|
|
|
#include "MathFunctions.h"
|
|
|
|
|
#include "SimpleIStringStream.h"
|
2016-07-09 02:18:40 +00:00
|
|
|
|
#include "ReadXML.h"
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
#include "tinyxml2.h"
|
|
|
|
|
using namespace tinyxml2;
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
std::string SkeletalSprite::animationPath = "data/animations/";
|
|
|
|
|
std::string SkeletalSprite::skinPath = "skins/";
|
|
|
|
|
|
|
|
|
|
std::string SkeletalSprite::secondaryAnimationPath = "";
|
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
static std::map<std::string, XMLDocument*> skelCache;
|
2012-02-19 03:57:04 +00:00
|
|
|
|
|
2014-09-15 22:29:57 +00:00
|
|
|
|
static XMLDocument *_retrieveSkeletalXML(const std::string& name, bool keepEmpty)
|
2012-02-19 03:57:04 +00:00
|
|
|
|
{
|
2014-06-09 21:39:33 +00:00
|
|
|
|
std::map<std::string, XMLDocument*>::iterator it = skelCache.find(name);
|
|
|
|
|
if(it != skelCache.end())
|
|
|
|
|
return it->second;
|
|
|
|
|
|
2014-09-15 22:29:57 +00:00
|
|
|
|
XMLDocument *doc = readXML(name, NULL, keepEmpty);
|
2014-06-09 21:39:33 +00:00
|
|
|
|
if(doc)
|
2014-06-08 20:11:23 +00:00
|
|
|
|
skelCache[name] = doc;
|
2014-06-09 21:39:33 +00:00
|
|
|
|
|
2012-02-19 03:57:04 +00:00
|
|
|
|
return doc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::clearCache()
|
|
|
|
|
{
|
2014-09-15 22:29:57 +00:00
|
|
|
|
for(std::map<std::string, XMLDocument*>::iterator it = skelCache.begin(); it != skelCache.end(); ++it)
|
|
|
|
|
delete it->second;
|
2012-02-19 03:57:04 +00:00
|
|
|
|
skelCache.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
void SkeletalKeyframe::copyAllButTime(SkeletalKeyframe *copy)
|
|
|
|
|
{
|
|
|
|
|
if (!copy) return;
|
|
|
|
|
|
|
|
|
|
float t = this->t;
|
|
|
|
|
(*this) = (*copy);
|
|
|
|
|
this->t = t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bone::Bone() : Quad()
|
|
|
|
|
{
|
2012-01-03 03:38:28 +00:00
|
|
|
|
addType(SCO_BONE);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
fileRenderQuad = true;
|
|
|
|
|
skeleton = 0;
|
|
|
|
|
generateCollisionMask = true;
|
|
|
|
|
animated = ANIM_ALL;
|
|
|
|
|
originalScale = Vector(1,1);
|
|
|
|
|
boneIdx = pidx = -1;
|
|
|
|
|
rbp = 0;
|
|
|
|
|
segmentChain = 0;
|
|
|
|
|
|
|
|
|
|
minDist = maxDist = 128;
|
|
|
|
|
reverse = false;
|
2016-04-18 20:08:36 +00:00
|
|
|
|
selectable = true;
|
2016-04-17 12:33:23 +00:00
|
|
|
|
originalRenderPass = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2016-07-09 02:18:40 +00:00
|
|
|
|
ParticleEffect *Bone::getEmitter(unsigned slot) const
|
|
|
|
|
{
|
|
|
|
|
return slot < emitters.size() ? emitters[slot] : NULL;
|
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
void Bone::destroy()
|
|
|
|
|
{
|
|
|
|
|
Quad::destroy();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < segments.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
segments[i]->setLife(1.0);
|
|
|
|
|
segments[i]->setDecayRate(10);
|
|
|
|
|
segments[i]->alpha = 0;
|
|
|
|
|
}
|
|
|
|
|
segments.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Bone::addSegment(Bone *b)
|
|
|
|
|
{
|
|
|
|
|
segments.push_back(b);
|
|
|
|
|
|
|
|
|
|
b->segmentChain = 2;
|
|
|
|
|
|
|
|
|
|
skeleton->removeChild(b);
|
|
|
|
|
|
|
|
|
|
core->getTopStateData()->addRenderObject(b, skeleton->getTopLayer());
|
|
|
|
|
b->position = this->getWorldPosition();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Bone::createStrip(bool vert, int num)
|
|
|
|
|
{
|
|
|
|
|
if (!vert)
|
|
|
|
|
{
|
|
|
|
|
createGrid(num, 2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
createGrid(2, num);
|
|
|
|
|
}
|
|
|
|
|
stripVert = vert;
|
|
|
|
|
gridType = GRID_SET;
|
|
|
|
|
changeStrip.resize(num);
|
|
|
|
|
setGridPoints(vert, strip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Quad* Bone::addFrame(const std::string &gfx)
|
|
|
|
|
{
|
|
|
|
|
renderQuad = false;
|
|
|
|
|
Quad *q = new Quad();
|
|
|
|
|
q->setTexture(gfx);
|
|
|
|
|
q->renderBeforeParent = 1;
|
|
|
|
|
addChild(q, PM_POINTER);
|
|
|
|
|
return q;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Bone::showFrame(int idx)
|
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
int c = 0;
|
|
|
|
|
for (Children::iterator i = children.begin(); i != children.end(); i++)
|
|
|
|
|
{
|
|
|
|
|
RenderObject *r = (*i);
|
|
|
|
|
if (idx == c)
|
|
|
|
|
{
|
|
|
|
|
if (r->alpha == 0)
|
|
|
|
|
{
|
|
|
|
|
r->alpha = 1;
|
|
|
|
|
|
|
|
|
|
// add option to turn on alpha fading
|
|
|
|
|
//r->alpha.interpolateTo(1, t);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
r->alpha = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (r->alpha == 1)
|
|
|
|
|
{
|
|
|
|
|
r->alpha = 0;
|
|
|
|
|
//r->alpha.interpolateTo(0, t*2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
r->alpha = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
c++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Bone::setAnimated(int b)
|
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
animated = b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Bone::setSegmentProps(int minDist, int maxDist, bool reverse)
|
|
|
|
|
{
|
|
|
|
|
this->minDist = minDist;
|
|
|
|
|
this->maxDist = maxDist;
|
|
|
|
|
this->reverse = reverse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Bone::updateSegment(Bone *b, const Vector &diff)
|
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
float angle = -1;
|
|
|
|
|
if (diff.getSquaredLength2D() > sqr(maxDist))
|
|
|
|
|
{
|
|
|
|
|
Vector useDiff = diff;
|
|
|
|
|
useDiff.setLength2D(maxDist);
|
|
|
|
|
Vector reallyUseDiff = diff - useDiff;
|
|
|
|
|
b->position += reallyUseDiff;
|
|
|
|
|
|
|
|
|
|
MathFunctions::calculateAngleBetweenVectorsInDegrees(Vector(0,0,0), diff, angle);
|
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
else if (diff.getSquaredLength2D() > sqr(minDist))
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
|
|
|
|
b->position += diff*0.05f;
|
|
|
|
|
|
|
|
|
|
MathFunctions::calculateAngleBetweenVectorsInDegrees(Vector(0,0,0), diff, angle);
|
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
if (angle != -1)
|
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
if (b->rotation.z >= 270 && angle < 90)
|
|
|
|
|
{
|
|
|
|
|
b->rotation.stop();
|
|
|
|
|
b->rotation.z -= 360;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b->rotation.z <= 90 && angle > 270)
|
|
|
|
|
{
|
|
|
|
|
b->rotation.stop();
|
|
|
|
|
b->rotation.z += 360;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
b->rotation.interpolateTo(Vector(0,0,angle),0.2);
|
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Bone::updateSegments()
|
|
|
|
|
{
|
|
|
|
|
if (segmentChain>0 && !segments.empty())
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!reverse)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < segments.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
Vector diff;
|
|
|
|
|
if (i == 0)
|
|
|
|
|
{
|
|
|
|
|
Vector world = getWorldCollidePosition(segmentOffset);
|
|
|
|
|
diff = world - segments[i]->getWorldPosition();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
diff = segments[i-1]->getWorldPosition() - segments[i]->getWorldPosition();
|
|
|
|
|
|
|
|
|
|
updateSegment(segments[i], diff);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int top = segments.size()-1;
|
|
|
|
|
for (int i = top; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
Vector diff;
|
|
|
|
|
if (i == top)
|
|
|
|
|
{
|
|
|
|
|
Vector world = getWorldCollidePosition(segmentOffset);
|
|
|
|
|
diff = world - segments[i]->getWorldPosition();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
diff = segments[i+1]->getWorldPosition() - segments[i]->getWorldPosition();
|
|
|
|
|
|
|
|
|
|
updateSegment(segments[i], diff);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-17 13:16:55 +00:00
|
|
|
|
bool BoneCommand::parse(Bone *b, SimpleIStringStream &is)
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
|
|
|
|
std::string type;
|
|
|
|
|
is >> type;
|
|
|
|
|
this->b = b;
|
|
|
|
|
if (type=="AC_PRT_LOAD")
|
|
|
|
|
{
|
|
|
|
|
command = AC_PRT_LOAD;
|
|
|
|
|
is >> slot >> file;
|
|
|
|
|
}
|
|
|
|
|
else if (type=="AC_SND_PLAY")
|
|
|
|
|
{
|
|
|
|
|
command = AC_SND_PLAY;
|
|
|
|
|
is >> file;
|
|
|
|
|
}
|
|
|
|
|
else if (type=="AC_FRM_SHOW")
|
|
|
|
|
{
|
|
|
|
|
command = AC_FRM_SHOW;
|
|
|
|
|
is >> slot;
|
|
|
|
|
}
|
|
|
|
|
else if (type=="AC_PRT_START")
|
|
|
|
|
{
|
|
|
|
|
command = AC_PRT_START;
|
|
|
|
|
is >> slot;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
else if (type=="AC_PRT_STOP")
|
|
|
|
|
{
|
|
|
|
|
command = AC_PRT_STOP;
|
|
|
|
|
is >> slot;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
else if (type=="AC_SEGS_START")
|
|
|
|
|
command = AC_SEGS_START;
|
|
|
|
|
else if (type=="AC_SEGS_STOP")
|
|
|
|
|
command = AC_SEGS_STOP;
|
2016-04-17 12:33:23 +00:00
|
|
|
|
else if (type == "AC_SET_PASS")
|
|
|
|
|
{
|
|
|
|
|
command = AC_SET_PASS;
|
|
|
|
|
is >> slot;
|
|
|
|
|
}
|
|
|
|
|
else if(type == "AC_RESET_PASS")
|
|
|
|
|
command = AC_RESET_PASS;
|
2016-04-17 13:16:55 +00:00
|
|
|
|
else // fail
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << "Failed to parse bone command string: invalid command: " << type;
|
|
|
|
|
errorLog(os.str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BoneCommand::run()
|
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
switch(command)
|
|
|
|
|
{
|
|
|
|
|
case AC_SND_PLAY:
|
|
|
|
|
{
|
|
|
|
|
core->sound->playSfx(file);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AC_FRM_SHOW:
|
|
|
|
|
{
|
|
|
|
|
b->showFrame(slot);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AC_PRT_LOAD:
|
|
|
|
|
{
|
2016-07-09 02:18:40 +00:00
|
|
|
|
ParticleEffect *e = b->getEmitter(slot);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (e)
|
|
|
|
|
{
|
|
|
|
|
e->load(file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AC_PRT_START:
|
|
|
|
|
{
|
2016-07-09 02:18:40 +00:00
|
|
|
|
ParticleEffect *e = b->getEmitter(slot);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (e)
|
|
|
|
|
e->start();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case AC_PRT_STOP:
|
|
|
|
|
{
|
2016-07-09 02:18:40 +00:00
|
|
|
|
ParticleEffect *e = b->getEmitter(slot);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (e)
|
|
|
|
|
e->stop();
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-04-17 12:33:23 +00:00
|
|
|
|
case AC_SET_PASS:
|
|
|
|
|
b->setRenderPass(slot);
|
|
|
|
|
break;
|
|
|
|
|
case AC_RESET_PASS:
|
|
|
|
|
b->setRenderPass(b->originalRenderPass);
|
|
|
|
|
break;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AnimationLayer::AnimationLayer()
|
|
|
|
|
{
|
|
|
|
|
lastNewKey = 0;
|
|
|
|
|
fallThru= 0;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
timer = 0;
|
|
|
|
|
loop = 0;
|
|
|
|
|
enqueuedAnimationLoop = 0;
|
|
|
|
|
timeMultiplier = 1;
|
|
|
|
|
animationLength = 0;
|
|
|
|
|
currentAnimation = 0;
|
|
|
|
|
animating = false;
|
|
|
|
|
fallThruSpeed = 0;
|
|
|
|
|
s = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimationLayer::setTimeMultiplier(float t)
|
|
|
|
|
{
|
|
|
|
|
timeMultiplier = t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimationLayer::playCurrentAnimation(int loop)
|
|
|
|
|
{
|
|
|
|
|
playAnimation(currentAnimation, loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimationLayer::animate(const std::string &a, int loop)
|
|
|
|
|
{
|
|
|
|
|
std::string animation = a;
|
|
|
|
|
stringToLower(animation);
|
|
|
|
|
|
|
|
|
|
bool played = false;
|
|
|
|
|
for (int i = 0; i < s->animations.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (s->animations[i].name == animation)
|
|
|
|
|
{
|
|
|
|
|
playAnimation(i, loop);
|
|
|
|
|
played = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!played)
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << "Could not find animation: " << animation;
|
|
|
|
|
debugLog(os.str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimationLayer::playAnimation(int idx, int loop)
|
|
|
|
|
{
|
|
|
|
|
if (!(&s->animLayers[0] == this))
|
|
|
|
|
{
|
|
|
|
|
fallThru = 1;
|
|
|
|
|
fallThruSpeed = 10;
|
|
|
|
|
}
|
|
|
|
|
timeMultiplier = 1;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
currentAnimation = idx;
|
|
|
|
|
timer = 0;
|
|
|
|
|
animating = true;
|
|
|
|
|
|
|
|
|
|
this->loop = loop;
|
|
|
|
|
|
|
|
|
|
animationLength = getCurrentAnimation()->getAnimationLength();
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-03 15:13:07 +00:00
|
|
|
|
void AnimationLayer::enqueueAnimation(const std::string& anim, int loop)
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
|
|
|
|
enqueuedAnimation = anim;
|
|
|
|
|
enqueuedAnimationLoop = loop;
|
|
|
|
|
stringToLower(enqueuedAnimation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float AnimationLayer::transitionAnimate(std::string anim, float time, int loop)
|
|
|
|
|
{
|
|
|
|
|
stringToLower(anim);
|
|
|
|
|
float totalTime =0;
|
|
|
|
|
if (createTransitionAnimation(anim, time))
|
|
|
|
|
{
|
|
|
|
|
timeMultiplier = 1;
|
|
|
|
|
|
|
|
|
|
currentAnimation = -1;
|
|
|
|
|
this->loop = 0;
|
|
|
|
|
timer = 0;
|
|
|
|
|
animating = 1;
|
|
|
|
|
animationLength = getCurrentAnimation()->getAnimationLength();
|
|
|
|
|
enqueueAnimation(anim, loop);
|
|
|
|
|
Animation *a = this->s->getAnimation(anim);
|
|
|
|
|
if (a)
|
|
|
|
|
{
|
|
|
|
|
if (loop > -1)
|
|
|
|
|
totalTime = a->getAnimationLength()*(loop+1) + time;
|
|
|
|
|
else
|
|
|
|
|
totalTime = a->getAnimationLength() + time;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return totalTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimationLayer::setSkeletalSprite(SkeletalSprite *s)
|
|
|
|
|
{
|
|
|
|
|
this->s = s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Animation* AnimationLayer::getCurrentAnimation()
|
|
|
|
|
{
|
|
|
|
|
if (currentAnimation == -1)
|
|
|
|
|
return &blendAnimation;
|
|
|
|
|
if (currentAnimation < 0 || currentAnimation >= s->animations.size())
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << "skel: " << s->filenameLoaded << " currentAnimation: " << currentAnimation << " is out of range\n error in anim file?";
|
2013-06-23 16:50:10 +00:00
|
|
|
|
exit_error(os.str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return &s->animations[currentAnimation];
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-03 15:13:07 +00:00
|
|
|
|
bool AnimationLayer::createTransitionAnimation(const std::string& anim, float time)
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
Animation *to = s->getAnimation(anim);
|
|
|
|
|
if (!to) return false;
|
|
|
|
|
blendAnimation.keyframes.clear();
|
|
|
|
|
SkeletalKeyframe k;
|
|
|
|
|
k.t = 0;
|
|
|
|
|
for (int i = 0; i < s->bones.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
BoneKeyframe b;
|
|
|
|
|
b.idx = s->bones[i]->boneIdx;
|
|
|
|
|
b.x = s->bones[i]->position.x;
|
|
|
|
|
b.y = s->bones[i]->position.y;
|
|
|
|
|
b.rot = s->bones[i]->rotation.z;
|
|
|
|
|
b.strip = s->bones[i]->strip;
|
|
|
|
|
b.sx = s->bones[i]->scale.x;
|
|
|
|
|
b.sy = s->bones[i]->scale.y;
|
|
|
|
|
k.keyframes.push_back(b);
|
|
|
|
|
}
|
|
|
|
|
blendAnimation.keyframes.push_back(k);
|
|
|
|
|
|
|
|
|
|
SkeletalKeyframe k2;
|
|
|
|
|
SkeletalKeyframe *rk = to->getKeyframe(0);
|
|
|
|
|
if (!rk) return false;
|
|
|
|
|
k2 = *rk;
|
|
|
|
|
k2.t = time;
|
|
|
|
|
blendAnimation.keyframes.push_back(k2);
|
|
|
|
|
|
|
|
|
|
blendAnimation.name = anim;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void AnimationLayer::stopAnimation()
|
|
|
|
|
{
|
2016-04-17 12:33:23 +00:00
|
|
|
|
if(s->loaded && getCurrentAnimation()->resetPassOnEnd)
|
|
|
|
|
resetPass();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
animating = false;
|
|
|
|
|
if (!enqueuedAnimation.empty())
|
|
|
|
|
{
|
|
|
|
|
animate(enqueuedAnimation, enqueuedAnimationLoop);
|
|
|
|
|
enqueuedAnimation = "";
|
2013-02-03 15:13:07 +00:00
|
|
|
|
enqueuedAnimationLoop = 0;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AnimationLayer::isAnimating()
|
|
|
|
|
{
|
|
|
|
|
return animating;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float AnimationLayer::getAnimationLength()
|
|
|
|
|
{
|
|
|
|
|
return animationLength;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-17 12:33:23 +00:00
|
|
|
|
Animation::Animation()
|
|
|
|
|
: resetPassOnEnd(false)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
int Animation::getNumKeyframes()
|
|
|
|
|
{
|
|
|
|
|
return keyframes.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SkeletalKeyframe *Animation::getKeyframe(int key)
|
|
|
|
|
{
|
|
|
|
|
if (key < 0 || key >= keyframes.size()) return 0;
|
|
|
|
|
return &keyframes[key];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Animation::reverse()
|
|
|
|
|
{
|
|
|
|
|
Keyframes copy = keyframes;
|
|
|
|
|
Keyframes copy2 = keyframes;
|
|
|
|
|
keyframes.clear();
|
|
|
|
|
int sz = copy.size()-1;
|
|
|
|
|
for (int i = sz; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
keyframes.push_back(copy[i]);
|
|
|
|
|
keyframes[keyframes.size()-1].t = copy2[sz-i].t;
|
|
|
|
|
}
|
|
|
|
|
reorderKeyframes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float Animation::getAnimationLength()
|
|
|
|
|
{
|
|
|
|
|
return getLastKeyframe()->t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SkeletalKeyframe *Animation::getLastKeyframe()
|
|
|
|
|
{
|
|
|
|
|
if (!keyframes.empty())
|
|
|
|
|
return &keyframes[keyframes.size()-1];
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SkeletalKeyframe *Animation::getFirstKeyframe()
|
|
|
|
|
{
|
|
|
|
|
if (!keyframes.empty())
|
|
|
|
|
return &keyframes[0];
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Animation::reorderKeyframes()
|
|
|
|
|
{
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
for (int i = 0; i < keyframes.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < keyframes.size()-1; j++)
|
|
|
|
|
{
|
|
|
|
|
if (keyframes[j].t > keyframes[j+1].t)
|
|
|
|
|
{
|
|
|
|
|
SkeletalKeyframe temp = keyframes[j+1];
|
|
|
|
|
keyframes[j+1] = keyframes[j];
|
|
|
|
|
keyframes[j] = temp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Animation::cloneKey(int key, float toffset)
|
|
|
|
|
{
|
|
|
|
|
std::vector<SkeletalKeyframe> copy = this->keyframes;
|
|
|
|
|
keyframes.clear();
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (i = 0; i <= key; i++)
|
|
|
|
|
keyframes.push_back(copy[i]);
|
|
|
|
|
for (i = key; i < copy.size(); i++)
|
|
|
|
|
keyframes.push_back(copy[i]);
|
|
|
|
|
keyframes[key+1].t += toffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Animation::deleteKey(int key)
|
|
|
|
|
{
|
|
|
|
|
std::vector<SkeletalKeyframe> copy = this->keyframes;
|
|
|
|
|
keyframes.clear();
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (i = 0; i < key; i++)
|
|
|
|
|
keyframes.push_back(copy[i]);
|
|
|
|
|
for (i = key+1; i < copy.size(); i++)
|
|
|
|
|
keyframes.push_back(copy[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Animation::getSkeletalKeyframeIndex(SkeletalKeyframe *skey)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < keyframes.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (&keyframes[i] == skey)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BoneKeyframe *SkeletalKeyframe::getBoneKeyframe(int idx)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < keyframes.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (keyframes[i].idx == idx)
|
|
|
|
|
{
|
|
|
|
|
return &keyframes[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SkeletalKeyframe *Animation::getPrevKeyframe(float t)
|
|
|
|
|
{
|
|
|
|
|
int kf = -1;
|
|
|
|
|
for (int i = keyframes.size()-1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
if (t >= keyframes[i].t)
|
|
|
|
|
{
|
|
|
|
|
kf = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (kf == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
if (kf >= keyframes.size())
|
|
|
|
|
kf = keyframes.size()-1;
|
|
|
|
|
if (kf < 0)
|
|
|
|
|
kf = 0;
|
|
|
|
|
return &keyframes[kf];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SkeletalKeyframe *Animation::getNextKeyframe(float t)
|
|
|
|
|
{
|
|
|
|
|
int kf = -1;
|
|
|
|
|
for (int i = 0; i < keyframes.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (t <= keyframes[i].t)
|
|
|
|
|
{
|
|
|
|
|
kf = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (kf == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
if (kf >= keyframes.size())
|
|
|
|
|
kf = keyframes.size()-1;
|
|
|
|
|
if (kf < 0)
|
|
|
|
|
kf = 0;
|
|
|
|
|
return &keyframes[kf];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SkeletalSprite::SkeletalSprite() : RenderObject()
|
|
|
|
|
{
|
|
|
|
|
frozen = false;
|
|
|
|
|
animKeyNotify = 0;
|
|
|
|
|
loaded = false;
|
|
|
|
|
animLayers.resize(10);
|
|
|
|
|
for (int i = 0; i < animLayers.size(); i++)
|
|
|
|
|
animLayers[i].setSkeletalSprite(this);
|
|
|
|
|
selectedBone = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::setAnimationKeyNotify(RenderObject *r)
|
|
|
|
|
{
|
|
|
|
|
animKeyNotify = r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::animate(const std::string &animation, int loop, int layer)
|
|
|
|
|
{
|
|
|
|
|
animLayers[layer].animate(animation, loop);
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-13 23:58:59 +00:00
|
|
|
|
float SkeletalSprite::transitionAnimate(const std::string& anim, float time, int loop, int layer)
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
|
|
|
|
AnimationLayer *animLayer = getAnimationLayer(layer);
|
|
|
|
|
if (animLayer)
|
|
|
|
|
return animLayer->transitionAnimate(anim, time, loop);
|
|
|
|
|
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << "playing animation on invalid layer: " << layer;
|
|
|
|
|
errorLog(os.str());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AnimationLayer* SkeletalSprite::getAnimationLayer(int l)
|
|
|
|
|
{
|
|
|
|
|
if (l >= 0 && l < animLayers.size())
|
|
|
|
|
{
|
|
|
|
|
return &animLayers[l];
|
|
|
|
|
}
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << "couldn't get animLayer: " << l;
|
|
|
|
|
debugLog(os.str());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SkeletalSprite::isLoaded()
|
|
|
|
|
{
|
|
|
|
|
return loaded;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::onUpdate(float dt)
|
|
|
|
|
{
|
|
|
|
|
if (frozen) return;
|
|
|
|
|
RenderObject::onUpdate(dt);
|
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < bones.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
Bone *b = bones[i];
|
|
|
|
|
if (b && !b->collisionMask.empty())
|
|
|
|
|
{
|
|
|
|
|
if (b->collisionMask.size() != b->transformedCollisionMask.size())
|
|
|
|
|
{
|
|
|
|
|
b->transformedCollisionMask.resize(b->collisionMask.size());
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < b->collisionMask.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
b->transformedCollisionMask[i] = b->getWorldCollidePosition(b->collisionMask[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
for (i = 0; i < animLayers.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
animLayers[i].update(dt);
|
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AnimationLayer::update(float dt)
|
|
|
|
|
{
|
|
|
|
|
timeMultiplier.update(dt);
|
|
|
|
|
if (animating)
|
|
|
|
|
{
|
|
|
|
|
timer += dt*timeMultiplier.x;
|
|
|
|
|
|
|
|
|
|
if (timer > animationLength)
|
|
|
|
|
{
|
|
|
|
|
float leftover;
|
|
|
|
|
if (animationLength > 0)
|
|
|
|
|
leftover = fmodf(timer, animationLength);
|
|
|
|
|
else
|
|
|
|
|
leftover = 0;
|
|
|
|
|
timer = animationLength;
|
|
|
|
|
if (loop==-1 || loop > 0)
|
|
|
|
|
{
|
|
|
|
|
playAnimation(this->currentAnimation, loop);
|
|
|
|
|
if (loop > 0)
|
|
|
|
|
loop --;
|
|
|
|
|
timer = leftover;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
stopAnimation();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
updateBones();
|
|
|
|
|
}
|
|
|
|
|
else if (!animating)
|
|
|
|
|
{
|
|
|
|
|
if (fallThru > 0)
|
|
|
|
|
{
|
|
|
|
|
fallThru -= dt * fallThruSpeed;
|
|
|
|
|
if (fallThru < 0)
|
|
|
|
|
fallThru = 0;
|
|
|
|
|
updateBones();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-28 03:42:02 +00:00
|
|
|
|
bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
|
|
|
|
std::string file, filename=fn;
|
|
|
|
|
stringToLower(filename);
|
|
|
|
|
|
|
|
|
|
if (!secondaryAnimationPath.empty())
|
2013-12-28 03:42:02 +00:00
|
|
|
|
{
|
|
|
|
|
createDir(secondaryAnimationPath);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
file = secondaryAnimationPath + filename + ".xml";
|
2013-12-28 03:42:02 +00:00
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
else
|
2013-12-28 03:42:02 +00:00
|
|
|
|
{
|
2011-08-03 20:05:33 +00:00
|
|
|
|
file = animationPath + filename + ".xml";
|
2013-12-28 03:42:02 +00:00
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
int i = 0;
|
2014-09-15 22:29:57 +00:00
|
|
|
|
XMLDocument *xml = _retrieveSkeletalXML(file, true);
|
2014-06-08 20:11:23 +00:00
|
|
|
|
xml->Clear();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *animationLayers = xml->NewElement("AnimationLayers");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
for (i = 0; i < animLayers.size(); i++)
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *animationLayer = xml->NewElement("AnimationLayer");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (animLayers[i].ignoreBones.size() > 0)
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
for (int j = 0; j < animLayers[i].ignoreBones.size(); j++)
|
|
|
|
|
{
|
|
|
|
|
os << animLayers[i].ignoreBones[j] << " ";
|
|
|
|
|
}
|
2014-06-08 20:11:23 +00:00
|
|
|
|
animationLayer->SetAttribute("ignore", os.str().c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
if (animLayers[i].includeBones.size() > 0)
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
for (int j = 0; j < animLayers[i].includeBones.size(); j++)
|
|
|
|
|
{
|
|
|
|
|
os << animLayers[i].includeBones[j] << " ";
|
|
|
|
|
}
|
2014-06-08 20:11:23 +00:00
|
|
|
|
animationLayer->SetAttribute("include", os.str().c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
if (!animLayers[i].name.empty())
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
animationLayer->SetAttribute("name", animLayers[i].name.c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
animationLayers->InsertEndChild(animationLayer);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
2014-06-08 20:11:23 +00:00
|
|
|
|
xml->InsertEndChild(animationLayers);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *bones = xml->NewElement("Bones");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
for (i = 0; i < this->bones.size(); i++)
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *bone = xml->NewElement("Bone");
|
|
|
|
|
bone->SetAttribute("idx", this->bones[i]->boneIdx);
|
|
|
|
|
bone->SetAttribute("gfx", this->bones[i]->gfx.c_str());
|
|
|
|
|
bone->SetAttribute("pidx", this->bones[i]->pidx);
|
|
|
|
|
bone->SetAttribute("name", this->bones[i]->name.c_str());
|
|
|
|
|
bone->SetAttribute("fh", this->bones[i]->isfh());
|
|
|
|
|
bone->SetAttribute("fv", this->bones[i]->isfv());
|
|
|
|
|
bone->SetAttribute("gc", this->bones[i]->generateCollisionMask);
|
|
|
|
|
bone->SetAttribute("cr", this->bones[i]->collideRadius);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (!this->bones[i]->renderQuad)
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bone->SetAttribute("rq", this->bones[i]->fileRenderQuad);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
2016-04-18 20:08:36 +00:00
|
|
|
|
if (!this->bones[i]->selectable)
|
|
|
|
|
{
|
|
|
|
|
bone->SetAttribute("sel", this->bones[i]->selectable);
|
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (this->bones[i]->rbp)
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bone->SetAttribute("rbp", this->bones[i]->rbp);
|
2016-04-17 12:33:23 +00:00
|
|
|
|
if (this->bones[i]->originalRenderPass)
|
|
|
|
|
bone->SetAttribute("pass", this->bones[i]->originalRenderPass);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (this->bones[i]->offset.x)
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bone->SetAttribute("offx", this->bones[i]->offset.x);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (this->bones[i]->offset.y)
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bone->SetAttribute("offy", this->bones[i]->offset.y);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (!this->bones[i]->prt.empty())
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bone->SetAttribute("prt", this->bones[i]->prt.c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (!this->bones[i]->changeStrip.empty())
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << this->bones[i]->stripVert << " " << this->bones[i]->changeStrip.size();
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bone->SetAttribute("strip", os.str().c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
if (!this->bones[i]->internalOffset.isZero())
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << this->bones[i]->internalOffset.x << " " << this->bones[i]->internalOffset.y;
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bone->SetAttribute("io", os.str().c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
if (this->bones[i]->isRepeatingTextureToFill())
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bone->SetAttribute("rt", 1);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
if (this->bones[i]->originalScale.x != 1 || this->bones[i]->originalScale.y != 1)
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << this->bones[i]->originalScale.x << " " << this->bones[i]->originalScale.y;
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bone->SetAttribute("sz", os.str().c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
for (Children::iterator j = this->bones[i]->children.begin(); j != this->bones[i]->children.end(); j++)
|
|
|
|
|
{
|
|
|
|
|
Bone *b = dynamic_cast<Bone*>(*j);
|
|
|
|
|
Quad *q = dynamic_cast<Quad*>(*j);
|
|
|
|
|
Particle *p = dynamic_cast<Particle*>(*j);
|
|
|
|
|
if (q && !b && !p)
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *frame = xml->NewElement("Frame");
|
|
|
|
|
frame->SetAttribute("gfx", q->texture->name.c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (q->getRenderPass() != 0)
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
frame->SetAttribute("pass", q->getRenderPass());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bone->InsertEndChild(frame);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-08 20:11:23 +00:00
|
|
|
|
bones->InsertEndChild(bone);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
2014-06-08 20:11:23 +00:00
|
|
|
|
xml->InsertEndChild(bones);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *animations = xml->NewElement("Animations");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
for (i = 0; i < this->animations.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
Animation *a = &this->animations[i];
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *animation = xml->NewElement("Animation");
|
|
|
|
|
animation->SetAttribute("name", a->name.c_str());
|
2016-04-17 12:33:23 +00:00
|
|
|
|
if(a->resetPassOnEnd)
|
|
|
|
|
animation->SetAttribute("resetPassOnEnd", a->resetPassOnEnd);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
for (int j = 0; j < a->keyframes.size(); j++)
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *key = xml->NewElement("Key");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (!a->keyframes[j].sound.empty())
|
2014-06-08 20:11:23 +00:00
|
|
|
|
key->SetAttribute("sound", a->keyframes[j].sound.c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (!a->keyframes[j].cmd.empty())
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
key->SetAttribute("cmd", a->keyframes[j].cmd.c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
if (a->keyframes[j].lerpType != 0)
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
key->SetAttribute("lerp", a->keyframes[j].lerpType);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << a->keyframes[j].t << " ";
|
|
|
|
|
std::ostringstream szos;
|
|
|
|
|
for (int k = 0; k < a->keyframes[j].keyframes.size(); k++)
|
|
|
|
|
{
|
|
|
|
|
BoneKeyframe *b = &a->keyframes[j].keyframes[k];
|
|
|
|
|
os << b->idx << " " << b->x << " " << b->y << " " << b->rot << " ";
|
|
|
|
|
os << b->strip.size() << " ";
|
|
|
|
|
for (int i = 0; i < b->strip.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
os << b->strip[i].x << " " << b->strip[i].y << " ";
|
|
|
|
|
}
|
|
|
|
|
if (b->doScale)
|
|
|
|
|
{
|
|
|
|
|
szos << b->idx << " " << b->sx << " " << b->sy << " ";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::string szoss = szos.str();
|
|
|
|
|
if (!szoss.empty())
|
2014-06-08 20:11:23 +00:00
|
|
|
|
key->SetAttribute("sz", szoss.c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
key->SetAttribute("e", os.str().c_str());
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
animation->InsertEndChild(key);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
2014-06-08 20:11:23 +00:00
|
|
|
|
animations->InsertEndChild(animation);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
2014-06-08 20:11:23 +00:00
|
|
|
|
xml->InsertEndChild(animations);
|
2014-06-10 00:18:55 +00:00
|
|
|
|
return xml->SaveFile(file.c_str()) == XML_SUCCESS;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SkeletalSprite::getBoneIdx(Bone *b)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < bones.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (bones[i] == b)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::toggleBone(int idx, int v)
|
|
|
|
|
{
|
|
|
|
|
if (idx >= 0 && idx < bones.size())
|
|
|
|
|
{
|
|
|
|
|
bones[idx]->alpha.x = v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bone *SkeletalSprite::getBoneByName(const std::string &name)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < bones.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (bones[i]->name == name)
|
|
|
|
|
return bones[i];
|
|
|
|
|
}
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << "Could not find bone with name[" << name << "]";
|
|
|
|
|
debugLog(os.str());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bone *SkeletalSprite::getBoneByIdx(int idx)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < bones.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (bones[i]->boneIdx == idx)
|
|
|
|
|
return bones[i];
|
|
|
|
|
}
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << "Could not find bone with idx[" << idx << "]";
|
|
|
|
|
debugLog(os.str());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-06 22:47:45 +00:00
|
|
|
|
Bone *SkeletalSprite::initBone(int idx, std::string gfx, int pidx, int rbp, std::string name, float cr, bool fh, bool fv)
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
|
|
|
|
Bone *b = new Bone;
|
|
|
|
|
b->boneIdx = idx;
|
|
|
|
|
b->setTexture(gfx);
|
|
|
|
|
b->skeleton = this;
|
|
|
|
|
b->gfx = gfx;
|
|
|
|
|
b->rbp = rbp;
|
|
|
|
|
b->renderBeforeParent = rbp;
|
|
|
|
|
b->pidx = pidx;
|
|
|
|
|
b->collideRadius = cr;
|
|
|
|
|
b->name = name;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (fh)
|
|
|
|
|
b->flipHorizontal();
|
|
|
|
|
if (fv)
|
|
|
|
|
b->flipVertical();
|
|
|
|
|
bones.push_back(b);
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::firstAnimation()
|
|
|
|
|
{
|
|
|
|
|
stopAnimation();
|
|
|
|
|
animLayers[0].currentAnimation = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::lastAnimation()
|
|
|
|
|
{
|
|
|
|
|
stopAnimation();
|
|
|
|
|
animLayers[0].currentAnimation = animations.size()-1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::nextAnimation()
|
|
|
|
|
{
|
|
|
|
|
stopAnimation();
|
|
|
|
|
animLayers[0].currentAnimation++;
|
|
|
|
|
if (animLayers[0].currentAnimation >= animations.size())
|
|
|
|
|
animLayers[0].currentAnimation = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::prevAnimation()
|
|
|
|
|
{
|
|
|
|
|
stopAnimation();
|
|
|
|
|
animLayers[0].currentAnimation--;
|
|
|
|
|
if (animLayers[0].currentAnimation < 0)
|
|
|
|
|
animLayers[0].currentAnimation = animations.size()-1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::deleteBones()
|
|
|
|
|
{
|
|
|
|
|
bones.clear();
|
2014-07-21 20:21:22 +00:00
|
|
|
|
for(Children::iterator it = children.begin(); it != children.end(); ++it)
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
2014-07-21 20:21:22 +00:00
|
|
|
|
(*it)->safeKill();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-03 15:13:07 +00:00
|
|
|
|
Animation *SkeletalSprite::getAnimation(const std::string& anim)
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < animations.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (animations[i].name == anim)
|
|
|
|
|
return &animations[i];
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::loadSkin(const std::string &fn)
|
|
|
|
|
{
|
|
|
|
|
std::string file;
|
|
|
|
|
|
|
|
|
|
if (!secondaryAnimationPath.empty())
|
|
|
|
|
{
|
|
|
|
|
file = secondaryAnimationPath + skinPath + fn + ".xml";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (file.empty() || !exists(file, false))
|
|
|
|
|
{
|
|
|
|
|
file = animationPath + skinPath + fn + ".xml";
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-09 02:18:40 +00:00
|
|
|
|
file = adjustFilenameCase(file);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
2013-02-27 00:54:38 +00:00
|
|
|
|
if (!exists(file))
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
2014-09-15 22:29:57 +00:00
|
|
|
|
errorLog("Could not load skin[" + file + "] - File not found.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
XMLDocument *d = _retrieveSkeletalXML(file, false);
|
|
|
|
|
if(!d)
|
|
|
|
|
{
|
|
|
|
|
errorLog("Could not load skin[" + file + "] - Malformed XML.");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *bonesXml = d->FirstChildElement("Bones");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (bonesXml)
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *boneXml = bonesXml->FirstChildElement("Bone");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
while (boneXml)
|
|
|
|
|
{
|
|
|
|
|
int idx = atoi(boneXml->Attribute("idx"));
|
|
|
|
|
Bone *b = getBoneByIdx(idx);
|
|
|
|
|
if (b)
|
|
|
|
|
{
|
|
|
|
|
if (boneXml->Attribute("rq"))
|
|
|
|
|
{
|
|
|
|
|
int rq = atoi(boneXml->Attribute("rq"));
|
|
|
|
|
b->renderQuad = rq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string gfx;
|
|
|
|
|
if (boneXml->Attribute("gfx"))
|
|
|
|
|
{
|
|
|
|
|
gfx = boneXml->Attribute("gfx");
|
|
|
|
|
if (!gfx.empty())
|
|
|
|
|
{
|
|
|
|
|
b->gfx = gfx;
|
|
|
|
|
b->setTexture(b->gfx);
|
|
|
|
|
b->renderQuad = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gfx.empty())
|
|
|
|
|
{
|
|
|
|
|
b->renderQuad = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (boneXml->Attribute("fh"))
|
|
|
|
|
{
|
|
|
|
|
int fh = atoi(boneXml->Attribute("fh"));
|
|
|
|
|
if (fh)
|
|
|
|
|
b->flipHorizontal();
|
|
|
|
|
}
|
|
|
|
|
if (boneXml->Attribute("fv"))
|
|
|
|
|
{
|
|
|
|
|
int fv = atoi(boneXml->Attribute("fv"));
|
|
|
|
|
if (fv)
|
|
|
|
|
b->flipVertical();
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << "SkinLoad: Could not find idx[" << idx << "]";
|
|
|
|
|
debugLog(os.str());
|
|
|
|
|
}
|
|
|
|
|
boneXml = boneXml->NextSiblingElement("Bone");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::stopAnimation(int layer)
|
|
|
|
|
{
|
|
|
|
|
animLayers[layer].stopAnimation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::stopAllAnimations()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < animLayers.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
animLayers[i].stopAnimation();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::playCurrentAnimation(int loop, int layer)
|
|
|
|
|
{
|
|
|
|
|
animLayers[layer].playCurrentAnimation(loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|
|
|
|
{
|
|
|
|
|
filenameLoaded = "";
|
|
|
|
|
loaded = false;
|
|
|
|
|
stopAnimation();
|
2015-06-03 02:04:19 +00:00
|
|
|
|
animLayers.clear();
|
2011-08-03 20:05:33 +00:00
|
|
|
|
deleteBones();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filenameLoaded = fn;
|
|
|
|
|
stringToLower(filenameLoaded);
|
|
|
|
|
|
|
|
|
|
std::string file;
|
|
|
|
|
|
|
|
|
|
if (!secondaryAnimationPath.empty())
|
|
|
|
|
{
|
|
|
|
|
file = secondaryAnimationPath + filenameLoaded + ".xml";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (file.empty() || !exists(file, false))
|
|
|
|
|
{
|
|
|
|
|
file = animationPath + filenameLoaded + ".xml";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!exists(file))
|
|
|
|
|
{
|
|
|
|
|
filenameLoaded = "";
|
2014-06-09 21:39:33 +00:00
|
|
|
|
errorLog("Could not load skeletal[" + file + "] - File not found.");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-09 02:18:40 +00:00
|
|
|
|
file = adjustFilenameCase(file);
|
2012-05-25 16:23:30 +00:00
|
|
|
|
|
2014-09-15 22:29:57 +00:00
|
|
|
|
XMLDocument *xml = _retrieveSkeletalXML(file, false);
|
2014-06-09 21:39:33 +00:00
|
|
|
|
if(!xml)
|
|
|
|
|
{
|
|
|
|
|
filenameLoaded = "";
|
|
|
|
|
errorLog("Could not load skeletal[" + file + "] - Malformed XML.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loaded = true;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *bones = xml->FirstChildElement("Bones");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (bones)
|
|
|
|
|
{
|
|
|
|
|
if (bones->Attribute("scale"))
|
|
|
|
|
{
|
|
|
|
|
SimpleIStringStream is(bones->Attribute("scale"));
|
|
|
|
|
is >> scale.x >> scale.y;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *bone = bones->FirstChildElement("Bone");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
while(bone)
|
|
|
|
|
{
|
|
|
|
|
int idx = atoi(bone->Attribute("idx"));
|
|
|
|
|
int pidx = -1, rbp=0, cr=0, fh=0, fv=0;
|
|
|
|
|
|
|
|
|
|
std::string name;
|
|
|
|
|
if (bone->Attribute("pidx"))
|
|
|
|
|
pidx = atoi(bone->Attribute("pidx"));
|
|
|
|
|
if (bone->Attribute("rbp"))
|
|
|
|
|
rbp = atoi(bone->Attribute("rbp"));
|
|
|
|
|
|
|
|
|
|
if (bone->Attribute("name"))
|
|
|
|
|
name = bone->Attribute("name");
|
|
|
|
|
if (bone->Attribute("cr"))
|
|
|
|
|
cr = atoi(bone->Attribute("cr"));
|
|
|
|
|
if (bone->Attribute("fh"))
|
|
|
|
|
fh = atoi(bone->Attribute("fh"));
|
|
|
|
|
if (bone->Attribute("fv"))
|
|
|
|
|
fv = atoi(bone->Attribute("fv"));
|
|
|
|
|
|
|
|
|
|
std::string gfx = bone->Attribute("gfx");
|
2016-05-06 22:47:45 +00:00
|
|
|
|
Bone *newb = initBone(idx, gfx, pidx, rbp, name, cr, fh, fv);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (bone->Attribute("offx"))
|
|
|
|
|
newb->offset.x = atoi(bone->Attribute("offx"));
|
|
|
|
|
if (bone->Attribute("offy"))
|
|
|
|
|
newb->offset.y = atoi(bone->Attribute("offy"));
|
|
|
|
|
|
|
|
|
|
if (bone->Attribute("prt"))
|
|
|
|
|
{
|
|
|
|
|
newb->prt = bone->Attribute("prt");
|
|
|
|
|
SimpleIStringStream is(newb->prt);
|
|
|
|
|
int slot;
|
2016-07-09 02:18:40 +00:00
|
|
|
|
std::string pfile;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
while (is >> slot)
|
|
|
|
|
{
|
2016-08-02 00:44:50 +00:00
|
|
|
|
if(slot < 0)
|
2016-07-09 02:18:40 +00:00
|
|
|
|
{
|
2016-08-02 00:44:50 +00:00
|
|
|
|
errorLog("particle slot < 0");
|
|
|
|
|
break;
|
2016-07-09 02:18:40 +00:00
|
|
|
|
}
|
2016-08-02 00:44:50 +00:00
|
|
|
|
is >> pfile;
|
|
|
|
|
// add particle system + load
|
|
|
|
|
ParticleEffect *e = new ParticleEffect;
|
|
|
|
|
if(newb->emitters.size() <= (size_t)slot)
|
|
|
|
|
newb->emitters.resize(slot+4, NULL);
|
|
|
|
|
newb->emitters[slot] = e;
|
|
|
|
|
newb->addChild(e, PM_POINTER);
|
|
|
|
|
e->load(pfile);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *fr=0;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
fr = bone->FirstChildElement("Frame");
|
|
|
|
|
int frc=0;
|
|
|
|
|
while(fr)
|
|
|
|
|
{
|
|
|
|
|
Quad *q=0;
|
|
|
|
|
std::string gfx;
|
|
|
|
|
if (fr->Attribute("gfx"))
|
|
|
|
|
{
|
|
|
|
|
gfx = fr->Attribute("gfx");
|
|
|
|
|
q = newb->addFrame(gfx);
|
|
|
|
|
}
|
|
|
|
|
if (fr->Attribute("pass"))
|
|
|
|
|
{
|
|
|
|
|
if (q)
|
|
|
|
|
{
|
|
|
|
|
q->setRenderPass(atoi(fr->Attribute("pass")));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fr = fr->NextSiblingElement("Frame");
|
|
|
|
|
frc++;
|
|
|
|
|
}
|
|
|
|
|
if (frc)
|
|
|
|
|
{
|
|
|
|
|
newb->showFrame(0);
|
|
|
|
|
}
|
|
|
|
|
if (bone->Attribute("pass"))
|
|
|
|
|
{
|
2016-04-17 12:33:23 +00:00
|
|
|
|
int pass = atoi(bone->Attribute("pass"));
|
|
|
|
|
newb->originalRenderPass = pass;
|
|
|
|
|
newb->setRenderPass(pass);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
if (bone->Attribute("gc"))
|
|
|
|
|
{
|
|
|
|
|
newb->generateCollisionMask = atoi(bone->Attribute("gc"));
|
|
|
|
|
}
|
|
|
|
|
if (bone->Attribute("rq"))
|
|
|
|
|
{
|
|
|
|
|
newb->renderQuad = newb->fileRenderQuad = atoi(bone->Attribute("rq"));
|
|
|
|
|
}
|
|
|
|
|
if (bone->Attribute("io"))
|
|
|
|
|
{
|
|
|
|
|
SimpleIStringStream is(bone->Attribute("io"));
|
|
|
|
|
is >> newb->internalOffset.x >> newb->internalOffset.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bone->Attribute("strip"))
|
|
|
|
|
{
|
|
|
|
|
SimpleIStringStream is(bone->Attribute("strip"));
|
|
|
|
|
bool vert;
|
|
|
|
|
int num;
|
|
|
|
|
is >> vert >> num;
|
|
|
|
|
newb->createStrip(vert, num);
|
|
|
|
|
}
|
|
|
|
|
if (bone->Attribute("sz"))
|
|
|
|
|
{
|
|
|
|
|
float sx, sy;
|
|
|
|
|
SimpleIStringStream is(bone->Attribute("sz"));
|
|
|
|
|
is >> sx >> sy;
|
|
|
|
|
|
|
|
|
|
newb->scale = newb->originalScale = Vector(sx,sy);
|
|
|
|
|
}
|
|
|
|
|
if (bone->Attribute("rt"))
|
|
|
|
|
{
|
|
|
|
|
newb->repeatTextureToFill(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bone->Attribute("blend"))
|
|
|
|
|
{
|
|
|
|
|
//if (bone->Attribute("blend")=="add")
|
|
|
|
|
newb->blendType = blendType = BLEND_ADD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bone->Attribute("alpha"))
|
|
|
|
|
{
|
|
|
|
|
float a=1.0;
|
|
|
|
|
SimpleIStringStream is(bone->Attribute("alpha"));
|
|
|
|
|
is >> a;
|
|
|
|
|
newb->alpha = a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bone->Attribute("alphaMod"))
|
|
|
|
|
{
|
|
|
|
|
float a=1.0;
|
|
|
|
|
SimpleIStringStream is(bone->Attribute("alphaMod"));
|
|
|
|
|
is >> a;
|
|
|
|
|
newb->alphaMod = a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bone->Attribute("segs"))
|
|
|
|
|
{
|
|
|
|
|
int x, y;
|
|
|
|
|
float dgox, dgoy, dgmx, dgmy, dgtm;
|
|
|
|
|
bool dgo;
|
|
|
|
|
SimpleIStringStream is(bone->Attribute("segs"));
|
|
|
|
|
is >> x >> y >> dgox >> dgoy >> dgmx >> dgmy >> dgtm >> dgo;
|
|
|
|
|
newb->setSegs(x, y, dgox, dgoy, dgmx, dgmy, dgtm, dgo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bone->Attribute("color"))
|
|
|
|
|
{
|
|
|
|
|
SimpleIStringStream in(bone->Attribute("color"));
|
|
|
|
|
in >> newb->color.x >> newb->color.y >> newb->color.z;
|
|
|
|
|
}
|
2016-04-18 20:08:36 +00:00
|
|
|
|
if (bone->Attribute("sel"))
|
|
|
|
|
{
|
|
|
|
|
newb->selectable = bone->BoolAttribute("sel");
|
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
bone = bone->NextSiblingElement("Bone");
|
|
|
|
|
}
|
|
|
|
|
// attach bones
|
|
|
|
|
for (int i = 0; i < this->bones.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
Bone *b = this->bones[i];
|
|
|
|
|
if (b->pidx != -1)
|
|
|
|
|
{
|
|
|
|
|
Bone *pb = getBoneByIdx(b->pidx);
|
|
|
|
|
if (!pb)
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << "Parent bone not found, index: " << b->pidx << " from bone idx: " << b->getIdx();
|
|
|
|
|
debugLog(os.str());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pb->addChild(b, PM_POINTER);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
addChild(b, PM_POINTER);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
animLayers.clear();
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *animationLayers = xml->FirstChildElement("AnimationLayers");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (animationLayers)
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *animationLayer = animationLayers->FirstChildElement("AnimationLayer");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
while (animationLayer)
|
|
|
|
|
{
|
|
|
|
|
AnimationLayer newAnimationLayer;
|
|
|
|
|
if (animationLayer->Attribute("ignore"))
|
|
|
|
|
{
|
|
|
|
|
SimpleIStringStream is(animationLayer->Attribute("ignore"));
|
|
|
|
|
int t;
|
|
|
|
|
while (is >> t)
|
|
|
|
|
{
|
|
|
|
|
newAnimationLayer.ignoreBones.push_back(t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (animationLayer->Attribute("include"))
|
|
|
|
|
{
|
|
|
|
|
SimpleIStringStream is(animationLayer->Attribute("include"));
|
|
|
|
|
int t;
|
|
|
|
|
while (is >> t)
|
|
|
|
|
{
|
|
|
|
|
newAnimationLayer.includeBones.push_back(t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (animationLayer->Attribute("name"))
|
|
|
|
|
{
|
|
|
|
|
newAnimationLayer.name = animationLayer->Attribute("name");
|
|
|
|
|
}
|
|
|
|
|
newAnimationLayer.setSkeletalSprite(this);
|
|
|
|
|
animLayers.push_back(newAnimationLayer);
|
|
|
|
|
animationLayer = animationLayer->NextSiblingElement("AnimationLayer");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
animations.clear();
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *animations = xml->FirstChildElement("Animations");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
if (animations)
|
|
|
|
|
{
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *animation = animations->FirstChildElement("Animation");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
while(animation)
|
|
|
|
|
{
|
|
|
|
|
Animation newAnimation;
|
|
|
|
|
newAnimation.name = animation->Attribute("name");
|
2016-04-17 12:33:23 +00:00
|
|
|
|
newAnimation.resetPassOnEnd = animation->BoolAttribute("resetPassOnEnd");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
stringToLower(newAnimation.name);
|
|
|
|
|
|
2014-06-08 20:11:23 +00:00
|
|
|
|
XMLElement *key = animation->FirstChildElement("Key");
|
2011-08-03 20:05:33 +00:00
|
|
|
|
while (key)
|
|
|
|
|
{
|
|
|
|
|
SkeletalKeyframe newSkeletalKeyframe;
|
|
|
|
|
if (key->Attribute("e"))
|
|
|
|
|
{
|
|
|
|
|
float time;
|
|
|
|
|
SimpleIStringStream is(key->Attribute("e"));
|
|
|
|
|
is >> time;
|
|
|
|
|
int idx, x, y, rot, strip;
|
|
|
|
|
newSkeletalKeyframe.t = time;
|
|
|
|
|
if (key->Attribute("sound"))
|
|
|
|
|
{
|
|
|
|
|
newSkeletalKeyframe.sound = key->Attribute("sound");
|
|
|
|
|
}
|
|
|
|
|
if (key->Attribute("lerp"))
|
|
|
|
|
{
|
|
|
|
|
newSkeletalKeyframe.lerpType = atoi(key->Attribute("lerp"));
|
|
|
|
|
}
|
|
|
|
|
while (is >> idx)
|
|
|
|
|
{
|
|
|
|
|
BoneKeyframe b;
|
|
|
|
|
is >> x >> y >> rot >> strip;
|
|
|
|
|
b.idx = idx;
|
|
|
|
|
b.x = x;
|
|
|
|
|
b.y = y;
|
|
|
|
|
b.rot = rot;
|
|
|
|
|
if (strip>0)
|
|
|
|
|
{
|
|
|
|
|
b.strip.resize(strip);
|
|
|
|
|
for (int i = 0; i < b.strip.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
is >> b.strip[i].x >> b.strip[i].y;
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (key->Attribute("sz"))
|
|
|
|
|
{
|
|
|
|
|
SimpleIStringStream is2(key->Attribute("sz"));
|
|
|
|
|
int midx;
|
|
|
|
|
float bsx, bsy;
|
|
|
|
|
while (is2 >> midx)
|
|
|
|
|
{
|
|
|
|
|
is2 >> bsx >> bsy;
|
|
|
|
|
if (midx == idx)
|
|
|
|
|
{
|
|
|
|
|
b.doScale = true;
|
|
|
|
|
b.sx = bsx;
|
|
|
|
|
b.sy = bsy;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
newSkeletalKeyframe.keyframes.push_back(b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if (key->Attribute("d"))
|
|
|
|
|
{
|
|
|
|
|
float time;
|
|
|
|
|
SimpleIStringStream is(key->Attribute("d"));
|
|
|
|
|
is >> time;
|
|
|
|
|
int idx, x, y, rot;
|
|
|
|
|
|
|
|
|
|
newSkeletalKeyframe.t = time;
|
|
|
|
|
if (key->Attribute("sound"))
|
|
|
|
|
{
|
|
|
|
|
newSkeletalKeyframe.sound = key->Attribute("sound");
|
|
|
|
|
}
|
|
|
|
|
while (is >> idx)
|
|
|
|
|
{
|
|
|
|
|
is >> x >> y >> rot;
|
|
|
|
|
BoneKeyframe b;
|
|
|
|
|
b.idx = idx;
|
|
|
|
|
b.x = x;
|
|
|
|
|
b.y = y;
|
|
|
|
|
b.rot = rot;
|
|
|
|
|
newSkeletalKeyframe.keyframes.push_back(b);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (key->Attribute("cmd"))
|
|
|
|
|
{
|
|
|
|
|
newSkeletalKeyframe.cmd = key->Attribute("cmd");
|
|
|
|
|
SimpleIStringStream is(newSkeletalKeyframe.cmd);
|
|
|
|
|
int bidx;
|
|
|
|
|
while (is >> bidx)
|
|
|
|
|
{
|
|
|
|
|
Bone *b = this->getBoneByIdx(bidx);
|
|
|
|
|
if (b)
|
|
|
|
|
{
|
|
|
|
|
BoneCommand bcmd;
|
2016-04-17 13:16:55 +00:00
|
|
|
|
if(!bcmd.parse(b, is))
|
|
|
|
|
break;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
newSkeletalKeyframe.commands.push_back(bcmd);
|
|
|
|
|
}
|
2016-04-17 13:16:55 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
os << "SkeletalSprite::loadSkeletal: File " << fn << " anim " << newAnimation.name << " specifies non-existing bone idx " << bidx;
|
|
|
|
|
errorLog(os.str());
|
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// generate empty bone keys
|
|
|
|
|
for (int i = 0; i < this->bones.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (newSkeletalKeyframe.getBoneKeyframe(this->bones[i]->boneIdx))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BoneKeyframe b;
|
|
|
|
|
b.idx = this->bones[i]->boneIdx;
|
|
|
|
|
newSkeletalKeyframe.keyframes.push_back(b);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
newAnimation.keyframes.push_back(newSkeletalKeyframe);
|
|
|
|
|
key = key->NextSiblingElement("Key");
|
|
|
|
|
}
|
|
|
|
|
animation = animation->NextSiblingElement("Animation");
|
|
|
|
|
this->animations.push_back(newAnimation);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Animation *SkeletalSprite::getCurrentAnimation(int layer)
|
|
|
|
|
{
|
2014-05-15 22:04:56 +00:00
|
|
|
|
return layer < animLayers.size() ? animLayers[layer].getCurrentAnimation() : NULL;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::setTime(float time, int layer)
|
|
|
|
|
{
|
2014-05-15 22:04:56 +00:00
|
|
|
|
if(layer < animLayers.size())
|
|
|
|
|
animLayers[layer].timer = time;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-04-17 12:33:23 +00:00
|
|
|
|
void AnimationLayer::resetPass()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < s->bones.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
Bone *b = s->bones[i];
|
|
|
|
|
if (contains(b))
|
|
|
|
|
b->setRenderPass(b->originalRenderPass);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AnimationLayer::contains(const Bone *b) const
|
|
|
|
|
{
|
|
|
|
|
const int idx = b->boneIdx;
|
|
|
|
|
if (!ignoreBones.empty())
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < ignoreBones.size(); j++)
|
|
|
|
|
if (idx == ignoreBones[j])
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else if (!includeBones.empty())
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < includeBones.size(); j++)
|
|
|
|
|
if (idx == includeBones[j])
|
|
|
|
|
return true;
|
2016-04-18 19:07:46 +00:00
|
|
|
|
return false;
|
2016-04-17 12:33:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
void AnimationLayer::updateBones()
|
|
|
|
|
{
|
|
|
|
|
if (!animating && !(&s->animLayers[0] == this) && fallThru == 0) return;
|
|
|
|
|
|
|
|
|
|
SkeletalKeyframe *key1 = getCurrentAnimation()->getPrevKeyframe(timer);
|
|
|
|
|
SkeletalKeyframe *key2 = getCurrentAnimation()->getNextKeyframe(timer);
|
|
|
|
|
if (!key1 || !key2) return;
|
|
|
|
|
float t1 = key1->t;
|
|
|
|
|
float t2 = key2->t;
|
|
|
|
|
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
float diff = t2-t1;
|
|
|
|
|
float dt;
|
|
|
|
|
if (diff != 0)
|
|
|
|
|
dt = (timer - t1)/(t2-t1);
|
|
|
|
|
else
|
|
|
|
|
dt = 0;
|
|
|
|
|
|
|
|
|
|
if (lastNewKey != key2)
|
|
|
|
|
{
|
|
|
|
|
if (!key2->sound.empty())
|
|
|
|
|
{
|
|
|
|
|
core->sound->playSfx(key2->sound);
|
|
|
|
|
}
|
|
|
|
|
if (!key2->commands.empty())
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < key2->commands.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
key2->commands[i].run();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (s->animKeyNotify)
|
|
|
|
|
{
|
|
|
|
|
s->animKeyNotify->onAnimationKeyPassed(getCurrentAnimation()->getSkeletalKeyframeIndex(lastNewKey));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lastNewKey = key2;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < s->bones.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
Bone *b = s->bones[i];
|
|
|
|
|
|
|
|
|
|
if (b->segmentChain == 1)
|
|
|
|
|
{
|
|
|
|
|
b->updateSegments();
|
|
|
|
|
}
|
|
|
|
|
if (b->segmentChain < 2)
|
|
|
|
|
{
|
2016-04-17 12:33:23 +00:00
|
|
|
|
if (b->animated != Bone::ANIM_NONE && contains(b))
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
2016-04-17 12:33:23 +00:00
|
|
|
|
int idx = b->boneIdx;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
BoneKeyframe *bkey1 = key1->getBoneKeyframe(idx);
|
|
|
|
|
BoneKeyframe *bkey2 = key2->getBoneKeyframe(idx);
|
|
|
|
|
if (bkey1 && bkey2)
|
|
|
|
|
{
|
|
|
|
|
if (!animating && fallThru > 0)
|
|
|
|
|
{
|
|
|
|
|
//HACK: TODO: fix this up nice like below
|
|
|
|
|
Vector p = Vector((bkey2->x-bkey1->x)*dt+bkey1->x, (bkey2->y-bkey1->y)*dt+bkey1->y);
|
|
|
|
|
float rot = (bkey2->rot - bkey1->rot)*dt + bkey1->rot;
|
|
|
|
|
p = Vector((p.x-b->position.x)*fallThru+b->position.x, (p.y-b->position.y)*fallThru+b->position.y);
|
|
|
|
|
rot = (rot-b->rotation.z)*fallThru + b->rotation.z;
|
|
|
|
|
if (b->animated==Bone::ANIM_ALL || b->animated==Bone::ANIM_POS)
|
|
|
|
|
b->position = p;
|
|
|
|
|
if (b->animated==Bone::ANIM_ALL || b->animated==Bone::ANIM_ROT)
|
|
|
|
|
b->rotation.z = rot;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int lerpType = key2->lerpType;
|
|
|
|
|
//k(0)×(2u3-3u2+1) + k(1)×(3u2-2u3)
|
|
|
|
|
if (b->animated==Bone::ANIM_ALL || b->animated==Bone::ANIM_POS)
|
|
|
|
|
{
|
|
|
|
|
b->position = Vector(lerp(bkey1->x, bkey2->x, dt, lerpType), lerp(bkey1->y, bkey2->y, dt, lerpType));
|
|
|
|
|
}
|
|
|
|
|
if (b->animated==Bone::ANIM_ALL || b->animated==Bone::ANIM_ROT)
|
|
|
|
|
{
|
|
|
|
|
b->rotation.z = lerp(bkey1->rot, bkey2->rot, dt, lerpType);
|
|
|
|
|
}
|
|
|
|
|
if (b->animated==Bone::ANIM_ALL && (bkey1->doScale || bkey2->doScale))
|
|
|
|
|
{
|
|
|
|
|
b->scale.x = lerp(bkey1->sx, bkey2->sx, dt, lerpType);
|
|
|
|
|
b->scale.y = lerp(bkey1->sy, bkey2->sy, dt, lerpType);
|
|
|
|
|
}
|
|
|
|
|
if (b->animated==Bone::ANIM_ALL && !b->changeStrip.empty())
|
|
|
|
|
{
|
|
|
|
|
if (bkey2->strip.size() < b->changeStrip.size())
|
|
|
|
|
bkey2->strip.resize(b->changeStrip.size());
|
|
|
|
|
if (bkey1->strip.size() < b->changeStrip.size())
|
|
|
|
|
bkey1->strip.resize(b->changeStrip.size());
|
|
|
|
|
for (int i = 0; i < b->changeStrip.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
b->changeStrip[i] = Vector(lerp(bkey1->strip[i].x, bkey2->strip[i].x, dt, lerpType), lerp(bkey1->strip[i].y, bkey2->strip[i].y, dt, lerpType));
|
|
|
|
|
}
|
|
|
|
|
b->setGridPoints(b->stripVert, b->changeStrip);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::setFreeze(bool f)
|
|
|
|
|
{
|
|
|
|
|
frozen = f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::updateBones()
|
|
|
|
|
{
|
|
|
|
|
if (!frozen)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < animLayers.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
animLayers[i].updateBones();
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-05 17:40:28 +00:00
|
|
|
|
|
2011-08-03 20:05:33 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SkeletalSprite::isAnimating(int layer)
|
|
|
|
|
{
|
|
|
|
|
return animLayers[layer].animating;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::setTimeMultiplier(float t, int layer)
|
|
|
|
|
{
|
|
|
|
|
animLayers[layer].timeMultiplier = t;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-31 17:02:18 +00:00
|
|
|
|
Bone* SkeletalSprite::getSelectedBone(bool mouseBased)
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
|
|
|
|
if (!loaded) return 0;
|
|
|
|
|
if (mouseBased)
|
|
|
|
|
{
|
2012-01-31 17:02:18 +00:00
|
|
|
|
float closestDist = HUGE_VALF;
|
2011-08-03 20:05:33 +00:00
|
|
|
|
Bone *b = 0;
|
|
|
|
|
Vector p = core->mouse.position;
|
|
|
|
|
for (int i = 0; i < bones.size(); i++)
|
|
|
|
|
{
|
2012-01-31 17:02:18 +00:00
|
|
|
|
if (bones[i]->renderQuad || core->getShiftState())
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
2012-01-31 17:02:18 +00:00
|
|
|
|
bones[i]->color = Vector(1,1,1);
|
2016-04-18 20:08:36 +00:00
|
|
|
|
if (bones[i]->selectable && bones[i]->renderQuad && bones[i]->isCoordinateInsideWorld(p))
|
2011-08-03 20:05:33 +00:00
|
|
|
|
{
|
2012-01-31 17:02:18 +00:00
|
|
|
|
float dist = (bones[i]->getWorldPosition() - p).getSquaredLength2D();
|
|
|
|
|
if (dist <= closestDist)
|
|
|
|
|
{
|
|
|
|
|
closestDist = dist;
|
|
|
|
|
b = bones[i];
|
|
|
|
|
selectedBone = i;
|
|
|
|
|
}
|
2011-08-03 20:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (b)
|
|
|
|
|
{
|
|
|
|
|
b->color = Vector(1,0,0);
|
|
|
|
|
}
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
// else
|
|
|
|
|
if (!bones.empty() && selectedBone >= 0 && selectedBone < bones.size())
|
|
|
|
|
return bones[selectedBone];
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::updateSelectedBoneColor()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < bones.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
bones[i]->color = Vector(1,1,1);
|
|
|
|
|
}
|
|
|
|
|
Bone *b = bones[selectedBone];
|
|
|
|
|
if (b)
|
|
|
|
|
b->color = Vector(0.5,0.5,1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::setSelectedBone(int b)
|
|
|
|
|
{
|
|
|
|
|
selectedBone = b;
|
|
|
|
|
updateSelectedBoneColor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::selectPrevBone()
|
|
|
|
|
{
|
2016-04-18 20:08:36 +00:00
|
|
|
|
const int oldsel = selectedBone;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
selectedBone++;
|
|
|
|
|
if(selectedBone == oldsel)
|
|
|
|
|
break;
|
|
|
|
|
if (selectedBone >= bones.size())
|
|
|
|
|
selectedBone = 0;
|
|
|
|
|
}
|
|
|
|
|
while (!bones[selectedBone]->selectable);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
updateSelectedBoneColor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SkeletalSprite::selectNextBone()
|
|
|
|
|
{
|
2016-04-18 20:08:36 +00:00
|
|
|
|
const int oldsel = selectedBone;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
selectedBone--;
|
|
|
|
|
if(selectedBone == oldsel)
|
|
|
|
|
break;
|
|
|
|
|
if (selectedBone < 0)
|
|
|
|
|
selectedBone = bones.size()-1;
|
|
|
|
|
}
|
|
|
|
|
while (!bones[selectedBone]->selectable);
|
2011-08-03 20:05:33 +00:00
|
|
|
|
updateSelectedBoneColor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|