From 4789ebb11407eb9402c385f3cc6fa242d91214c2 Mon Sep 17 00:00:00 2001 From: Bjørn Lindeijer Date: Mon, 24 Jul 2006 00:13:24 +0000 Subject: Implemented caching of spritesets, including a lot of cleanups to the new animation system. Action now refers to the Spriteset directly and AnimatedSprite refers to the current Action directly instead of using the std::map with a std::string constantly. Some methods and parameters are marked as const. The READ_PROP macro was replaced by static methods. Warnings are logged when unnamed actions are defined or when actions refer to undefined imagesets. Code is more tolerant towards missing actions. --- src/animation.cpp | 320 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 179 insertions(+), 141 deletions(-) (limited to 'src/animation.cpp') diff --git a/src/animation.cpp b/src/animation.cpp index 4dae04c4..313fd25c 100644 --- a/src/animation.cpp +++ b/src/animation.cpp @@ -23,21 +23,13 @@ #include "animation.h" -#include +#include #include "log.h" -#include "graphic/spriteset.h" - #include "resources/image.h" #include "resources/resourcemanager.h" - -#define READ_PROP(node, prop, name, target, cast) \ - prop = xmlGetProp(node, BAD_CAST name); \ - if (prop) { \ - target = cast((const char*)prop); \ - xmlFree(prop); \ - } +#include "resources/spriteset.h" Animation::Animation(): mTime(0) @@ -65,7 +57,7 @@ Animation::update(unsigned int time) } int -Animation::getCurrentPhase() +Animation::getCurrentPhase() const { if (mAnimationPhases.empty()) { @@ -78,7 +70,7 @@ Animation::getCurrentPhase() } void -Animation::addPhase (int image, unsigned int delay, int offsetX, int offsetY) +Animation::addPhase(int image, unsigned int delay, int offsetX, int offsetY) { //add new phase to animation list AnimationPhase newPhase; @@ -106,10 +98,9 @@ Animation::getLength() return length; } -Action::Action() - :mImageset("") +Action::Action(): + mSpriteset(NULL) { - //NOOP } Action::~Action() @@ -121,28 +112,30 @@ Action::~Action() mAnimations.clear(); } -Animation * -Action::getAnimation(std::string direction) +Animation* +Action::getAnimation(const std::string& direction) const { Animation *animation = NULL; - AnimationIterator i = mAnimations.find(direction); + Animations::const_iterator i = mAnimations.find(direction); + + // When the direction isn't defined, try the default if (i == mAnimations.end()) { - //when the direction isn't defined just use another one - animation = mAnimations["default"]; + i = mAnimations.find("default"); } - else + + if (i != mAnimations.end()) { - animation = mAnimations[direction]; + animation = i->second; } return animation; } void -Action::setAnimation(std::string direction, Animation *animation) +Action::setAnimation(const std::string& direction, Animation *animation) { - //set first direction as default direction + // Set first direction as default direction if (mAnimations.empty()) { mAnimations["default"] = animation; @@ -152,18 +145,18 @@ Action::setAnimation(std::string direction, Animation *animation) } -AnimatedSprite::AnimatedSprite(std::string animationFile, int variant): - mAction("stand"), mDirection("down"), mLastTime(0), mSpeed(1.0f) +AnimatedSprite::AnimatedSprite(const std::string& animationFile, int variant): + mAction(NULL), + mDirection("down"), + mLastTime(0), + mSpeed(1.0f) { - int variant_num = 0; - int variant_offset = 0; int size; ResourceManager *resman = ResourceManager::getInstance(); - char *data = (char*)resman->loadFile( - animationFile.c_str(), size); + char *data = (char*)resman->loadFile(animationFile.c_str(), size); if (!data) { - logger->error("Animation: Could not find " + animationFile + " !"); + logger->error("Animation: Could not find " + animationFile + "!"); } xmlDocPtr doc = xmlParseMemory(data, size); @@ -182,10 +175,9 @@ AnimatedSprite::AnimatedSprite(std::string animationFile, int variant): return; } - //get the variant - xmlChar *prop = NULL; - READ_PROP(node, prop, "variants", variant_num, atoi); - READ_PROP(node, prop, "variant_offset", variant_offset, atoi); + // Get the variant + int variant_num = getProperty(node, "variants", 0); + int variant_offset = getProperty(node, "variant_offset", 0); if (variant_num > 0 && variant < variant_num ) { @@ -200,16 +192,14 @@ AnimatedSprite::AnimatedSprite(std::string animationFile, int variant): { if (xmlStrEqual(node->name, BAD_CAST "imageset")) { - int width = 0, height = 0; - std::string name = "", imageSrc = ""; - xmlChar *prop = NULL; - READ_PROP(node, prop, "name", name, ); - READ_PROP(node, prop, "src", imageSrc, ); - READ_PROP(node, prop, "width", width, atoi); - READ_PROP(node, prop, "height", height, atoi); - - Spriteset *spriteset = resman->createSpriteset( - imageSrc, width, height); + int width = getProperty(node, "width", 0); + int height = getProperty(node, "height", 0); + std::string name = getProperty(node, "name", ""); + std::string imageSrc = getProperty(node, "src", ""); + + Spriteset *spriteset = + resman->getSpriteset(imageSrc, width, height); + if (!spriteset) { logger->error("Couldn't load spriteset!"); @@ -222,59 +212,73 @@ AnimatedSprite::AnimatedSprite(std::string animationFile, int variant): // get action else if (xmlStrEqual(node->name, BAD_CAST "action")) { - std::string name = "", imageset = ""; - xmlChar *prop = NULL; - READ_PROP(node, prop, "name", name, ); - READ_PROP(node, prop, "imageset", imageset, ); + std::string name = getProperty(node, "name", ""); + std::string imageset = getProperty(node, "imageset", ""); + + if (name.length() == 0) + { + logger->log("Warning: unnamed action in %s", + animationFile.c_str()); + } Action *action = new Action(); - mActions[name] = action; - action->setImageset(imageset); - //get animations - for ( xmlNodePtr animationNode = node->xmlChildrenNode; - animationNode != NULL; - animationNode = animationNode->next) + if (mSpritesets.find(imageset) != mSpritesets.end()) + { + action->setSpriteset(mSpritesets[imageset]); + mActions[name] = action; + } + else + { + logger->log("Warning: imageset \"%s\" not defined in %s", + imageset.c_str(), + animationFile.c_str()); + + // Discard action and skip loading animations + delete action; + continue; + } + + // get animations + for (xmlNodePtr animationNode = node->xmlChildrenNode; + animationNode != NULL; + animationNode = animationNode->next) { if (xmlStrEqual(animationNode->name, BAD_CAST "animation")) { - std::string direction = ""; - + std::string direction = + getProperty(animationNode, "direction", ""); Animation *animation = new Animation(); - READ_PROP(animationNode, prop, "direction", direction, ); - //get animation phases - for ( xmlNodePtr phaseNode = animationNode->xmlChildrenNode; - phaseNode != NULL; - phaseNode = phaseNode->next) + // Get animation phases + for (xmlNodePtr phaseNode = animationNode->xmlChildrenNode; + phaseNode != NULL; + phaseNode = phaseNode->next) { - int index = -1; - int start = 0; - int end = 0; - int delay = 0; - int offsetX = 0; - int offsetY = 0; + int delay = getProperty(phaseNode, "delay", 0); + if (xmlStrEqual(phaseNode->name, BAD_CAST "frame")) { - READ_PROP(phaseNode, prop, "index", index, atoi); - READ_PROP(phaseNode, prop, "delay", delay, atoi); - READ_PROP(phaseNode, prop, "offsetX", offsetX, atoi); - READ_PROP(phaseNode, prop, "offsetY", offsetY, atoi); + int index = getProperty(phaseNode, "index", -1); + int offsetX = getProperty(phaseNode, "offsetX", 0); + int offsetY = getProperty(phaseNode, "offsetY", 0); + offsetY = offsetY - mSpritesets[imageset]->getHeight() + 32; offsetX = offsetX - mSpritesets[imageset]->getWidth() / 2 + 16; - animation->addPhase(index + variant_offset, delay, offsetX, offsetY); + animation->addPhase(index + variant_offset, delay, + offsetX, offsetY); } - if (xmlStrEqual(phaseNode->name, BAD_CAST "sequence")) + else if (xmlStrEqual(phaseNode->name, BAD_CAST "sequence")) { - READ_PROP(phaseNode, prop, "start", start, atoi); - READ_PROP(phaseNode, prop, "end", end, atoi); - READ_PROP(phaseNode, prop, "delay", delay, atoi); - offsetY = 0 - mSpritesets[imageset]->getHeight() + 32; - offsetX = 0 - mSpritesets[imageset]->getWidth() / 2 + 16; + int start = getProperty(phaseNode, "start", 0); + int end = getProperty(phaseNode, "end", 0); + int offsetY = 0 - mSpritesets[imageset]->getHeight() + 32; + int offsetX = 0 - mSpritesets[imageset]->getWidth() / 2 + 16; while (end >= start) { - animation->addPhase(start + variant_offset, delay, offsetX, offsetY); + animation->addPhase(start + variant_offset, + delay, offsetX, offsetY); start++; } } @@ -285,8 +289,7 @@ AnimatedSprite::AnimatedSprite(std::string animationFile, int variant): } // if "" else if "" } // for node - //complete missing actions - substituteAction("stand", ""); + // Complete missing actions substituteAction("walk", "stand"); substituteAction("walk", "run"); substituteAction("attack", "stand"); @@ -301,11 +304,44 @@ AnimatedSprite::AnimatedSprite(std::string animationFile, int variant): substituteAction("hurt", "stand"); substituteAction("dead", "hurt"); + // Play the stand animation by default + play("stand"); + xmlFreeDoc(doc); } +int +AnimatedSprite::getProperty(xmlNodePtr node, const char* name, int def) +{ + xmlChar *prop = xmlGetProp(node, BAD_CAST name); + if (prop) { + int val = atoi((char*)prop); + xmlFree(prop); + return val; + } + else { + return def; + } +} + +std::string +AnimatedSprite::getProperty(xmlNodePtr node, const char* name, + const std::string& def) +{ + xmlChar *prop = xmlGetProp(node, BAD_CAST name); + if (prop) { + std::string val = (char*)prop; + xmlFree(prop); + return val; + } + else { + return def; + } +} + void -AnimatedSprite::substituteAction(std::string complete, std::string with) +AnimatedSprite::substituteAction(const std::string& complete, + const std::string& with) { if (mActions.find(complete) == mActions.end()) { @@ -315,104 +351,106 @@ AnimatedSprite::substituteAction(std::string complete, std::string with) AnimatedSprite::~AnimatedSprite() { - for (SpritesetIterator i = mSpritesets.begin(); i != mSpritesets.end(); i++) + for (SpritesetIterator i = mSpritesets.begin(); i != mSpritesets.end(); ++i) { - delete i->second; + i->second->decRef(); } mSpritesets.clear(); } void -AnimatedSprite::play(std::string action) +AnimatedSprite::play(const std::string& action) { - if (mAction != action) + Actions::iterator iAction; + iAction = mActions.find(action); + + if (iAction == mActions.end()) + { + logger->log("Warning: no action \"%s\" defined!", action.c_str()); + mAction = NULL; + return; + } + + if (mAction != iAction->second) { - mAction = action; + mAction = iAction->second; + mLastTime = 0; } - mLastTime = 0; + mSpeed = 1.0f; } void -AnimatedSprite::play(std::string action, int time) +AnimatedSprite::play(const std::string& action, int time) { - if (mAction != action) + play(action); + + if (mAction != NULL) { - mAction = action; + Animation *animation = mAction->getAnimation(mDirection); + int animationLength = animation->getLength(); + mSpeed = (float) animationLength / time; } - mLastTime = 0; - int animationLength = 0; - Action *nextAction = mActions[mAction]; - Animation *animation = nextAction->getAnimation(mDirection); - animationLength = animation->getLength(); - mSpeed = (float)animationLength / time; } void AnimatedSprite::update(int time) { - // avoid freaking out at first frame or when tick_time overflows + // Avoid freaking out at first frame or when tick_time overflows if (time < mLastTime || mLastTime == 0) mLastTime = time; - // if not enough time have passed yet, do nothing + // If not enough time have passed yet, do nothing if (time > mLastTime) { - Action *action = mActions[mAction]; - Animation *animation = action->getAnimation(mDirection); - animation->update((unsigned int)((time - mLastTime) * mSpeed)); - mLastTime = time; + if (mAction != NULL) + { + Animation *animation = mAction->getAnimation(mDirection); + animation->update((unsigned int)((time - mLastTime) * mSpeed)); + mLastTime = time; + } } } bool -AnimatedSprite::draw(Graphics * graphics, Sint32 posX, Sint32 posY) +AnimatedSprite::draw(Graphics* graphics, Sint32 posX, Sint32 posY) const { - Sint32 offsetX, offsetY; - Action *action = mActions[mAction]; - Spriteset *spriteset = mSpritesets[action->getImageset()]; - Animation *animation = action->getAnimation(mDirection); - - if (animation->getCurrentPhase() >= 0) - { - Image *image = spriteset->get(animation->getCurrentPhase()); - offsetX = animation->getOffsetX(); - offsetY = animation->getOffsetY(); - return graphics->drawImage(image, posX + offsetX, posY + offsetY); - } - else + if (mAction != NULL) { - return false; + Animation *animation = mAction->getAnimation(mDirection); + + if (animation->getCurrentPhase() >= 0) + { + Spriteset *spriteset = mAction->getSpriteset(); + Image *image = spriteset->get(animation->getCurrentPhase()); + Sint32 offsetX = animation->getOffsetX(); + Sint32 offsetY = animation->getOffsetY(); + return graphics->drawImage(image, posX + offsetX, posY + offsetY); + } } + + return false; } -Image * -AnimatedSprite::getCurrentFrame() +int +AnimatedSprite::getWidth() const { - Action *action = mActions[mAction]; - Spriteset *spriteset = mSpritesets[action->getImageset()]; - Animation *animation = action->getAnimation(mDirection); - if (animation->getCurrentPhase() >= 0) + if (mAction != NULL) { - return spriteset->get(animation->getCurrentPhase()); + Spriteset *spriteset = mAction->getSpriteset(); + return spriteset->getWidth(); } - else - { - return NULL; - } -} -int -AnimatedSprite::getWidth() -{ - Action *action = mActions[mAction]; - Spriteset *spriteset = mSpritesets[action->getImageset()]; - return spriteset->getWidth(); + return 0; } int -AnimatedSprite::getHeight() +AnimatedSprite::getHeight() const { - Action *action = mActions[mAction]; - Spriteset *spriteset = mSpritesets[action->getImageset()]; - return spriteset->getHeight(); + if (mAction != NULL) + { + Spriteset *spriteset = mAction->getSpriteset(); + return spriteset->getHeight(); + } + + return 0; } -- cgit v1.2.3-70-g09d2