diff options
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | NEWS | 8 | ||||
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/animation.cpp | 320 | ||||
-rw-r--r-- | src/animation.h | 100 | ||||
-rw-r--r-- | src/being.cpp | 10 | ||||
-rw-r--r-- | src/being.h | 2 | ||||
-rw-r--r-- | src/engine.cpp | 25 | ||||
-rw-r--r-- | src/floor_item.cpp | 3 | ||||
-rw-r--r-- | src/gui/equipmentwindow.cpp | 7 | ||||
-rw-r--r-- | src/gui/itemcontainer.cpp | 7 | ||||
-rw-r--r-- | src/gui/playerbox.cpp | 2 | ||||
-rw-r--r-- | src/log.cpp | 3 | ||||
-rw-r--r-- | src/main.cpp | 21 | ||||
-rw-r--r-- | src/resources/mapreader.cpp | 3 | ||||
-rw-r--r-- | src/resources/resourcemanager.cpp | 74 | ||||
-rw-r--r-- | src/resources/resourcemanager.h | 8 | ||||
-rw-r--r-- | src/resources/spriteset.cpp (renamed from src/graphic/spriteset.cpp) | 9 | ||||
-rw-r--r-- | src/resources/spriteset.h (renamed from src/graphic/spriteset.h) | 11 | ||||
-rw-r--r-- | src/tileset.h | 4 |
20 files changed, 400 insertions, 243 deletions
@@ -1,3 +1,23 @@ +2006-07-24 Bjørn Lindeijer <bjorn@lindeijer.nl> + + * src/floor_item.cpp, src/animation.h, src/being.cpp, src/main.cpp, + src/gui/equipmentwindow.cpp, src/gui/playerbox.cpp, + src/gui/itemcontainer.cpp, src/engine.cpp, src/tileset.h, + src/animation.cpp, src/Makefile.am, src/resources/mapreader.cpp, + src/resources/resourcemanager.cpp, src/resources/spriteset.cpp, + src/resources/resourcemanager.h, src/resources/spriteset.h, + src/being.h, src/graphic/spriteset.cpp, src/graphic/spriteset.h, + data/graphics/sprites/npc.xml, data/graphics/sprites/weapons.xml: + 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. + * NEWS: Rearranged some items. + 2006-07-21 Eugenio Favalli <elvenprogrammer@gmail.com> * src/animation.cpp, src/animation.h: Removed unused code, fixed a @@ -1,16 +1,16 @@ 0.0.20 (23 July 2006) -- Reduced size of textures to stay within the OpenGL limits - Added new hairstyle, and some fixes to the old ones -- Fixed connection not being shut down completely in case of an error -- Fixed min size of a window when resizing - Added slider to set FPS limit - Added visible equipments - Added new maps and monsters - Added female characters -- Some fixes to monsters and player graphics - Implemented a new animation system - Updated the updating system +- Reduced size of textures to stay within the limits of some OpenGL drivers +- Fixed connection not being shut down completely in case of an error +- Fixed min size of a window when resizing - Fixed some maps issues +- Some fixes to monsters and player graphics - Minor bug fixes and lots of code cleanups 0.0.19 (6 March 2006) diff --git a/src/Makefile.am b/src/Makefile.am index c6db2ec6..1bb1d538 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,5 @@ bin_PROGRAMS = tmw -tmw_SOURCES = graphic/spriteset.cpp \ - graphic/imagerect.h \ - graphic/spriteset.h \ +tmw_SOURCES = graphic/imagerect.h \ gui/browserbox.cpp \ gui/browserbox.h \ gui/buddywindow.cpp \ @@ -177,6 +175,8 @@ tmw_SOURCES = graphic/spriteset.cpp \ resources/sdlimageloader.cpp \ resources/soundeffect.h \ resources/soundeffect.cpp \ + resources/spriteset.h \ + resources/spriteset.cpp \ resources/buddylist.h \ resources/buddylist.cpp \ utils/dtor.h \ 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 <libxml/tree.h> +#include <cassert> #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 "<imageset>" else if "<action>" } // 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; } diff --git a/src/animation.h b/src/animation.h index 4f7d57a9..c5adb873 100644 --- a/src/animation.h +++ b/src/animation.h @@ -28,11 +28,16 @@ #include <map> #include <string> +#include <libxml/tree.h> + #include "graphics.h" class Image; class Spriteset; +/** + * A single frame in an animation, with a delay and an offset. + */ struct AnimationPhase { int image; @@ -41,19 +46,26 @@ struct AnimationPhase int offsetY; }; +/** + * An animation consists of several frames, each with their own delay and + * offset. + */ class Animation { public: + /** + * Constructor. + */ Animation(); void addPhase(int image, unsigned int delay, int offsetX, int offsetY); void update(unsigned int time); - int getCurrentPhase(); + int getCurrentPhase() const; - int getOffsetX() { return (*iCurrentPhase).offsetX; }; - int getOffsetY() { return (*iCurrentPhase).offsetY; }; + int getOffsetX() const { return (*iCurrentPhase).offsetX; }; + int getOffsetY() const { return (*iCurrentPhase).offsetY; }; int getLength(); @@ -63,23 +75,42 @@ class Animation unsigned int mTime; }; +/** + * An action consists of several animations, one for each direction. + */ class Action { public: + /** + * Constructor. + */ Action(); + /** + * Destructor. + */ ~Action(); - void setImageset(std::string imageset) { mImageset = imageset; } + /** + * Sets the spriteset used by this action. + */ + void + setSpriteset(Spriteset *spriteset) { mSpriteset = spriteset; } - std::string getImageset() { return mImageset; } + /** + * Returns the spriteset used by this action. + */ + Spriteset* + getSpriteset() const { return mSpriteset; } - void setAnimation(std::string direction, Animation *animation); + void + setAnimation(const std::string& direction, Animation *animation); - Animation *getAnimation(std::string direction); // { return mAnimations[direction]; } + Animation* + getAnimation(const std::string& direction) const; protected: - std::string mImageset; + Spriteset *mSpriteset; typedef std::map<std::string, Animation*> Animations; typedef Animations::iterator AnimationIterator; Animations mAnimations; @@ -94,7 +125,7 @@ class AnimatedSprite /** * Constructor. */ - AnimatedSprite(std::string animationFile, int variant); + AnimatedSprite(const std::string& animationFile, int variant); /** * Destructor. @@ -104,12 +135,14 @@ class AnimatedSprite /** * Sets a new action using the current direction. */ - void play(std::string action); + void + play(const std::string& action); /** * Plays an action in a specified time. */ - void play(std::string action, int time); + void + play(const std::string& action, int time); /** * Inform the animation of the passed time so that it can output the @@ -119,45 +152,66 @@ class AnimatedSprite /** * Draw the current animation phase at the coordinates given in screen - * pixels - */ - bool draw(Graphics * graphics, Sint32 posX, Sint32 posY); - - /** - * Draw the current animation phase. + * pixels. */ - Image *getCurrentFrame(); + bool + draw(Graphics* graphics, Sint32 posX, Sint32 posY) const; /** * gets the width in pixels of the current animation phase. */ - int getWidth(); + int + getWidth() const; /** * gets the height in pixels of the current animation phase. */ - int getHeight(); + int + getHeight() const; /** * Sets the direction. */ - void setDirection(std::string direction) { mDirection = direction; } + void + setDirection(const std::string& direction) + { + mDirection = direction; + } protected: /** * When there are no animations defined for the action "complete", its * animations become a copy of those of the action "with". */ - void substituteAction(std::string complete, std::string with); + void + substituteAction(const std::string& complete, + const std::string& with); typedef std::map<std::string, Spriteset*> Spritesets; typedef Spritesets::iterator SpritesetIterator; Spritesets mSpritesets; typedef std::map<std::string, Action*> Actions; Actions mActions; - std::string mAction, mDirection; + Action *mAction; + std::string mDirection; int mLastTime; float mSpeed; + + private: + /** + * Gets an integer property from an xmlNodePtr. + * + * TODO: Same function is present in MapReader. Should probably be + * TODO: shared in a static utility class. + */ + static int + getProperty(xmlNodePtr node, const char* name, int def); + + /** + * Gets a string property from an xmlNodePtr. + */ + static std::string + getProperty(xmlNodePtr node, const char* name, const std::string& def); }; #endif diff --git a/src/being.cpp b/src/being.cpp index d34ea43e..437023d4 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -28,7 +28,7 @@ #include "log.h" #include "map.h" -#include "graphic/spriteset.h" +#include "resources/spriteset.h" #include "gui/gui.h" @@ -65,9 +65,12 @@ Being::Being(Uint32 id, Uint16 job, Map *map): Being::~Being() { - for (int i =0; i < VECTOREND_SPRITE; i++) + for (int i = 0; i < VECTOREND_SPRITE; i++) { - delete mSprites[i]; + if (mSprites[i] != NULL) + { + delete mSprites[i]; + } } clearPath(); @@ -266,7 +269,6 @@ Being::setDirection(Uint8 direction) { if (mSprites[i] != NULL) mSprites[i]->setDirection(dir); } - } void diff --git a/src/being.h b/src/being.h index 6fac98b7..6d2bada6 100644 --- a/src/being.h +++ b/src/being.h @@ -371,7 +371,7 @@ class Being : public Sprite bool mShowSpeech, mShowDamage; Sint32 mPx, mPy; /**< Pixel coordinates */ - std::vector<AnimatedSprite *>mSprites; + std::vector<AnimatedSprite*> mSprites; }; #endif diff --git a/src/engine.cpp b/src/engine.cpp index c5cf5c1a..b1fb9b4b 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -38,8 +38,6 @@ #include "map.h" #include "sound.h" -#include "graphic/spriteset.h" - #include "gui/gui.h" #include "gui/minimap.h" @@ -49,6 +47,7 @@ #include "resources/itemmanager.h" #include "resources/mapreader.h" #include "resources/resourcemanager.h" +#include "resources/spriteset.h" #include "utils/dtor.h" #include "utils/tostring.h" @@ -75,12 +74,12 @@ Engine::Engine(Network *network): // Load the sprite sets ResourceManager *resman = ResourceManager::getInstance(); - npcset = resman->createSpriteset("graphics/sprites/npcs.png", 50, 80); - emotionset = resman->createSpriteset("graphics/sprites/emotions.png", + npcset = resman->getSpriteset("graphics/sprites/npcs.png", 50, 80); + emotionset = resman->getSpriteset("graphics/sprites/emotions.png", 30, 32); for (int i = 0; i < 2; i++) { - Spriteset *tmp = ResourceManager::getInstance()->createSpriteset( + Spriteset *tmp = ResourceManager::getInstance()->getSpriteset( "graphics/sprites/weapon" + toString(i) + ".png", 64, 64); if (!tmp) { logger->error("Unable to load weaponset"); @@ -88,11 +87,10 @@ Engine::Engine(Network *network): weaponset.push_back(tmp); } } - itemset = resman->createSpriteset("graphics/sprites/items.png", 32, 32); + itemset = resman->getSpriteset("graphics/sprites/items.png", 32, 32); if (!npcset) logger->error("Unable to load NPC spriteset!"); if (!emotionset) logger->error("Unable to load emotions spriteset!"); - //if (!weaponset) logger->error("Unable to load weapon spriteset!"); if (!itemset) logger->error("Unable to load item spriteset!"); // Initialize item manager @@ -102,11 +100,16 @@ Engine::Engine(Network *network): Engine::~Engine() { // Delete sprite sets - delete npcset; - delete emotionset; - for_each(weaponset.begin(), weaponset.end(), make_dtor(weaponset)); + npcset->decRef(); + emotionset->decRef(); + itemset->decRef(); + + std::vector<Spriteset *>::iterator iter; + for (iter = weaponset.begin(); iter != weaponset.end(); ++iter) + { + (*iter)->decRef(); + } weaponset.clear(); - delete itemset; delete itemDb; diff --git a/src/floor_item.cpp b/src/floor_item.cpp index 4573d646..1581b201 100644 --- a/src/floor_item.cpp +++ b/src/floor_item.cpp @@ -25,10 +25,9 @@ #include "map.h" -#include "graphic/spriteset.h" - #include "resources/itemmanager.h" #include "resources/iteminfo.h" +#include "resources/spriteset.h" extern Spriteset *itemset; diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index fd979beb..bef39dff 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -28,10 +28,9 @@ #include "../item.h" #include "../log.h" -#include "../graphic/spriteset.h" - #include "../resources/iteminfo.h" #include "../resources/resourcemanager.h" +#include "../resources/spriteset.h" #include "../utils/tostring.h" @@ -42,14 +41,14 @@ EquipmentWindow::EquipmentWindow(Equipment *equipment): setDefaultSize(5, 230, 200, 120); loadWindowState(); - mItemset = ResourceManager::getInstance()->createSpriteset( + mItemset = ResourceManager::getInstance()->getSpriteset( "graphics/sprites/items.png", 32, 32); if (!mItemset) logger->error("Unable to load items.png"); } EquipmentWindow::~EquipmentWindow() { - delete mItemset; + mItemset->decRef(); } void EquipmentWindow::draw(gcn::Graphics *graphics) diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp index 9b8dc09b..edcf9764 100644 --- a/src/gui/itemcontainer.cpp +++ b/src/gui/itemcontainer.cpp @@ -30,11 +30,10 @@ #include "../item.h" #include "../log.h" -#include "../graphic/spriteset.h" - #include "../resources/image.h" #include "../resources/iteminfo.h" #include "../resources/resourcemanager.h" +#include "../resources/spriteset.h" #include "../utils/tostring.h" @@ -42,7 +41,7 @@ ItemContainer::ItemContainer(Inventory *inventory): mInventory(inventory) { ResourceManager *resman = ResourceManager::getInstance(); - mItemset = resman->createSpriteset("graphics/sprites/items.png", 32, 32); + mItemset = resman->getSpriteset("graphics/sprites/items.png", 32, 32); if (!mItemset) logger->error("Unable to load items.png"); mSelImg = resman->getImage("graphics/gui/selection.png"); @@ -56,7 +55,7 @@ ItemContainer::ItemContainer(Inventory *inventory): ItemContainer::~ItemContainer() { - delete mItemset; + mItemset->decRef(); mSelImg->decRef(); } diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp index d5c70ffe..f0ed9b71 100644 --- a/src/gui/playerbox.cpp +++ b/src/gui/playerbox.cpp @@ -27,10 +27,10 @@ #include "../graphics.h" #include "../graphic/imagerect.h" -#include "../graphic/spriteset.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" +#include "../resources/spriteset.h" #include "../utils/dtor.h" diff --git a/src/log.cpp b/src/log.cpp index d40927c5..3d101d29 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -53,7 +53,8 @@ void Logger::setLogFile(const std::string &logFilename) void Logger::log(const char *log_text, ...) { - if (!mLogFile.is_open()) { + if (!mLogFile.is_open()) + { return; } diff --git a/src/main.cpp b/src/main.cpp index 5ecb4f35..28debf47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,8 +56,6 @@ #endif #include "sound.h" -#include "graphic/spriteset.h" - #include "gui/char_server.h" #include "gui/char_select.h" #include "gui/connection.h" @@ -76,6 +74,7 @@ #include "resources/image.h" #include "resources/resourcemanager.h" +#include "resources/spriteset.h" #include "utils/dtor.h" #include "utils/tostring.h" @@ -244,17 +243,17 @@ void init_engine() // Initialize for drawing graphics->_beginDraw(); - playerset[0] = resman->createSpriteset( + playerset[0] = resman->getSpriteset( "graphics/sprites/player_male_base.png", 64, 64); if (!playerset[0]) logger->error("Couldn't load male player spriteset!"); - playerset[1] = resman->createSpriteset( + playerset[1] = resman->getSpriteset( "graphics/sprites/player_female_base.png", 64, 64); if (!playerset[1]) logger->error("Couldn't load female player spriteset!"); for (int i=0; i < NR_HAIR_STYLES; i++) { - Spriteset *tmp = ResourceManager::getInstance()->createSpriteset( + Spriteset *tmp = ResourceManager::getInstance()->getSpriteset( "graphics/sprites/hairstyle" + toString(i + 1) + ".png", 40, 40); if (!tmp) { @@ -288,10 +287,16 @@ void exit_engine() config.write(); delete gui; delete graphics; - for_each(hairset.begin(), hairset.end(), make_dtor(hairset)); + + std::vector<Spriteset *>::iterator iter; + for (iter = hairset.begin(); iter != hairset.end(); ++iter) + { + (*iter)->decRef(); + } hairset.clear(); - delete playerset[0]; - delete playerset[1]; + + playerset[0]->decRef(); + playerset[1]->decRef(); // Shutdown libxml xmlCleanupParser(); diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index 48f23aea..af79480a 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -28,14 +28,13 @@ #include "resourcemanager.h" #include "image.h" +#include "spriteset.h" #include "../base64.h" #include "../log.h" #include "../map.h" #include "../tileset.h" -#include "../graphic/spriteset.h" - const unsigned int DEFAULT_TILE_WIDTH = 32; const unsigned int DEFAULT_TILE_HEIGHT = 32; diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index a6dc692b..26899d77 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -30,11 +30,10 @@ #include "image.h" #include "music.h" #include "soundeffect.h" +#include "spriteset.h" #include "../log.h" -#include "../graphic/spriteset.h" - ResourceManager *ResourceManager::instance = NULL; @@ -44,25 +43,39 @@ ResourceManager::ResourceManager() ResourceManager::~ResourceManager() { - // Create our resource iterator. + // Release any remaining spritesets first because they depend on images ResourceIterator iter = mResources.begin(); + while (iter != mResources.end()) + { + if (dynamic_cast<Spriteset*>(iter->second) != NULL) + { + cleanUp(iter->second); + ResourceIterator toErase = iter; + ++iter; + mResources.erase(toErase); + } + else + { + ++iter; + } + } - // Iterate through and release references until objects are deleted. + // Release remaining resources, logging the number of dangling references. while (!mResources.empty()) { - Resource *res = mResources.begin()->second; - std::string id = res->getIdPath(); - int references = 0; - - references += res->mRefCount; - release(res->mIdPath); - delete res; - - logger->log("ResourceManager::~ResourceManager() cleaned up %d " - "references to %s", references, id.c_str()); + cleanUp(mResources.begin()->second); + mResources.erase(mResources.begin()); } } +void +ResourceManager::cleanUp(Resource *res) +{ + logger->log("ResourceManager::~ResourceManager() cleaning up %d " + "references to %s", res->mRefCount, res->mIdPath.c_str()); + delete res; +} + bool ResourceManager::setWriteDir(const std::string &path) { @@ -151,42 +164,55 @@ ResourceManager::get(const E_RESOURCE_TYPE &type, const std::string &idPath) mResources[idPath] = resource; } - // Return NULL if the object could not be created. + // Returns NULL if the object could not be created. return resource; } Image* ResourceManager::getImage(const std::string &idPath) { - return (Image*)get(IMAGE, idPath); + return dynamic_cast<Image*>(get(IMAGE, idPath)); } Music* ResourceManager::getMusic(const std::string &idPath) { - return (Music*)get(MUSIC, idPath); + return dynamic_cast<Music*>(get(MUSIC, idPath)); } SoundEffect* ResourceManager::getSoundEffect(const std::string &idPath) { - return (SoundEffect*)get(SOUND_EFFECT, idPath); + return dynamic_cast<SoundEffect*>(get(SOUND_EFFECT, idPath)); } -Spriteset* ResourceManager::createSpriteset(const std::string &imagePath, - int w, int h) +Spriteset* +ResourceManager::getSpriteset(const std::string &imagePath, int w, int h) { - Image *img; + std::stringstream ss; + ss << imagePath << "[" << w << "x" << h << "]"; + const std::string idPath = ss.str(); + + ResourceIterator resIter = mResources.find(idPath); + + if (resIter != mResources.end()) { + resIter->second->incRef(); + return dynamic_cast<Spriteset*>(resIter->second); + } + + Image *img = getImage(imagePath); - if (!(img = getImage(imagePath))) { + if (!img) { return NULL; } - Spriteset *result = new Spriteset(img, w, h); + Spriteset *spriteset = new Spriteset(idPath, img, w, h); + spriteset->incRef(); + mResources[idPath] = spriteset; img->decRef(); - return result; + return spriteset; } void diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h index 8d60ae8c..f254a8b4 100644 --- a/src/resources/resourcemanager.h +++ b/src/resources/resourcemanager.h @@ -136,7 +136,7 @@ class ResourceManager * Creates a spriteset based on the image referenced by the given * path and the supplied sprite sizes */ - Spriteset* createSpriteset(const std::string &imagePath, int w, int h); + Spriteset* getSpriteset(const std::string &imagePath, int w, int h); /** * Releases a resource, removing it from the set of loaded resources. @@ -177,6 +177,12 @@ class ResourceManager deleteInstance(); private: + /** + * Deletes the resource after logging a cleanup message. + */ + static void + cleanUp(Resource *resource); + static ResourceManager *instance; typedef std::map<std::string, Resource*> Resources; typedef Resources::iterator ResourceIterator; diff --git a/src/graphic/spriteset.cpp b/src/resources/spriteset.cpp index 3b190f31..9b09f1e5 100644 --- a/src/graphic/spriteset.cpp +++ b/src/resources/spriteset.cpp @@ -25,11 +25,14 @@ #include "../log.h" -#include "../resources/image.h" +#include "image.h" #include "../utils/dtor.h" -Spriteset::Spriteset(Image *img, int width, int height) +Spriteset::Spriteset(const std::string& idPath, + Image *img, + int width, int height): + Resource(idPath) { for (int y = 0; y + height <= img->getHeight(); y += height) { @@ -47,7 +50,7 @@ Spriteset::~Spriteset() for_each(mSpriteset.begin(), mSpriteset.end(), make_dtor(mSpriteset)); } -Image * +Image* Spriteset::get(size_type i) { if (i > mSpriteset.size()) diff --git a/src/graphic/spriteset.h b/src/resources/spriteset.h index 94ccb742..c51e6a75 100644 --- a/src/graphic/spriteset.h +++ b/src/resources/spriteset.h @@ -26,18 +26,21 @@ #include <vector> +#include "resource.h" + class Image; /** * Stores a complete set of sprites. */ -class Spriteset { +class Spriteset : public Resource +{ public: /* * Cuts the passed image in a grid of sub images. */ - Spriteset(Image *img, int w, int h); + Spriteset(const std::string& idPath, Image *img, int w, int h); /** * Destructor. @@ -49,14 +52,14 @@ class Spriteset { int getHeight() { return mHeight; }; typedef std::vector<Image*>::size_type size_type; - Image * get(size_type i); + Image* get(size_type i); size_type size() { return mSpriteset.size(); } private: // Vector storing the whole spriteset. std::vector<Image*> mSpriteset; - //height and width of the images in the spriteset + // Height and width of the images in the spriteset int mHeight; int mWidth; }; diff --git a/src/tileset.h b/src/tileset.h index 5fa4ade1..27bc28c3 100644 --- a/src/tileset.h +++ b/src/tileset.h @@ -24,7 +24,7 @@ #ifndef _TMW_TILESET_H_ #define _TMW_TILESET_H_ -#include "graphic/spriteset.h" +#include "resources/spriteset.h" /** * A tileset, which is basically just a spriteset but it stores a firstgid. @@ -36,7 +36,7 @@ class Tileset : public Spriteset * Constructor. */ Tileset(Image *img, int w, int h, int firstGid): - Spriteset(img, w, h), + Spriteset("", img, w, h), mFirstGid(firstGid) { } |