1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3
4 This file is part of Aquaria.
5
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
15 See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 #include "SkeletalSprite.h"
22 #include "Core.h"
23 #include "Particles.h"
24 #include "MathFunctions.h"
25 #include "SimpleIStringStream.h"
26
27 #include "tinyxml2.h"
28 using namespace tinyxml2;
29
30 std::string SkeletalSprite::animationPath = "data/animations/";
31 std::string SkeletalSprite::skinPath = "skins/";
32
33 std::string SkeletalSprite::secondaryAnimationPath = "";
34
35 static std::map<std::string, XMLDocument*> skelCache;
36
_retrieveSkeletalXML(const std::string & name,bool keepEmpty)37 static XMLDocument *_retrieveSkeletalXML(const std::string& name, bool keepEmpty)
38 {
39 std::map<std::string, XMLDocument*>::iterator it = skelCache.find(name);
40 if(it != skelCache.end())
41 return it->second;
42
43 XMLDocument *doc = readXML(name, NULL, keepEmpty);
44 if(doc)
45 skelCache[name] = doc;
46
47 return doc;
48 }
49
clearCache()50 void SkeletalSprite::clearCache()
51 {
52 for(std::map<std::string, XMLDocument*>::iterator it = skelCache.begin(); it != skelCache.end(); ++it)
53 delete it->second;
54 skelCache.clear();
55 }
56
57
copyAllButTime(SkeletalKeyframe * copy)58 void SkeletalKeyframe::copyAllButTime(SkeletalKeyframe *copy)
59 {
60 if (!copy) return;
61
62 float t = this->t;
63 (*this) = (*copy);
64 this->t = t;
65 }
66
Bone()67 Bone::Bone() : Quad()
68 {
69 addType(SCO_BONE);
70 fileRenderQuad = true;
71 skeleton = 0;
72 generateCollisionMask = true;
73 animated = ANIM_ALL;
74 originalScale = Vector(1,1);
75 boneIdx = pidx = -1;
76 rbp = 0;
77 segmentChain = 0;
78
79 minDist = maxDist = 128;
80 reverse = false;
81 }
82 /*
83 void Bone::createStrip(bool vert, int num)
84 {
85 Quad::createStrip(vert, num);
86 changeStrip.resize(num);
87 }
88 */
89
destroy()90 void Bone::destroy()
91 {
92 Quad::destroy();
93
94 for (int i = 0; i < segments.size(); i++)
95 {
96 segments[i]->setLife(1.0);
97 segments[i]->setDecayRate(10);
98 segments[i]->alpha = 0;
99 }
100 segments.clear();
101 }
102
addSegment(Bone * b)103 void Bone::addSegment(Bone *b)
104 {
105 segments.push_back(b);
106
107 b->segmentChain = 2;
108
109 skeleton->removeChild(b);
110
111 core->getTopStateData()->addRenderObject(b, skeleton->getTopLayer());
112 b->position = this->getWorldPosition();
113 }
114
createStrip(bool vert,int num)115 void Bone::createStrip(bool vert, int num)
116 {
117 if (!vert)
118 {
119 createGrid(num, 2);
120 }
121 else
122 {
123 createGrid(2, num);
124 }
125 stripVert = vert;
126 gridType = GRID_SET;
127 changeStrip.resize(num);
128 setGridPoints(vert, strip);
129 }
130
131
addFrame(const std::string & gfx)132 Quad* Bone::addFrame(const std::string &gfx)
133 {
134 renderQuad = false;
135 Quad *q = new Quad();
136 q->setTexture(gfx);
137 q->renderBeforeParent = 1;
138 addChild(q, PM_POINTER);
139 return q;
140 }
141
showFrame(int idx)142 void Bone::showFrame(int idx)
143 {
144 //float t = 0.1;
145 int c = 0;
146 for (Children::iterator i = children.begin(); i != children.end(); i++)
147 {
148 RenderObject *r = (*i);
149 if (idx == c)
150 {
151 if (r->alpha == 0)
152 {
153 r->alpha = 1;
154
155 // add option to turn on alpha fading
156 //r->alpha.interpolateTo(1, t);
157 }
158 else
159 {
160 r->alpha = 1;
161 }
162 }
163 else
164 {
165 if (r->alpha == 1)
166 {
167 r->alpha = 0;
168 //r->alpha.interpolateTo(0, t*2);
169 }
170 else
171 {
172 r->alpha = 0;
173 }
174 }
175 c++;
176 }
177 }
178
179
setAnimated(int b)180 void Bone::setAnimated(int b)
181 {
182 /*
183 std::ostringstream os;
184 os << "setting animated: " << b;
185 debugLog(os.str());
186 */
187
188 animated = b;
189 }
190
191
setSegmentProps(int minDist,int maxDist,bool reverse)192 void Bone::setSegmentProps(int minDist, int maxDist, bool reverse)
193 {
194 this->minDist = minDist;
195 this->maxDist = maxDist;
196 this->reverse = reverse;
197 }
198
updateSegment(Bone * b,const Vector & diff)199 void Bone::updateSegment(Bone *b, const Vector &diff)
200 {
201 /*
202 int maxDist, minDist;
203 maxDist = minDist = 128;
204 */
205
206 float angle = -1;
207 if (diff.getSquaredLength2D() > sqr(maxDist))
208 {
209 Vector useDiff = diff;
210 useDiff.setLength2D(maxDist);
211 Vector reallyUseDiff = diff - useDiff;
212 b->position += reallyUseDiff;
213
214 MathFunctions::calculateAngleBetweenVectorsInDegrees(Vector(0,0,0), diff, angle);
215 }
216 else if (diff.getSquaredLength2D() > sqr(minDist)) // 6.3
217 {
218 b->position += diff*0.05f;
219
220 MathFunctions::calculateAngleBetweenVectorsInDegrees(Vector(0,0,0), diff, angle);
221
222 //b->rotation.interpolateTo(Vector(0,0,angle),0.2);
223 }
224 if (angle != -1)
225 {
226 /*
227 std::ostringstream os;
228 os << "rotz: " << b->rotation.z << " angle: " << angle;
229 debugLog(os.str());
230 */
231
232 if (b->rotation.z >= 270 && angle < 90)
233 {
234 b->rotation.stop();
235 b->rotation.z -= 360;
236 }
237
238 if (b->rotation.z <= 90 && angle > 270)
239 {
240 b->rotation.stop();
241 b->rotation.z += 360;
242 }
243
244
245 b->rotation.interpolateTo(Vector(0,0,angle),0.2);
246 }
247 /*
248 else
249 {
250 float angle;
251 MathFunctions::calculateAngleBetweenVectorsInDegrees(Vector(0,0,0), diff, angle);
252 b->rotation.interpolateTo(Vector(0,0,angle),0);
253 }
254 */
255 }
256
updateSegments()257 void Bone::updateSegments()
258 {
259 if (segmentChain>0 && !segments.empty())
260 {
261 //bool reverse = true;
262
263 /*
264 std::vector<Bone*> segments;
265 Bone *child = (Bone*)(this->children.front());
266 while (child)
267 {
268 segments.push_back(child);
269
270 if (child->children.empty())
271 child = 0;
272 else
273 child = (Bone*)(child->children.front());
274 }
275 */
276
277 if (!reverse)
278 {
279 for (int i = 0; i < segments.size(); i++)
280 {
281 Vector diff;
282 if (i == 0)
283 {
284 Vector world = getWorldCollidePosition(segmentOffset);
285 diff = world - segments[i]->getWorldPosition();
286 }
287 else
288 diff = segments[i-1]->getWorldPosition() - segments[i]->getWorldPosition();
289
290 updateSegment(segments[i], diff);
291 }
292 }
293 else
294 {
295 int top = segments.size()-1;
296 for (int i = top; i >= 0; i--)
297 {
298 Vector diff;
299 if (i == top)
300 {
301 Vector world = getWorldCollidePosition(segmentOffset);
302 diff = world - segments[i]->getWorldPosition();
303 }
304 else
305 diff = segments[i+1]->getWorldPosition() - segments[i]->getWorldPosition();
306
307 updateSegment(segments[i], diff);
308 }
309 }
310 }
311 }
312
parse(Bone * b,SimpleIStringStream & is)313 void BoneCommand::parse(Bone *b, SimpleIStringStream &is)
314 {
315 std::string type;
316 is >> type;
317 this->b = b;
318 if (type=="AC_PRT_LOAD")
319 {
320 command = AC_PRT_LOAD;
321 is >> slot >> file;
322 }
323 else if (type=="AC_SND_PLAY")
324 {
325 command = AC_SND_PLAY;
326 is >> file;
327 }
328 else if (type=="AC_FRM_SHOW")
329 {
330 command = AC_FRM_SHOW;
331 is >> slot;
332 }
333 else if (type=="AC_PRT_START")
334 {
335 command = AC_PRT_START;
336 is >> slot;
337 /*
338 Emitter *e = b->emitters[slot];
339 if (e)
340 {
341 e->start();
342 }
343 */
344 }
345 else if (type=="AC_PRT_STOP")
346 {
347 command = AC_PRT_STOP;
348 is >> slot;
349 /*
350 Emitter *e = b->emitters[slot];
351 if (e)
352 {
353 e->stop();
354 }
355 */
356 }
357 else if (type=="AC_SEGS_START")
358 command = AC_SEGS_START;
359 else if (type=="AC_SEGS_STOP")
360 command = AC_SEGS_STOP;
361 }
362
run()363 void BoneCommand::run()
364 {
365 //debugLog("running CMD");
366 switch(command)
367 {
368 case AC_SND_PLAY:
369 {
370 core->sound->playSfx(file);
371 }
372 break;
373 case AC_FRM_SHOW:
374 {
375 b->showFrame(slot);
376 }
377 break;
378 case AC_PRT_LOAD:
379 {
380 ParticleEffect *e = b->emitters[slot];
381 if (e)
382 {
383 e->load(file);
384 }
385 }
386 break;
387 case AC_PRT_START:
388 {
389 ParticleEffect *e = b->emitters[slot];
390 if (e)
391 e->start();
392 }
393 break;
394 case AC_PRT_STOP:
395 {
396 ParticleEffect *e = b->emitters[slot];
397 if (e)
398 e->stop();
399 }
400 break;
401 }
402 }
403
404
AnimationLayer()405 AnimationLayer::AnimationLayer()
406 {
407 lastNewKey = 0;
408 fallThru= 0;
409 //index = -1;
410 timer = 0;
411 loop = 0;
412 enqueuedAnimationLoop = 0;
413 timeMultiplier = 1;
414 animationLength = 0;
415 currentAnimation = 0;
416 animating = false;
417 fallThruSpeed = 0;
418 s = 0;
419 }
420
setTimeMultiplier(float t)421 void AnimationLayer::setTimeMultiplier(float t)
422 {
423 timeMultiplier = t;
424 }
425
playCurrentAnimation(int loop)426 void AnimationLayer::playCurrentAnimation(int loop)
427 {
428 playAnimation(currentAnimation, loop);
429 }
430
animate(const std::string & a,int loop)431 void AnimationLayer::animate(const std::string &a, int loop)
432 {
433 std::string animation = a;
434 stringToLower(animation);
435
436 bool played = false;
437 for (int i = 0; i < s->animations.size(); i++)
438 {
439 if (s->animations[i].name == animation)
440 {
441 playAnimation(i, loop);
442 played = true;
443 break;
444 }
445 }
446 if (!played)
447 {
448 std::ostringstream os;
449 os << "Could not find animation: " << animation;
450 debugLog(os.str());
451 }
452 }
453
playAnimation(int idx,int loop)454 void AnimationLayer::playAnimation(int idx, int loop)
455 {
456 if (!(&s->animLayers[0] == this))
457 {
458 fallThru = 1;
459 fallThruSpeed = 10;
460 }
461 timeMultiplier = 1;
462 //currentKeyframe = 0;
463 currentAnimation = idx;
464 timer = 0;
465 animating = true;
466
467 this->loop = loop;
468
469 animationLength = getCurrentAnimation()->getAnimationLength();
470 //doNextKeyframe();
471 }
472
enqueueAnimation(const std::string & anim,int loop)473 void AnimationLayer::enqueueAnimation(const std::string& anim, int loop)
474 {
475 enqueuedAnimation = anim;
476 enqueuedAnimationLoop = loop;
477 stringToLower(enqueuedAnimation);
478 }
479
transitionAnimate(std::string anim,float time,int loop)480 float AnimationLayer::transitionAnimate(std::string anim, float time, int loop)
481 {
482 stringToLower(anim);
483 float totalTime =0;
484 if (createTransitionAnimation(anim, time))
485 {
486 timeMultiplier = 1;
487
488 currentAnimation = -1;
489 this->loop = 0;
490 timer = 0;
491 animating = 1;
492 animationLength = getCurrentAnimation()->getAnimationLength();
493 enqueueAnimation(anim, loop);
494 Animation *a = this->s->getAnimation(anim);
495 if (a)
496 {
497 if (loop > -1)
498 totalTime = a->getAnimationLength()*(loop+1) + time;
499 else
500 totalTime = a->getAnimationLength() + time;
501 }
502 }
503 return totalTime;
504 }
505
setSkeletalSprite(SkeletalSprite * s)506 void AnimationLayer::setSkeletalSprite(SkeletalSprite *s)
507 {
508 this->s = s;
509 }
510
getCurrentAnimation()511 Animation* AnimationLayer::getCurrentAnimation()
512 {
513 if (currentAnimation == -1)
514 return &blendAnimation;
515 if (currentAnimation < 0 || currentAnimation >= s->animations.size())
516 {
517 std::ostringstream os;
518 os << "skel: " << s->filenameLoaded << " currentAnimation: " << currentAnimation << " is out of range\n error in anim file?";
519 exit_error(os.str());
520 return 0;
521 }
522 return &s->animations[currentAnimation];
523 }
524
createTransitionAnimation(const std::string & anim,float time)525 bool AnimationLayer::createTransitionAnimation(const std::string& anim, float time)
526 {
527 //Animation *a = getCurrentAnimation();
528 Animation *to = s->getAnimation(anim);
529 if (!to) return false;
530 blendAnimation.keyframes.clear();
531 SkeletalKeyframe k;
532 k.t = 0;
533 for (int i = 0; i < s->bones.size(); i++)
534 {
535 BoneKeyframe b;
536 b.idx = s->bones[i]->boneIdx;
537 b.x = s->bones[i]->position.x;
538 b.y = s->bones[i]->position.y;
539 b.rot = s->bones[i]->rotation.z;
540 b.strip = s->bones[i]->strip;
541 b.sx = s->bones[i]->scale.x;
542 b.sy = s->bones[i]->scale.y;
543 k.keyframes.push_back(b);
544 }
545 blendAnimation.keyframes.push_back(k);
546
547 SkeletalKeyframe k2;
548 SkeletalKeyframe *rk = to->getKeyframe(0);
549 if (!rk) return false;
550 k2 = *rk;
551 k2.t = time;
552 blendAnimation.keyframes.push_back(k2);
553
554 blendAnimation.name = anim;
555 return true;
556 }
557
558
stopAnimation()559 void AnimationLayer::stopAnimation()
560 {
561 animating = false;
562 if (!enqueuedAnimation.empty())
563 {
564 animate(enqueuedAnimation, enqueuedAnimationLoop);
565 enqueuedAnimation = "";
566 enqueuedAnimationLoop = 0;
567 }
568 }
569
isAnimating()570 bool AnimationLayer::isAnimating()
571 {
572 return animating;
573 }
574
getAnimationLength()575 float AnimationLayer::getAnimationLength()
576 {
577 return animationLength;
578 }
579
getNumKeyframes()580 int Animation::getNumKeyframes()
581 {
582 return keyframes.size();
583 }
584
getKeyframe(int key)585 SkeletalKeyframe *Animation::getKeyframe(int key)
586 {
587 if (key < 0 || key >= keyframes.size()) return 0;
588 return &keyframes[key];
589 }
590
reverse()591 void Animation::reverse()
592 {
593 Keyframes copy = keyframes;
594 Keyframes copy2 = keyframes;
595 keyframes.clear();
596 int sz = copy.size()-1;
597 for (int i = sz; i >= 0; i--)
598 {
599 keyframes.push_back(copy[i]);
600 keyframes[keyframes.size()-1].t = copy2[sz-i].t;
601 }
602 reorderKeyframes();
603 }
604
getAnimationLength()605 float Animation::getAnimationLength()
606 {
607 return getLastKeyframe()->t;
608 }
609
getLastKeyframe()610 SkeletalKeyframe *Animation::getLastKeyframe()
611 {
612 if (!keyframes.empty())
613 return &keyframes[keyframes.size()-1];
614 return 0;
615 }
616
getFirstKeyframe()617 SkeletalKeyframe *Animation::getFirstKeyframe()
618 {
619 if (!keyframes.empty())
620 return &keyframes[0];
621 return 0;
622 }
623
reorderKeyframes()624 void Animation::reorderKeyframes()
625 {
626 /*
627 std::vector<SkeletalKeyframe> copy = this->keyframes;
628 keyframes.clear();
629 */
630 for (int i = 0; i < keyframes.size(); i++)
631 {
632 for (int j = 0; j < keyframes.size()-1; j++)
633 {
634 if (keyframes[j].t > keyframes[j+1].t)
635 {
636 SkeletalKeyframe temp = keyframes[j+1];
637 keyframes[j+1] = keyframes[j];
638 keyframes[j] = temp;
639 }
640 }
641 }
642 }
643
cloneKey(int key,float toffset)644 void Animation::cloneKey(int key, float toffset)
645 {
646 std::vector<SkeletalKeyframe> copy = this->keyframes;
647 keyframes.clear();
648 int i = 0;
649 for (i = 0; i <= key; i++)
650 keyframes.push_back(copy[i]);
651 for (i = key; i < copy.size(); i++)
652 keyframes.push_back(copy[i]);
653 keyframes[key+1].t += toffset;
654 }
655
deleteKey(int key)656 void Animation::deleteKey(int key)
657 {
658 std::vector<SkeletalKeyframe> copy = this->keyframes;
659 keyframes.clear();
660 int i = 0;
661 for (i = 0; i < key; i++)
662 keyframes.push_back(copy[i]);
663 for (i = key+1; i < copy.size(); i++)
664 keyframes.push_back(copy[i]);
665 }
666
getSkeletalKeyframeIndex(SkeletalKeyframe * skey)667 int Animation::getSkeletalKeyframeIndex(SkeletalKeyframe *skey)
668 {
669 for (int i = 0; i < keyframes.size(); i++)
670 {
671 if (&keyframes[i] == skey)
672 return i;
673 }
674 return -1;
675 }
676
getBoneKeyframe(int idx)677 BoneKeyframe *SkeletalKeyframe::getBoneKeyframe(int idx)
678 {
679 for (int i = 0; i < keyframes.size(); i++)
680 {
681 if (keyframes[i].idx == idx)
682 {
683 return &keyframes[i];
684 }
685 }
686 return 0;
687 }
688
getPrevKeyframe(float t)689 SkeletalKeyframe *Animation::getPrevKeyframe(float t)
690 {
691 int kf = -1;
692 for (int i = keyframes.size()-1; i >= 0; i--)
693 {
694 if (t >= keyframes[i].t)
695 {
696 kf = i;
697 break;
698 }
699 }
700 if (kf == -1)
701 return 0;
702 if (kf >= keyframes.size())
703 kf = keyframes.size()-1;
704 if (kf < 0)
705 kf = 0;
706 return &keyframes[kf];
707 }
708
getNextKeyframe(float t)709 SkeletalKeyframe *Animation::getNextKeyframe(float t)
710 {
711 int kf = -1;
712 for (int i = 0; i < keyframes.size(); i++)
713 {
714 if (t <= keyframes[i].t)
715 {
716 kf = i;
717 break;
718 }
719 }
720 // kf++;
721 if (kf == -1)
722 return 0;
723 if (kf >= keyframes.size())
724 kf = keyframes.size()-1;
725 if (kf < 0)
726 kf = 0;
727 return &keyframes[kf];
728 }
729
SkeletalSprite()730 SkeletalSprite::SkeletalSprite() : RenderObject()
731 {
732 frozen = false;
733 animKeyNotify = 0;
734 loaded = false;
735 animLayers.resize(10);
736 for (int i = 0; i < animLayers.size(); i++)
737 animLayers[i].setSkeletalSprite(this);
738 selectedBone = -1;
739 }
740
741
setAnimationKeyNotify(RenderObject * r)742 void SkeletalSprite::setAnimationKeyNotify(RenderObject *r)
743 {
744 animKeyNotify = r;
745 }
746
animate(const std::string & animation,int loop,int layer)747 void SkeletalSprite::animate(const std::string &animation, int loop, int layer)
748 {
749 animLayers[layer].animate(animation, loop);
750 }
751
transitionAnimate(const std::string & anim,float time,int loop,int layer)752 float SkeletalSprite::transitionAnimate(const std::string& anim, float time, int loop, int layer)
753 {
754 AnimationLayer *animLayer = getAnimationLayer(layer);
755 if (animLayer)
756 return animLayer->transitionAnimate(anim, time, loop);
757
758 std::ostringstream os;
759 os << "playing animation on invalid layer: " << layer;
760 errorLog(os.str());
761 return 0;
762 }
763
getAnimationLayer(int l)764 AnimationLayer* SkeletalSprite::getAnimationLayer(int l)
765 {
766 if (l >= 0 && l < animLayers.size())
767 {
768 return &animLayers[l];
769 }
770 std::ostringstream os;
771 os << "couldn't get animLayer: " << l;
772 debugLog(os.str());
773 return 0;
774 }
775
isLoaded()776 bool SkeletalSprite::isLoaded()
777 {
778 return loaded;
779 }
780
onUpdate(float dt)781 void SkeletalSprite::onUpdate(float dt)
782 {
783 if (frozen) return;
784 RenderObject::onUpdate(dt);
785
786 int i = 0;
787
788 for (i = 0; i < bones.size(); i++)
789 {
790 Bone *b = bones[i];
791 if (b && !b->collisionMask.empty())
792 {
793 if (b->collisionMask.size() != b->transformedCollisionMask.size())
794 {
795 b->transformedCollisionMask.resize(b->collisionMask.size());
796 }
797 for (int i = 0; i < b->collisionMask.size(); i++)
798 {
799 b->transformedCollisionMask[i] = b->getWorldCollidePosition(b->collisionMask[i]);
800 }
801 }
802 }
803
804 /*
805 for (int i = 0; i < bones.size(); i++)
806 {
807 bones[i]->update(dt);
808 }
809 */
810 for (i = 0; i < animLayers.size(); i++)
811 {
812 animLayers[i].update(dt);
813 }
814 //updateBones();
815 }
816
update(float dt)817 void AnimationLayer::update(float dt)
818 {
819 timeMultiplier.update(dt);
820 if (animating)
821 {
822 timer += dt*timeMultiplier.x;
823
824 if (timer > animationLength)
825 {
826 float leftover;
827 if (animationLength > 0)
828 leftover = fmodf(timer, animationLength);
829 else
830 leftover = 0;
831 timer = animationLength;
832 if (loop==-1 || loop > 0)
833 {
834 playAnimation(this->currentAnimation, loop);
835 if (loop > 0)
836 loop --;
837 timer = leftover;
838 }
839 else
840 {
841 stopAnimation();
842 }
843 }
844 updateBones();
845 }
846 else if (!animating)
847 {
848 if (fallThru > 0)
849 {
850 fallThru -= dt * fallThruSpeed;
851 if (fallThru < 0)
852 fallThru = 0;
853 updateBones();
854 }
855 }
856 }
857
saveSkeletal(const std::string & fn)858 bool SkeletalSprite::saveSkeletal(const std::string &fn)
859 {
860 std::string file, filename=fn;
861 stringToLower(filename);
862
863 if (!secondaryAnimationPath.empty())
864 {
865 createDir(secondaryAnimationPath);
866 file = secondaryAnimationPath + filename + ".xml";
867 }
868 else
869 {
870 file = animationPath + filename + ".xml";
871 }
872
873 int i = 0;
874 XMLDocument *xml = _retrieveSkeletalXML(file, true);
875 xml->Clear();
876
877 XMLElement *animationLayers = xml->NewElement("AnimationLayers");
878 for (i = 0; i < animLayers.size(); i++)
879 {
880 XMLElement *animationLayer = xml->NewElement("AnimationLayer");
881 if (animLayers[i].ignoreBones.size() > 0)
882 {
883 std::ostringstream os;
884 for (int j = 0; j < animLayers[i].ignoreBones.size(); j++)
885 {
886 os << animLayers[i].ignoreBones[j] << " ";
887 }
888 animationLayer->SetAttribute("ignore", os.str().c_str());
889 }
890 if (animLayers[i].includeBones.size() > 0)
891 {
892 std::ostringstream os;
893 for (int j = 0; j < animLayers[i].includeBones.size(); j++)
894 {
895 os << animLayers[i].includeBones[j] << " ";
896 }
897 animationLayer->SetAttribute("include", os.str().c_str());
898 }
899 if (!animLayers[i].name.empty())
900 {
901 animationLayer->SetAttribute("name", animLayers[i].name.c_str());
902 }
903
904 animationLayers->InsertEndChild(animationLayer);
905 }
906 xml->InsertEndChild(animationLayers);
907
908
909 XMLElement *bones = xml->NewElement("Bones");
910 for (i = 0; i < this->bones.size(); i++)
911 {
912 XMLElement *bone = xml->NewElement("Bone");
913 bone->SetAttribute("idx", this->bones[i]->boneIdx);
914 bone->SetAttribute("gfx", this->bones[i]->gfx.c_str());
915 bone->SetAttribute("pidx", this->bones[i]->pidx);
916 bone->SetAttribute("name", this->bones[i]->name.c_str());
917 bone->SetAttribute("fh", this->bones[i]->isfh());
918 bone->SetAttribute("fv", this->bones[i]->isfv());
919 bone->SetAttribute("gc", this->bones[i]->generateCollisionMask);
920 bone->SetAttribute("cr", this->bones[i]->collideRadius);
921 if (!this->bones[i]->renderQuad)
922 {
923 bone->SetAttribute("rq", this->bones[i]->fileRenderQuad);
924 }
925 if (!this->bones[i]->collisionRects.empty())
926 {
927 std::ostringstream os;
928 os << this->bones[i]->collisionRects.size() << " ";
929 for (int j = 0; j < this->bones[i]->collisionRects.size(); j++)
930 {
931 RectShape *r = &this->bones[i]->collisionRects[j];
932 int x, y, w, h;
933 r->getCWH(&x, &y, &w, &h);
934 os << x << " " << y << " " << w << " " << h << " ";
935 }
936 bone->SetAttribute("crects", os.str().c_str());
937 }
938 std::ostringstream os;
939 os << this->bones[i]->collidePosition.x << " " << this->bones[i]->collidePosition.y;
940 bone->SetAttribute("cp", os.str().c_str());
941 if (this->bones[i]->rbp)
942 bone->SetAttribute("rbp", this->bones[i]->rbp);
943 if (this->bones[i]->getRenderPass())
944 bone->SetAttribute("pass", this->bones[i]->getRenderPass());
945 if (this->bones[i]->offset.x)
946 bone->SetAttribute("offx", this->bones[i]->offset.x);
947 if (this->bones[i]->offset.y)
948 bone->SetAttribute("offy", this->bones[i]->offset.y);
949 if (!this->bones[i]->prt.empty())
950 bone->SetAttribute("prt", this->bones[i]->prt.c_str());
951 if (!this->bones[i]->changeStrip.empty())
952 {
953 std::ostringstream os;
954 os << this->bones[i]->stripVert << " " << this->bones[i]->changeStrip.size();
955 bone->SetAttribute("strip", os.str().c_str());
956 }
957 if (!this->bones[i]->internalOffset.isZero())
958 {
959 std::ostringstream os;
960 os << this->bones[i]->internalOffset.x << " " << this->bones[i]->internalOffset.y;
961 bone->SetAttribute("io", os.str().c_str());
962 }
963 if (this->bones[i]->isRepeatingTextureToFill())
964 {
965 bone->SetAttribute("rt", 1);
966 }
967 if (this->bones[i]->originalScale.x != 1 || this->bones[i]->originalScale.y != 1)
968 {
969 std::ostringstream os;
970 os << this->bones[i]->originalScale.x << " " << this->bones[i]->originalScale.y;
971 bone->SetAttribute("sz", os.str().c_str());
972 }
973 /*
974 if (this->bones[i]->color.x != 1 || this->bones[i]->color.y != 1 || this->bones[i]->color.z != 1)
975 {
976 std::ostringstream os;
977 os << this->bones[i]->color.x << " " << this->bones[i]->color.y << " " << this->bones[i]->color.z;
978 bone->SetAttribute("color", os.str().c_str());
979 }
980 */
981
982 for (Children::iterator j = this->bones[i]->children.begin(); j != this->bones[i]->children.end(); j++)
983 {
984 Bone *b = dynamic_cast<Bone*>(*j);
985 Quad *q = dynamic_cast<Quad*>(*j);
986 Particle *p = dynamic_cast<Particle*>(*j);
987 if (q && !b && !p)
988 {
989 XMLElement *frame = xml->NewElement("Frame");
990 frame->SetAttribute("gfx", q->texture->name.c_str());
991 if (q->getRenderPass() != 0)
992 {
993 frame->SetAttribute("pass", q->getRenderPass());
994 }
995 bone->InsertEndChild(frame);
996 }
997 }
998 bones->InsertEndChild(bone);
999 }
1000 xml->InsertEndChild(bones);
1001
1002 XMLElement *animations = xml->NewElement("Animations");
1003 for (i = 0; i < this->animations.size(); i++)
1004 {
1005 Animation *a = &this->animations[i];
1006 XMLElement *animation = xml->NewElement("Animation");
1007 animation->SetAttribute("name", a->name.c_str());
1008 for (int j = 0; j < a->keyframes.size(); j++)
1009 {
1010 XMLElement *key = xml->NewElement("Key");
1011 if (!a->keyframes[j].sound.empty())
1012 key->SetAttribute("sound", a->keyframes[j].sound.c_str());
1013 if (!a->keyframes[j].cmd.empty())
1014 {
1015 key->SetAttribute("cmd", a->keyframes[j].cmd.c_str());
1016 }
1017 if (a->keyframes[j].lerpType != 0)
1018 {
1019 key->SetAttribute("lerp", a->keyframes[j].lerpType);
1020 }
1021 std::ostringstream os;
1022 os << a->keyframes[j].t << " ";
1023 std::ostringstream szos;
1024 for (int k = 0; k < a->keyframes[j].keyframes.size(); k++)
1025 {
1026 BoneKeyframe *b = &a->keyframes[j].keyframes[k];
1027 os << b->idx << " " << b->x << " " << b->y << " " << b->rot << " ";
1028 os << b->strip.size() << " ";
1029 for (int i = 0; i < b->strip.size(); i++)
1030 {
1031 os << b->strip[i].x << " " << b->strip[i].y << " ";
1032 }
1033 if (b->doScale)
1034 {
1035 szos << b->idx << " " << b->sx << " " << b->sy << " ";
1036 }
1037 }
1038 std::string szoss = szos.str();
1039 if (!szoss.empty())
1040 key->SetAttribute("sz", szoss.c_str());
1041
1042 key->SetAttribute("e", os.str().c_str());
1043
1044 animation->InsertEndChild(key);
1045 }
1046 animations->InsertEndChild(animation);
1047 }
1048 xml->InsertEndChild(animations);
1049 return xml->SaveFile(file.c_str()) == XML_SUCCESS;
1050 }
1051
getBoneIdx(Bone * b)1052 int SkeletalSprite::getBoneIdx(Bone *b)
1053 {
1054 for (int i = 0; i < bones.size(); i++)
1055 {
1056 if (bones[i] == b)
1057 return i;
1058 }
1059 return -1;
1060 }
1061
toggleBone(int idx,int v)1062 void SkeletalSprite::toggleBone(int idx, int v)
1063 {
1064 if (idx >= 0 && idx < bones.size())
1065 {
1066 bones[idx]->alpha.x = v;
1067 }
1068 }
1069
getBoneByName(const std::string & name)1070 Bone *SkeletalSprite::getBoneByName(const std::string &name)
1071 {
1072 for (int i = 0; i < bones.size(); i++)
1073 {
1074 if (bones[i]->name == name)
1075 return bones[i];
1076 }
1077 std::ostringstream os;
1078 os << "Could not find bone with name[" << name << "]";
1079 debugLog(os.str());
1080 return 0;
1081 }
1082
getBoneByIdx(int idx)1083 Bone *SkeletalSprite::getBoneByIdx(int idx)
1084 {
1085 for (int i = 0; i < bones.size(); i++)
1086 {
1087 if (bones[i]->boneIdx == idx)
1088 return bones[i];
1089 }
1090 std::ostringstream os;
1091 os << "Could not find bone with idx[" << idx << "]";
1092 debugLog(os.str());
1093 return 0;
1094 }
1095
initBone(int idx,std::string gfx,int pidx,int rbp,std::string name,float cr,bool fh,bool fv,const Vector & cp)1096 Bone *SkeletalSprite::initBone(int idx, std::string gfx, int pidx, int rbp, std::string name, float cr, bool fh, bool fv, const Vector &cp)
1097 {
1098 Bone *b = new Bone;
1099 b->boneIdx = idx;
1100 b->setTexture(gfx);
1101 b->skeleton = this;
1102 b->gfx = gfx;
1103 b->rbp = rbp;
1104 b->renderBeforeParent = rbp;
1105 b->pidx = pidx;
1106 b->collideRadius = cr;
1107 b->collidePosition = cp;
1108 b->name = name;
1109 //core->generateCollisionMask(b);
1110 if (fh)
1111 b->flipHorizontal();
1112 if (fv)
1113 b->flipVertical();
1114 bones.push_back(b);
1115 return b;
1116 }
1117
firstAnimation()1118 void SkeletalSprite::firstAnimation()
1119 {
1120 stopAnimation();
1121 animLayers[0].currentAnimation = 0;
1122 }
1123
lastAnimation()1124 void SkeletalSprite::lastAnimation()
1125 {
1126 stopAnimation();
1127 animLayers[0].currentAnimation = animations.size()-1;
1128 }
1129
nextAnimation()1130 void SkeletalSprite::nextAnimation()
1131 {
1132 stopAnimation();
1133 animLayers[0].currentAnimation++;
1134 if (animLayers[0].currentAnimation >= animations.size())
1135 animLayers[0].currentAnimation = 0;
1136 }
1137
prevAnimation()1138 void SkeletalSprite::prevAnimation()
1139 {
1140 stopAnimation();
1141 animLayers[0].currentAnimation--;
1142 if (animLayers[0].currentAnimation < 0)
1143 animLayers[0].currentAnimation = animations.size()-1;
1144 }
1145
deleteBones()1146 void SkeletalSprite::deleteBones()
1147 {
1148 bones.clear();
1149 for(Children::iterator it = children.begin(); it != children.end(); ++it)
1150 {
1151 (*it)->safeKill();
1152 }
1153 bones.clear();
1154 }
1155
getAnimation(const std::string & anim)1156 Animation *SkeletalSprite::getAnimation(const std::string& anim)
1157 {
1158 for (int i = 0; i < animations.size(); i++)
1159 {
1160 if (animations[i].name == anim)
1161 return &animations[i];
1162 }
1163 return 0;
1164 }
1165
loadSkin(const std::string & fn)1166 void SkeletalSprite::loadSkin(const std::string &fn)
1167 {
1168 std::string file;
1169
1170 if (!secondaryAnimationPath.empty())
1171 {
1172 file = secondaryAnimationPath + skinPath + fn + ".xml";
1173 }
1174
1175 if (file.empty() || !exists(file, false))
1176 {
1177 file = animationPath + skinPath + fn + ".xml";
1178 }
1179
1180 file = core->adjustFilenameCase(file);
1181
1182 if (!exists(file))
1183 {
1184 errorLog("Could not load skin[" + file + "] - File not found.");
1185 return;
1186 }
1187 XMLDocument *d = _retrieveSkeletalXML(file, false);
1188 if(!d)
1189 {
1190 errorLog("Could not load skin[" + file + "] - Malformed XML.");
1191 return;
1192 }
1193
1194 XMLElement *bonesXml = d->FirstChildElement("Bones");
1195 if (bonesXml)
1196 {
1197 XMLElement *boneXml = bonesXml->FirstChildElement("Bone");
1198 while (boneXml)
1199 {
1200 int idx = atoi(boneXml->Attribute("idx"));
1201 Bone *b = getBoneByIdx(idx);
1202 if (b)
1203 {
1204 if (boneXml->Attribute("rq"))
1205 {
1206 int rq = atoi(boneXml->Attribute("rq"));
1207 b->renderQuad = rq;
1208 }
1209
1210 std::string gfx;
1211 if (boneXml->Attribute("gfx"))
1212 {
1213 gfx = boneXml->Attribute("gfx");
1214 if (!gfx.empty())
1215 {
1216 b->gfx = gfx;
1217 b->setTexture(b->gfx);
1218 b->renderQuad = true;
1219 }
1220 }
1221
1222 if (gfx.empty())
1223 {
1224 b->renderQuad = false;
1225 }
1226
1227 if (boneXml->Attribute("fh"))
1228 {
1229 int fh = atoi(boneXml->Attribute("fh"));
1230 if (fh)
1231 b->flipHorizontal();
1232 }
1233 if (boneXml->Attribute("fv"))
1234 {
1235 int fv = atoi(boneXml->Attribute("fv"));
1236 if (fv)
1237 b->flipVertical();
1238 }
1239
1240 /*
1241 if (boneXml->Attribute("a"))
1242 {
1243 float alpha = 0;
1244 boneXml->Attribute("a", &alpha);
1245 b->alpha = alpha;
1246 }
1247 */
1248 /*
1249 // this is for SKINS
1250 if (boneXml->Attribute("sz"))
1251 {
1252 float v1, v2;
1253 SimpleIStringStream is(boneXml->Attribute("sz"));
1254 is >> v1 >> v2;
1255 b->scale = Vector(v1,v2);
1256 b->originalScale = b->scale;
1257 }
1258 */
1259 }
1260 else
1261 {
1262 std::ostringstream os;
1263 os << "SkinLoad: Could not find idx[" << idx << "]";
1264 debugLog(os.str());
1265 }
1266 boneXml = boneXml->NextSiblingElement("Bone");
1267 }
1268 }
1269 }
1270
stopAnimation(int layer)1271 void SkeletalSprite::stopAnimation(int layer)
1272 {
1273 animLayers[layer].stopAnimation();
1274 }
1275
stopAllAnimations()1276 void SkeletalSprite::stopAllAnimations()
1277 {
1278 for (int i = 0; i < animLayers.size(); i++)
1279 {
1280 animLayers[i].stopAnimation();
1281 }
1282 }
1283
playCurrentAnimation(int loop,int layer)1284 void SkeletalSprite::playCurrentAnimation(int loop, int layer)
1285 {
1286 animLayers[layer].playCurrentAnimation(loop);
1287 }
1288
loadSkeletal(const std::string & fn)1289 void SkeletalSprite::loadSkeletal(const std::string &fn)
1290 {
1291 filenameLoaded = "";
1292 loaded = false;
1293 stopAnimation();
1294 animLayers.clear();
1295 deleteBones();
1296
1297
1298 filenameLoaded = fn;
1299 stringToLower(filenameLoaded);
1300
1301 std::string file;
1302
1303 if (!secondaryAnimationPath.empty())
1304 {
1305 file = secondaryAnimationPath + filenameLoaded + ".xml";
1306 }
1307
1308 if (file.empty() || !exists(file, false))
1309 {
1310 file = animationPath + filenameLoaded + ".xml";
1311 }
1312
1313 if (!exists(file))
1314 {
1315 filenameLoaded = "";
1316 errorLog("Could not load skeletal[" + file + "] - File not found.");
1317 return;
1318 }
1319
1320 file = core->adjustFilenameCase(file);
1321
1322 XMLDocument *xml = _retrieveSkeletalXML(file, false);
1323 if(!xml)
1324 {
1325 filenameLoaded = "";
1326 errorLog("Could not load skeletal[" + file + "] - Malformed XML.");
1327 return;
1328 }
1329
1330 loaded = true;
1331
1332 XMLElement *bones = xml->FirstChildElement("Bones");
1333 if (bones)
1334 {
1335 if (bones->Attribute("scale"))
1336 {
1337 SimpleIStringStream is(bones->Attribute("scale"));
1338 is >> scale.x >> scale.y;
1339 }
1340
1341 XMLElement *bone = bones->FirstChildElement("Bone");
1342 while(bone)
1343 {
1344 int idx = atoi(bone->Attribute("idx"));
1345 int pidx = -1, rbp=0, cr=0, fh=0, fv=0;
1346
1347 std::string name;
1348 Vector cp;
1349 if (bone->Attribute("pidx"))
1350 pidx = atoi(bone->Attribute("pidx"));
1351 if (bone->Attribute("rbp"))
1352 rbp = atoi(bone->Attribute("rbp"));
1353
1354 if (bone->Attribute("name"))
1355 name = bone->Attribute("name");
1356 if (bone->Attribute("cr"))
1357 cr = atoi(bone->Attribute("cr"));
1358 if (bone->Attribute("fh"))
1359 fh = atoi(bone->Attribute("fh"));
1360 if (bone->Attribute("fv"))
1361 fv = atoi(bone->Attribute("fv"));
1362 if (bone->Attribute("cp"))
1363 {
1364 SimpleIStringStream is(bone->Attribute("cp"));
1365 is >> cp.x >> cp.y;
1366 }
1367
1368
1369
1370
1371
1372 std::string gfx = bone->Attribute("gfx");
1373 Bone *newb = initBone(idx, gfx, pidx, rbp, name, cr, fh, fv, cp);
1374 if (bone->Attribute("offx"))
1375 newb->offset.x = atoi(bone->Attribute("offx"));
1376 if (bone->Attribute("offy"))
1377 newb->offset.y = atoi(bone->Attribute("offy"));
1378
1379 if (bone->Attribute("crects"))
1380 {
1381 SimpleIStringStream is(bone->Attribute("crects"));
1382 int num = 0;
1383 is >> num;
1384 for (int i = 0; i < num; i++)
1385 {
1386 RectShape r;
1387 int x, y, w, h;
1388 is >> x >> y >> w >> h;
1389 r.setCWH(x, y, w, h);
1390
1391 newb->collisionRects.push_back(r);
1392 }
1393 }
1394
1395 if (bone->Attribute("prt"))
1396 {
1397 newb->prt = bone->Attribute("prt");
1398 SimpleIStringStream is(newb->prt);
1399 int slot;
1400 while (is >> slot)
1401 {
1402 std::string pfile;
1403 is >> pfile;
1404 // add particle system + load
1405 newb->emitters[slot] = new ParticleEffect;
1406 ParticleEffect *e = newb->emitters[slot];
1407 newb->addChild(e, PM_POINTER);
1408 e->load(pfile);
1409 // hack for now:
1410 //e->start();
1411 }
1412 }
1413 XMLElement *fr=0;
1414 fr = bone->FirstChildElement("Frame");
1415 int frc=0;
1416 while(fr)
1417 {
1418 Quad *q=0;
1419 std::string gfx;
1420 if (fr->Attribute("gfx"))
1421 {
1422 gfx = fr->Attribute("gfx");
1423 q = newb->addFrame(gfx);
1424 }
1425 if (fr->Attribute("pass"))
1426 {
1427 if (q)
1428 {
1429 q->setRenderPass(atoi(fr->Attribute("pass")));
1430 }
1431 }
1432 fr = fr->NextSiblingElement("Frame");
1433 frc++;
1434 }
1435 if (frc)
1436 {
1437 newb->showFrame(0);
1438 }
1439 if (bone->Attribute("pass"))
1440 {
1441 newb->setRenderPass(atoi(bone->Attribute("pass")));
1442 }
1443 if (bone->Attribute("gc"))
1444 {
1445 newb->generateCollisionMask = atoi(bone->Attribute("gc"));
1446 }
1447 if (bone->Attribute("rq"))
1448 {
1449 newb->renderQuad = newb->fileRenderQuad = atoi(bone->Attribute("rq"));
1450 }
1451 if (bone->Attribute("io"))
1452 {
1453 SimpleIStringStream is(bone->Attribute("io"));
1454 is >> newb->internalOffset.x >> newb->internalOffset.y;
1455 }
1456
1457 if (bone->Attribute("strip"))
1458 {
1459 SimpleIStringStream is(bone->Attribute("strip"));
1460 bool vert;
1461 int num;
1462 is >> vert >> num;
1463 newb->createStrip(vert, num);
1464 }
1465 if (bone->Attribute("sz"))
1466 {
1467 float sx, sy;
1468 SimpleIStringStream is(bone->Attribute("sz"));
1469 is >> sx >> sy;
1470
1471 newb->scale = newb->originalScale = Vector(sx,sy);
1472 }
1473 if (bone->Attribute("rt"))
1474 {
1475 newb->repeatTextureToFill(true);
1476 }
1477
1478 if (bone->Attribute("blend"))
1479 {
1480 //if (bone->Attribute("blend")=="add")
1481 newb->blendType = blendType = BLEND_ADD;
1482 }
1483
1484 if (bone->Attribute("alpha"))
1485 {
1486 float a=1.0;
1487 SimpleIStringStream is(bone->Attribute("alpha"));
1488 is >> a;
1489 newb->alpha = a;
1490 }
1491
1492 if (bone->Attribute("alphaMod"))
1493 {
1494 float a=1.0;
1495 SimpleIStringStream is(bone->Attribute("alphaMod"));
1496 is >> a;
1497 newb->alphaMod = a;
1498 }
1499
1500 if (bone->Attribute("segs"))
1501 {
1502 int x, y;
1503 float dgox, dgoy, dgmx, dgmy, dgtm;
1504 bool dgo;
1505 SimpleIStringStream is(bone->Attribute("segs"));
1506 is >> x >> y >> dgox >> dgoy >> dgmx >> dgmy >> dgtm >> dgo;
1507 newb->setSegs(x, y, dgox, dgoy, dgmx, dgmy, dgtm, dgo);
1508 }
1509
1510 if (bone->Attribute("color"))
1511 {
1512 SimpleIStringStream in(bone->Attribute("color"));
1513 in >> newb->color.x >> newb->color.y >> newb->color.z;
1514 }
1515 bone = bone->NextSiblingElement("Bone");
1516 }
1517 // attach bones
1518 for (int i = 0; i < this->bones.size(); i++)
1519 {
1520 Bone *b = this->bones[i];
1521 if (b->pidx != -1)
1522 {
1523 Bone *pb = getBoneByIdx(b->pidx);
1524 if (!pb)
1525 {
1526 std::ostringstream os;
1527 os << "Parent bone not found, index: " << b->pidx << " from bone idx: " << b->getIdx();
1528 debugLog(os.str());
1529 }
1530 else
1531 {
1532 pb->addChild(b, PM_POINTER);
1533 }
1534 }
1535 else
1536 addChild(b, PM_POINTER);
1537 }
1538 }
1539
1540 animLayers.clear();
1541 XMLElement *animationLayers = xml->FirstChildElement("AnimationLayers");
1542 if (animationLayers)
1543 {
1544 XMLElement *animationLayer = animationLayers->FirstChildElement("AnimationLayer");
1545 while (animationLayer)
1546 {
1547 AnimationLayer newAnimationLayer;
1548 if (animationLayer->Attribute("ignore"))
1549 {
1550 SimpleIStringStream is(animationLayer->Attribute("ignore"));
1551 int t;
1552 while (is >> t)
1553 {
1554 newAnimationLayer.ignoreBones.push_back(t);
1555 }
1556 }
1557 if (animationLayer->Attribute("include"))
1558 {
1559 SimpleIStringStream is(animationLayer->Attribute("include"));
1560 int t;
1561 while (is >> t)
1562 {
1563 newAnimationLayer.includeBones.push_back(t);
1564 }
1565 }
1566 if (animationLayer->Attribute("name"))
1567 {
1568 newAnimationLayer.name = animationLayer->Attribute("name");
1569 }
1570 newAnimationLayer.setSkeletalSprite(this);
1571 animLayers.push_back(newAnimationLayer);
1572 animationLayer = animationLayer->NextSiblingElement("AnimationLayer");
1573 }
1574 }
1575
1576 animations.clear();
1577 XMLElement *animations = xml->FirstChildElement("Animations");
1578 if (animations)
1579 {
1580 XMLElement *animation = animations->FirstChildElement("Animation");
1581 while(animation)
1582 {
1583 Animation newAnimation;
1584 newAnimation.name = animation->Attribute("name");
1585 stringToLower(newAnimation.name);
1586
1587 XMLElement *key = animation->FirstChildElement("Key");
1588 while (key)
1589 {
1590 SkeletalKeyframe newSkeletalKeyframe;
1591 if (key->Attribute("e"))
1592 {
1593 float time;
1594 SimpleIStringStream is(key->Attribute("e"));
1595 is >> time;
1596 int idx, x, y, rot, strip;
1597 newSkeletalKeyframe.t = time;
1598 if (key->Attribute("sound"))
1599 {
1600 newSkeletalKeyframe.sound = key->Attribute("sound");
1601 }
1602 if (key->Attribute("lerp"))
1603 {
1604 newSkeletalKeyframe.lerpType = atoi(key->Attribute("lerp"));
1605 }
1606 while (is >> idx)
1607 {
1608 BoneKeyframe b;
1609 is >> x >> y >> rot >> strip;
1610 b.idx = idx;
1611 b.x = x;
1612 b.y = y;
1613 b.rot = rot;
1614 if (strip>0)
1615 {
1616 b.strip.resize(strip);
1617 for (int i = 0; i < b.strip.size(); i++)
1618 {
1619 is >> b.strip[i].x >> b.strip[i].y;
1620 //b.strip[i].y *= 10;
1621 }
1622 }
1623 if (key->Attribute("sz"))
1624 {
1625 SimpleIStringStream is2(key->Attribute("sz"));
1626 int midx;
1627 float bsx, bsy;
1628 while (is2 >> midx)
1629 {
1630 is2 >> bsx >> bsy;
1631 if (midx == idx)
1632 {
1633 b.doScale = true;
1634 b.sx = bsx;
1635 b.sy = bsy;
1636 break;
1637 }
1638 }
1639 }
1640 newSkeletalKeyframe.keyframes.push_back(b);
1641 }
1642
1643 }
1644 if (key->Attribute("d"))
1645 {
1646 float time;
1647 SimpleIStringStream is(key->Attribute("d"));
1648 is >> time;
1649 int idx, x, y, rot;
1650
1651 newSkeletalKeyframe.t = time;
1652 if (key->Attribute("sound"))
1653 {
1654 newSkeletalKeyframe.sound = key->Attribute("sound");
1655 }
1656 while (is >> idx)
1657 {
1658 is >> x >> y >> rot;
1659 BoneKeyframe b;
1660 b.idx = idx;
1661 b.x = x;
1662 b.y = y;
1663 b.rot = rot;
1664 newSkeletalKeyframe.keyframes.push_back(b);
1665 }
1666 }
1667 if (key->Attribute("cmd"))
1668 {
1669 newSkeletalKeyframe.cmd = key->Attribute("cmd");
1670 SimpleIStringStream is(newSkeletalKeyframe.cmd);
1671 int bidx;
1672 while (is >> bidx)
1673 {
1674 Bone *b = this->getBoneByIdx(bidx);
1675 if (b)
1676 {
1677 BoneCommand bcmd;
1678 bcmd.parse(b, is);
1679 newSkeletalKeyframe.commands.push_back(bcmd);
1680 }
1681 }
1682 }
1683 // generate empty bone keys
1684 for (int i = 0; i < this->bones.size(); i++)
1685 {
1686 if (newSkeletalKeyframe.getBoneKeyframe(this->bones[i]->boneIdx))
1687 {
1688 }
1689 else
1690 {
1691 BoneKeyframe b;
1692 b.idx = this->bones[i]->boneIdx;
1693 newSkeletalKeyframe.keyframes.push_back(b);
1694 }
1695 }
1696 newAnimation.keyframes.push_back(newSkeletalKeyframe);
1697 key = key->NextSiblingElement("Key");
1698 }
1699 animation = animation->NextSiblingElement("Animation");
1700 this->animations.push_back(newAnimation);
1701 }
1702 }
1703 }
1704
getCurrentAnimation(int layer)1705 Animation *SkeletalSprite::getCurrentAnimation(int layer)
1706 {
1707 return layer < animLayers.size() ? animLayers[layer].getCurrentAnimation() : NULL;
1708 }
1709
setTime(float time,int layer)1710 void SkeletalSprite::setTime(float time, int layer)
1711 {
1712 if(layer < animLayers.size())
1713 animLayers[layer].timer = time;
1714 }
1715
updateBones()1716 void AnimationLayer::updateBones()
1717 {
1718 if (!animating && !(&s->animLayers[0] == this) && fallThru == 0) return;
1719
1720 SkeletalKeyframe *key1 = getCurrentAnimation()->getPrevKeyframe(timer);
1721 SkeletalKeyframe *key2 = getCurrentAnimation()->getNextKeyframe(timer);
1722 if (!key1 || !key2) return;
1723 float t1 = key1->t;
1724 float t2 = key2->t;
1725
1726 /*
1727 if (key1 == key2)
1728 stopAnimation();
1729 */
1730
1731 float diff = t2-t1;
1732 float dt;
1733 if (diff != 0)
1734 dt = (timer - t1)/(t2-t1);
1735 else
1736 dt = 0;
1737
1738 if (lastNewKey != key2)
1739 {
1740 if (!key2->sound.empty())
1741 {
1742 core->sound->playSfx(key2->sound);
1743 }
1744 if (!key2->commands.empty())
1745 {
1746 for (int i = 0; i < key2->commands.size(); i++)
1747 {
1748 key2->commands[i].run();
1749 }
1750 }
1751 if (s->animKeyNotify)
1752 {
1753 s->animKeyNotify->onAnimationKeyPassed(getCurrentAnimation()->getSkeletalKeyframeIndex(lastNewKey));
1754 }
1755 }
1756 lastNewKey = key2;
1757
1758 bool c = 0;
1759 for (int i = 0; i < s->bones.size(); i++)
1760 {
1761 int idx = s->bones[i]->boneIdx;
1762 Bone *b = s->bones[i];
1763
1764 if (b->segmentChain == 1)
1765 {
1766 b->updateSegments();
1767 }
1768 if (b->segmentChain < 2)
1769 {
1770 c=0;
1771 if (!ignoreBones.empty())
1772 {
1773 for (int j = 0; j < ignoreBones.size(); j++)
1774 {
1775 if (idx == ignoreBones[j])
1776 { c=1; break; }
1777 }
1778 }
1779 else if (!includeBones.empty())
1780 {
1781 c = 1;
1782 for (int j = 0; j < includeBones.size(); j++)
1783 {
1784 if (idx == includeBones[j])
1785 { c=0; break; }
1786 }
1787 }
1788 if (b->animated==Bone::ANIM_NONE)
1789 {
1790 c = 1;
1791 }
1792 if (!c)
1793 {
1794
1795 BoneKeyframe *bkey1 = key1->getBoneKeyframe(idx);
1796 BoneKeyframe *bkey2 = key2->getBoneKeyframe(idx);
1797 if (bkey1 && bkey2)
1798 {
1799 if (!animating && fallThru > 0)
1800 {
1801 //HACK: TODO: fix this up nice like below
1802 Vector p = Vector((bkey2->x-bkey1->x)*dt+bkey1->x, (bkey2->y-bkey1->y)*dt+bkey1->y);
1803 float rot = (bkey2->rot - bkey1->rot)*dt + bkey1->rot;
1804 p = Vector((p.x-b->position.x)*fallThru+b->position.x, (p.y-b->position.y)*fallThru+b->position.y);
1805 rot = (rot-b->rotation.z)*fallThru + b->rotation.z;
1806 if (b->animated==Bone::ANIM_ALL || b->animated==Bone::ANIM_POS)
1807 b->position = p;
1808 if (b->animated==Bone::ANIM_ALL || b->animated==Bone::ANIM_ROT)
1809 b->rotation.z = rot;
1810 }
1811 else
1812 {
1813 int lerpType = key2->lerpType;
1814 //k(0)×(2u3-3u2+1) + k(1)×(3u2-2u3)
1815 if (b->animated==Bone::ANIM_ALL || b->animated==Bone::ANIM_POS)
1816 {
1817 b->position = Vector(lerp(bkey1->x, bkey2->x, dt, lerpType), lerp(bkey1->y, bkey2->y, dt, lerpType));
1818 }
1819 if (b->animated==Bone::ANIM_ALL || b->animated==Bone::ANIM_ROT)
1820 {
1821 b->rotation.z = lerp(bkey1->rot, bkey2->rot, dt, lerpType);
1822 }
1823 if (b->animated==Bone::ANIM_ALL && (bkey1->doScale || bkey2->doScale))
1824 {
1825 b->scale.x = lerp(bkey1->sx, bkey2->sx, dt, lerpType);
1826 b->scale.y = lerp(bkey1->sy, bkey2->sy, dt, lerpType);
1827 }
1828 if (b->animated==Bone::ANIM_ALL && !b->changeStrip.empty())
1829 {
1830 if (bkey2->strip.size() < b->changeStrip.size())
1831 bkey2->strip.resize(b->changeStrip.size());
1832 if (bkey1->strip.size() < b->changeStrip.size())
1833 bkey1->strip.resize(b->changeStrip.size());
1834 for (int i = 0; i < b->changeStrip.size(); i++)
1835 {
1836 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));
1837 }
1838 b->setGridPoints(b->stripVert, b->changeStrip);
1839 }
1840 }
1841 }
1842 }
1843 }
1844 }
1845 }
1846
setFreeze(bool f)1847 void SkeletalSprite::setFreeze(bool f)
1848 {
1849 frozen = f;
1850 }
1851
updateBones()1852 void SkeletalSprite::updateBones()
1853 {
1854 if (!frozen)
1855 {
1856 for (int i = 0; i < animLayers.size(); i++)
1857 {
1858 animLayers[i].updateBones();
1859 }
1860 }
1861 /*
1862 for (int i = animLayers.size()-1; i >= 0; i--)
1863 {
1864 if (animLayers[i].animating)
1865 {
1866 animLayers[i].updateBones();
1867 return;
1868 }
1869 }
1870 */
1871
1872 }
1873
isAnimating(int layer)1874 bool SkeletalSprite::isAnimating(int layer)
1875 {
1876 return animLayers[layer].animating;
1877 }
1878
setTimeMultiplier(float t,int layer)1879 void SkeletalSprite::setTimeMultiplier(float t, int layer)
1880 {
1881 animLayers[layer].timeMultiplier = t;
1882 }
1883
getSelectedBone(bool mouseBased)1884 Bone* SkeletalSprite::getSelectedBone(bool mouseBased)
1885 {
1886 if (!loaded) return 0;
1887 if (mouseBased)
1888 {
1889 float closestDist = HUGE_VALF;
1890 Bone *b = 0;
1891 Vector p = core->mouse.position;
1892 for (int i = 0; i < bones.size(); i++)
1893 {
1894 if (bones[i]->renderQuad || core->getShiftState())
1895 {
1896 bones[i]->color = Vector(1,1,1);
1897 if (bones[i]->renderQuad && bones[i]->isCoordinateInsideWorld(p))
1898 {
1899 float dist = (bones[i]->getWorldPosition() - p).getSquaredLength2D();
1900 if (dist <= closestDist)
1901 {
1902 closestDist = dist;
1903 b = bones[i];
1904 selectedBone = i;
1905 }
1906 }
1907 }
1908 }
1909 if (b)
1910 {
1911 b->color = Vector(1,0,0);
1912 }
1913 return b;
1914 }
1915 // else
1916 if (!bones.empty() && selectedBone >= 0 && selectedBone < bones.size())
1917 return bones[selectedBone];
1918
1919 return 0;
1920 }
1921
1922
updateSelectedBoneColor()1923 void SkeletalSprite::updateSelectedBoneColor()
1924 {
1925 for (int i = 0; i < bones.size(); i++)
1926 {
1927 bones[i]->color = Vector(1,1,1);
1928 }
1929 Bone *b = bones[selectedBone];
1930 if (b)
1931 b->color = Vector(0.5,0.5,1);
1932 }
1933
setSelectedBone(int b)1934 void SkeletalSprite::setSelectedBone(int b)
1935 {
1936 selectedBone = b;
1937 updateSelectedBoneColor();
1938 }
1939
selectPrevBone()1940 void SkeletalSprite::selectPrevBone()
1941 {
1942 selectedBone++;
1943 if (selectedBone >= bones.size())
1944 selectedBone = 0;
1945 updateSelectedBoneColor();
1946 }
1947
selectNextBone()1948 void SkeletalSprite::selectNextBone()
1949 {
1950 selectedBone--;
1951 if (selectedBone < 0)
1952 selectedBone = bones.size()-1;
1953 updateSelectedBoneColor();
1954 }
1955
1956
1957