diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/animationparticle.cpp | 51 | ||||
-rw-r--r-- | src/animationparticle.h | 49 | ||||
-rw-r--r-- | src/being.cpp | 98 | ||||
-rw-r--r-- | src/being.h | 10 | ||||
-rw-r--r-- | src/engine.cpp | 7 | ||||
-rw-r--r-- | src/game.cpp | 5 | ||||
-rw-r--r-- | src/graphics.cpp | 11 | ||||
-rw-r--r-- | src/graphics.h | 8 | ||||
-rw-r--r-- | src/gui/debugwindow.cpp | 10 | ||||
-rw-r--r-- | src/gui/debugwindow.h | 1 | ||||
-rw-r--r-- | src/imageparticle.cpp | 67 | ||||
-rw-r--r-- | src/imageparticle.h | 46 | ||||
-rw-r--r-- | src/map.cpp | 23 | ||||
-rw-r--r-- | src/map.h | 25 | ||||
-rw-r--r-- | src/net/beinghandler.cpp | 17 | ||||
-rw-r--r-- | src/particle.cpp | 366 | ||||
-rw-r--r-- | src/particle.h | 278 | ||||
-rw-r--r-- | src/particleemitter.cpp | 313 | ||||
-rw-r--r-- | src/particleemitter.h | 108 | ||||
-rw-r--r-- | src/resources/mapreader.cpp | 24 | ||||
-rw-r--r-- | src/simpleanimation.cpp | 87 | ||||
-rw-r--r-- | src/simpleanimation.h | 27 | ||||
-rw-r--r-- | src/utils/fastsqrt.h | 23 | ||||
-rw-r--r-- | src/utils/minmax.h | 47 | ||||
-rw-r--r-- | src/utils/wingettimeofday.h | 226 | ||||
-rw-r--r-- | src/utils/xml.cpp | 23 | ||||
-rw-r--r-- | src/utils/xml.h | 11 |
29 files changed, 1812 insertions, 171 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed5623fc..b88921c6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -260,6 +260,8 @@ SET(SRCS utils/xml.h animatedsprite.cpp animatedsprite.h + animationparticle.cpp + animationparticle.h being.cpp being.h beingmanager.cpp @@ -280,6 +282,8 @@ SET(SRCS graphics.cpp graphics.h guichanfwd.h + imageparticle.cpp + imageparticle.h inventory.cpp inventory.h item.cpp @@ -302,6 +306,10 @@ SET(SRCS npc.h openglgraphics.cpp openglgraphics.h + particle.cpp + particle.h + particleemitter.cpp + particleemitter.h player.cpp player.h properties.h @@ -311,6 +319,8 @@ SET(SRCS sound.cpp sound.h sprite.h + textparticle.cpp + textparticle.h tileset.h ) diff --git a/src/Makefile.am b/src/Makefile.am index d491ca4b..088c4b18 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -209,6 +209,8 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \ utils/xml.h \ animatedsprite.cpp \ animatedsprite.h \ + animationparticle.cpp \ + animationparticle.h \ being.cpp \ being.h \ beingmanager.cpp \ @@ -229,6 +231,8 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \ graphics.cpp \ graphics.h \ guichanfwd.h \ + imageparticle.cpp \ + imageparticle.h \ inventory.cpp \ inventory.h \ item.cpp \ @@ -251,15 +255,21 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \ npc.h \ openglgraphics.cpp\ openglgraphics.h \ + particle.cpp \ + particle.h \ + particleemitter.cpp \ + particleemitter.h \ player.cpp \ player.h \ properties.h \ serverinfo.h \ simpleanimation.cpp \ - simpleanimation.h \ + simpleanimation.h \ sound.cpp \ sound.h \ sprite.h \ + textparticle.cpp \ + textparticle.h \ tileset.h # set the include path found by configure diff --git a/src/animationparticle.cpp b/src/animationparticle.cpp new file mode 100644 index 00000000..30c33da7 --- /dev/null +++ b/src/animationparticle.cpp @@ -0,0 +1,51 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "animationparticle.h" + +#include "graphics.h" +#include "simpleanimation.h" + +AnimationParticle::AnimationParticle(Map *map, Animation *animation): + ImageParticle(map, 0), + mAnimation(new SimpleAnimation(animation)) +{ +} + +AnimationParticle::AnimationParticle(Map *map, xmlNodePtr animationNode): + ImageParticle(map, 0), + mAnimation(new SimpleAnimation(animationNode)) +{ +} + +AnimationParticle::~AnimationParticle() +{ + delete mAnimation; +} + +bool AnimationParticle::update() +{ + mAnimation->update(10); // particle engine is updated every 10ms + mImage = mAnimation->getCurrentImage(); + + return Particle::update(); +} diff --git a/src/animationparticle.h b/src/animationparticle.h new file mode 100644 index 00000000..054b1b73 --- /dev/null +++ b/src/animationparticle.h @@ -0,0 +1,49 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ANIMATION_PARTICLE +#define _ANIMATION_PARTICLE + +#include <libxml/tree.h> + +#include "imageparticle.h" + +class Animation; +class Map; +class SimpleAnimation; + +class AnimationParticle : public ImageParticle +{ + public: + AnimationParticle(Map *map, Animation *animation); + + AnimationParticle(Map *map, xmlNodePtr animationNode); + + ~AnimationParticle(); + + virtual bool update(); + + private: + SimpleAnimation *mAnimation; /**< Used animation for this particle */ +}; + +#endif diff --git a/src/being.cpp b/src/being.cpp index 930c2d24..db7751bf 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -30,12 +30,16 @@ #include "graphics.h" #include "log.h" #include "map.h" +#include "particle.h" #include "resources/resourcemanager.h" #include "resources/imageset.h" #include "gui/gui.h" +#include "resources/resourcemanager.h" +#include "resources/imageset.h" + #include "utils/dtor.h" #include "utils/tostring.h" @@ -58,7 +62,6 @@ Being::Being(Uint32 id, Uint16 job, Map *map): mHairStyle(0), mHairColor(0), mSex(2), mSpeechTime(0), - mDamageTime(0), mPx(0), mPy(0), mSprites(VECTOREND_SPRITE, NULL), mEquipmentSpriteIDs(VECTOREND_SPRITE, 0) @@ -82,6 +85,13 @@ Being::~Being() clearPath(); setMap(NULL); + for ( std::list<Particle *>::iterator i = mChildParticleEffects.begin(); + i != mChildParticleEffects.end(); + i++) + { + (*i)->kill(); + } + instances--; if (instances == 0) @@ -154,8 +164,34 @@ Being::setSpeech(const std::string &text, Uint32 time) void Being::takeDamage(int amount) { - mDamage = amount ? toString(amount) : "miss"; - mDamageTime = 300; + gcn::Font* font; + std::string damage = amount ? toString(amount) : "miss"; + + // Selecting the right color + if (damage == "miss") + { + font = hitYellowFont; + } + else + { + // hit particle effect + controlParticle(particleEngine->addEffect("graphics/particles/hit.particle.xml", 0, 0)); + + if (getType() == MONSTER) + { + font = hitBlueFont; + } + else + { + font = hitRedFont; + } + } + + // show damage number + particleEngine->addTextSplashEffect(damage, + font, + gcn::Color(255, 255, 255), + mPx + 16, mPy + 16); } void @@ -182,6 +218,19 @@ Being::setMap(Map *map) { mSpriteIterator = mMap->addSprite(this); } + + //clear particle effect list because child particles became invalid + mChildParticleEffects.clear(); +} + +void +Being::controlParticle(Particle *particle) +{ + if (particle) + { + particle->disableAutoDelete(); //the effect may not die without the beings permission or we segvault + mChildParticleEffects.push_back(particle); + } } void @@ -321,10 +370,6 @@ Being::logic() if (mSpeechTime > 0) mSpeechTime--; - // Reduce the time that damage is still displayed - if (mDamageTime > 0) - mDamageTime--; - // Update pixel coordinates mPx = mX * 32 + getXOffset(); mPy = mY * 32 + getYOffset(); @@ -345,6 +390,14 @@ Being::logic() mSprites[i]->update(tick_time * 10); } } + + //Update particle effects + for ( std::list<Particle *>::iterator i = mChildParticleEffects.begin(); + i != mChildParticleEffects.end(); + i++) + { + (*i)->setPosition((float)mPx + 16.0f, (float)mPy + 32.0f); + } } void @@ -387,37 +440,6 @@ Being::drawSpeech(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) graphics->setColor(gcn::Color(255, 255, 255)); graphics->drawText(mSpeech, px + 18, py - 60, gcn::Graphics::CENTER); } - - // Draw damage above this being - if (mDamageTime > 0 && mDamageTime < 275) - { - // Selecting the right color - if (mDamage == "miss") - { - graphics->setFont(hitYellowFont); - } - else if (getType() == MONSTER) - { - graphics->setFont(hitBlueFont); - } - else - { - graphics->setFont(hitRedFont); - } - - int textY = (getType() == MONSTER) ? 32 : 70; - int ft = 150 - mDamageTime; - float a = (ft > 0) ? 1.0 - ft / 150.0 : 1.0; - - graphics->setColor(gcn::Color(255, 255, 255, (int)(255 * a))); - graphics->drawText(mDamage, - px + 16, - py - textY - (300 - mDamageTime) / 10, - gcn::Graphics::CENTER); - - // Reset alpha value - graphics->setColor(gcn::Color(255, 255, 255)); - } } Being::Type diff --git a/src/being.h b/src/being.h index 08b0e710..5dbd845b 100644 --- a/src/being.h +++ b/src/being.h @@ -42,6 +42,7 @@ class Item; class Map; class Graphics; class ImageSet; +class Particle; /** * A position along a being's path. @@ -351,6 +352,12 @@ class Being : public Sprite std::auto_ptr<Equipment> mEquipment; + /** + * Take control of a particle + */ + void + controlParticle(Particle *particle); + protected: /** * Sets the new path for this being. @@ -380,15 +387,14 @@ class Being : public Sprite Path mPath; std::string mSpeech; - std::string mDamage; Uint16 mHairStyle, mHairColor; Uint8 mSex; Uint32 mSpeechTime; - Uint32 mDamageTime; Sint32 mPx, mPy; /**< Pixel coordinates */ std::vector<AnimatedSprite*> mSprites; std::vector<int> mEquipmentSpriteIDs; + std::list<Particle *> mChildParticleEffects; private: static int instances; /**< Number of Being instances */ diff --git a/src/engine.cpp b/src/engine.cpp index 8546f150..fb6b6048 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -36,6 +36,7 @@ #include "log.h" #include "main.h" #include "map.h" +#include "particle.h" #include "sound.h" #include "gui/gui.h" @@ -68,6 +69,7 @@ void Engine::changeMap(const std::string &mapPath) floorItemManager->clear(); beingManager->clear(); + particleEngine->clear(); // Store full map path in global var map_path = "maps/" + mapPath.substr(0, mapPath.rfind(".")) + ".tmx.gz"; @@ -88,8 +90,12 @@ void Engine::changeMap(const std::string &mapPath) } minimap->setMapImage(mapImage); beingManager->setMap(newMap); + particleEngine->setMap(newMap); viewport->setMap(newMap); + // Initialize map-based particle effects + newMap->initializeParticleEffects(particleEngine); + // Start playing new music file when necessary std::string oldMusic = ""; @@ -115,5 +121,6 @@ void Engine::changeMap(const std::string &mapPath) void Engine::logic() { beingManager->logic(); + particleEngine->update(); gui->logic(); } diff --git a/src/game.cpp b/src/game.cpp index d8235384..a51343dd 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -40,6 +40,7 @@ #include "localplayer.h" #include "log.h" #include "npc.h" +#include "particle.h" #include "gui/buy.h" #include "gui/buysell.h" @@ -117,6 +118,7 @@ DebugWindow *debugWindow; BeingManager *beingManager = NULL; FloorItemManager *floorItemManager = NULL; +Particle* particleEngine = NULL; const int MAX_TIME = 10000; @@ -251,6 +253,8 @@ Game::Game(Network *network): beingManager = new BeingManager(network); floorItemManager = new FloorItemManager(); + particleEngine = new Particle(NULL); + particleEngine->setupEngine(); // Initialize timers tick_time = 0; @@ -295,6 +299,7 @@ Game::~Game() delete beingManager; delete floorItemManager; delete joystick; + delete particleEngine; beingManager = NULL; floorItemManager = NULL; diff --git a/src/graphics.cpp b/src/graphics.cpp index f007470a..4ea75a93 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -148,6 +148,17 @@ bool Graphics::drawImage(Image *image, int srcX, int srcY, int dstX, int dstY, return !(SDL_BlitSurface(image->mImage, &srcRect, mScreen, &dstRect) < 0); } +bool Graphics::drawImageTransparent(Image *image, int x, int y, float opacity) +{ + if (!image) return false; + + float oldalpha = image->getAlpha(); + image->setAlpha(opacity * oldalpha); + bool retval = drawImage(image, x, y); + image->setAlpha(oldalpha); + return retval; +} + void Graphics::drawImagePattern(Image *image, int x, int y, int w, int h) { int iw = image->getWidth(); diff --git a/src/graphics.h b/src/graphics.h index b3d36653..abef794f 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -97,6 +97,14 @@ class Graphics : public gcn::SDLGraphics { int dstX, int dstY, int width, int height); + /** + * Blits an image onto the screen with an alpha factor + * + * @return <code>true</code> if the image was blitted properly + * <code>false</code> otherwise. + */ + bool drawImageTransparent(Image *image, int x, int y, float opacity); + virtual void drawImagePattern(Image *image, int x, int y, diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp index 563f380f..ebf7d974 100644 --- a/src/gui/debugwindow.cpp +++ b/src/gui/debugwindow.cpp @@ -33,6 +33,7 @@ #include "../game.h" #include "../engine.h" +#include "../particle.h" #include "../map.h" #include "../utils/tostring.h" @@ -58,6 +59,9 @@ DebugWindow::DebugWindow(): mTileMouseLabel = new gcn::Label("[Mouse: 0, 0]"); mTileMouseLabel->setPosition(100, 0); + mParticleCountLabel = new gcn::Label("[Particle count: 0]"); + mParticleCountLabel->setPosition(100, 60); + Button *closeButton = new Button("Close", "close", this); closeButton->setPosition(5, 60); @@ -65,6 +69,7 @@ DebugWindow::DebugWindow(): add(mMusicFileLabel); add(mMapFileLabel); add(mTileMouseLabel); + add(mParticleCountLabel); add(closeButton); } @@ -97,6 +102,11 @@ DebugWindow::logic() mMapFileLabel->setCaption(minimap); mMapFileLabel->adjustSize(); } + + mParticleCountLabel->setCaption("[Particle count: " + + toString(Particle::particleCount) + +"]"); + mParticleCountLabel->adjustSize(); } void diff --git a/src/gui/debugwindow.h b/src/gui/debugwindow.h index 4fd33d83..d082b2ca 100644 --- a/src/gui/debugwindow.h +++ b/src/gui/debugwindow.h @@ -58,6 +58,7 @@ class DebugWindow : public Window, public gcn::ActionListener private: gcn::Label *mMusicFileLabel, *mMapFileLabel; gcn::Label *mTileMouseLabel, *mFPSLabel; + gcn::Label *mParticleCountLabel; }; #endif diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp new file mode 100644 index 00000000..86e7e50f --- /dev/null +++ b/src/imageparticle.cpp @@ -0,0 +1,67 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "imageparticle.h" + +#include "graphics.h" + +#include "resources/image.h" + +ImageParticle::ImageParticle(Map *map, Image *image): + Particle(map), + mImage(image) +{ +} + +void ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const +{ + if (!mAlive) + return; + + int screenX = (int)mPosX + offsetX - mImage->getWidth()/2; + int screenY = (int)mPosY - int(mPosZ) + offsetY - mImage->getHeight()/2; + + // check if on screen + if (screenX + mImage->getWidth() < 0 || + screenX > graphics->getWidth() || + screenY + mImage->getHeight() < 0 || + screenY > graphics->getHeight()) + return; + + float alphafactor = 1.0f; + + if (mLifetimeLeft > -1 && mLifetimeLeft < mFadeOut) + alphafactor *= ((float)mLifetimeLeft / (float)mFadeOut); + + if (mLifetimePast < mFadeIn) + alphafactor *= ((float)mLifetimePast / (float)mFadeIn); + + if (alphafactor < 1.0f) { + graphics->drawImageTransparent(mImage, + screenX, + screenY, + alphafactor + ); + } else { + graphics->drawImage(mImage, screenX, screenY); + } +} diff --git a/src/imageparticle.h b/src/imageparticle.h new file mode 100644 index 00000000..4396fb7c --- /dev/null +++ b/src/imageparticle.h @@ -0,0 +1,46 @@ +/* + * The Mana World + * Copyright 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _IMAGEPARTICLE_H +#define _IMAGEPARTICLE_H + +#include "particle.h" + +class Image; +class Map; + +class ImageParticle : public Particle +{ + public: + ImageParticle(Map *map, Image *image); + + /** + * Draws the particle image + */ + virtual void + draw(Graphics *graphics, int offsetX, int offsetY) const; + + protected: + Image *mImage; /**< The image used for this particle. */ +}; + +#endif diff --git a/src/map.cpp b/src/map.cpp index 575f80d3..1f0c22b9 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -29,6 +29,7 @@ #include "beingmanager.h" #include "game.h" #include "graphics.h" +#include "particle.h" #include "sprite.h" #include "tileset.h" @@ -508,3 +509,25 @@ Map::findPath(int startX, int startY, int destX, int destY) return path; } + +void +Map::addParticleEffect (std::string effectFile, int x, int y) +{ + ParticleEffectData newEffect; + newEffect.file = effectFile; + newEffect.x = x; + newEffect.y = y; + particleEffects.push_back(newEffect); +} + +void +Map::initializeParticleEffects(Particle* particleEngine) +{ + for (std::list<ParticleEffectData>::iterator i = particleEffects.begin(); + i != particleEffects.end(); + i++ + ) + { + particleEngine->addEffect(i->file, i->x, i->y); + } +} @@ -32,8 +32,9 @@ class AmbientOverlay; class Graphics; class Image; -class Tileset; +class Particle; class Sprite; +class Tileset; struct PATH_NODE; @@ -185,6 +186,17 @@ class Map : public Properties void removeSprite(SpriteIterator iterator); + /** + * Adds a particle effect + */ + void addParticleEffect (std::string effectFile, int x, int y); + + /** + * Initializes all added particle effects + */ + void + initializeParticleEffects(Particle* particleEngine); + private: /** * Converts a global tile id to the Image* pointing to the associated @@ -220,10 +232,19 @@ class Map : public Properties // Pathfinding members int mOnClosedList, mOnOpenList; - //overlay Data + // Overlay Data std::list<AmbientOverlay*> mOverlays; float mLastScrollX; float mLastScrollY; + + // Particle effect data + struct ParticleEffectData + { + std::string file; + int x; + int y; + }; + std::list<ParticleEffectData> particleEffects; }; #endif diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 4734a710..fc202b36 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -34,6 +34,7 @@ #include "../localplayer.h" #include "../log.h" #include "../main.h" +#include "../particle.h" #include "../sound.h" const int EMOTION_TIME = 150; /**< Duration of emotion icon */ @@ -212,13 +213,23 @@ void BeingHandler::handleMessage(MessageIn *msg) break; case SMSG_BEING_LEVELUP: - if ((Uint32) msg->readInt32() == player_node->getId()) { + id = (Uint32)msg->readInt32(); + + if (id == player_node->getId()) { logger->log("Level up"); sound.playSfx("sfx/levelup.ogg"); - } else { + } + else { logger->log("Someone else went level up"); } - msg->readInt32(); // type + Particle *levelupFX; + if (msg->readInt32() == 0) { // type + levelupFX = particleEngine->addEffect("graphics/particles/levelup.particle.xml", 0, 0); + } + else { + levelupFX = particleEngine->addEffect("graphics/particles/skillup.particle.xml", 0, 0); + } + beingManager->findBeing(id)->controlParticle(levelupFX); break; case SMSG_BEING_EMOTION: diff --git a/src/particle.cpp b/src/particle.cpp new file mode 100644 index 00000000..bb28c873 --- /dev/null +++ b/src/particle.cpp @@ -0,0 +1,366 @@ +/*
+ * The Mana World
+ * Copyright 2006 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "particle.h"
+
+#include <cmath>
+
+#include "animationparticle.h"
+#include "configuration.h"
+#include "imageparticle.h"
+#include "log.h"
+#include "map.h"
+#include "particleemitter.h"
+#include "textparticle.h"
+
+#include "resources/resourcemanager.h"
+
+#include "utils/dtor.h"
+#include "utils/fastsqrt.h"
+#include "utils/xml.h"
+
+class Graphics;
+class Image;
+
+int Particle::particleCount = 0;
+int Particle::maxCount = 0;
+int Particle::fastPhysics = 0;
+int Particle::emitterSkip = 1;
+const float Particle::PARTICLE_SKY = 800.0f;
+
+Particle::Particle(Map *map) :
+ mAlive(true),
+ mPosX(0.0f), mPosY(0.0f), mPosZ(0.0f),
+ mLifetimeLeft(-1),
+ mLifetimePast(0),
+ mFadeOut(0),
+ mFadeIn(0),
+ mAutoDelete(true),
+ mMap(map),
+ mVectorX(0.0f), mVectorY(0.0f), mVectorZ(0.0f),
+ mGravity(0.0f),
+ mRandomnes(0),
+ mBounce(0.0f),
+ mTarget(NULL),
+ mAcceleration(0.0f),
+ mInvDieDistance(-1.0f),
+ mMomentum(1.0f)
+{
+ Particle::particleCount++;
+ if (mMap) setSpriteIterator(mMap->addSprite(this));
+}
+
+
+void
+Particle::setupEngine()
+{
+ Particle::maxCount = (int)config.getValue("particleMaxCount", 3000);
+ Particle::fastPhysics = (int)config.getValue("particleFastPhysics", 0);
+ Particle::emitterSkip = (int)config.getValue("particleEmitterSkip", 0) + 1;
+ disableAutoDelete();
+ logger->log("Particle engine set up");
+}
+
+bool
+Particle::update()
+{
+ if (!mMap) return false;
+
+ if (mLifetimeLeft == 0)
+ {
+ mAlive = false;
+ }
+
+ if (mAlive)
+ {
+ //update child emitters
+ if (mLifetimePast%Particle::emitterSkip == 0)
+ {
+ for ( EmitterIterator e = mChildEmitters.begin();
+ e != mChildEmitters.end();
+ e++
+ )
+ {
+ Particles newParticles = (*e)->createParticles();
+ for ( ParticleIterator p = newParticles.begin();
+ p != newParticles.end();
+ p++
+ )
+ {
+ (*p)->moveBy(mPosX, mPosY, mPosZ);
+ mChildParticles.push_back (*p);
+ }
+ }
+ }
+
+ if (mMomentum != 1.0f)
+ {
+ mVectorX *= mMomentum;
+ mVectorY *= mMomentum;
+ mVectorZ *= mMomentum;
+ }
+
+ if (mTarget && mAcceleration != 0.0f)
+ {
+ float distX = mPosX - mTarget->getPosX();
+ float distY = mPosY - mTarget->getPosY();
+ float distZ = mPosZ - mTarget->getPosZ();
+ float invHypotenuse;
+
+ switch(Particle::fastPhysics)
+ {
+ case 1:
+ invHypotenuse = fastInvSqrt(
+ distX * distX + distY * distY + distZ * distZ);
+ break;
+ case 2:
+ invHypotenuse = 2.0f /
+ fabs(distX) + fabs(distY) + fabs(distZ);
+ break;
+ default:
+ invHypotenuse = 1.0f / sqrt(
+ distX * distX + distY * distY + distZ * distZ);
+ break;
+ }
+
+ if (invHypotenuse)
+ {
+ if (mInvDieDistance > 0.0f && invHypotenuse > mInvDieDistance)
+ {
+ logger->log("killed");
+ mAlive = false;
+ }
+ float accFactor = invHypotenuse * mAcceleration;
+ mVectorX -= distX * accFactor;
+ mVectorY -= distY * accFactor;
+ mVectorZ -= distZ * accFactor;
+ }
+ }
+
+ if (mRandomnes > 0)
+ {
+ mVectorX += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f;
+ mVectorY += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f;
+ mVectorZ += (rand()%mRandomnes - rand()%mRandomnes) / 1000.0f;
+ }
+
+ mVectorZ -= mGravity;
+
+ // update position
+ mPosX += mVectorX;
+ mPosY += mVectorY;
+ mPosZ += mVectorZ;
+
+ //update other stuff
+ if (mLifetimeLeft > 0)
+ {
+ mLifetimeLeft--;
+ }
+ mLifetimePast++;
+
+ if (mPosZ > PARTICLE_SKY || mPosZ < 0.0f)
+ {
+ if (mBounce && fabs(mVectorZ) > mGravity * 2) {
+ mPosZ *= -mBounce;
+ mVectorX *= mBounce;
+ mVectorY *= mBounce;
+ mVectorZ *= -mBounce;
+ }
+ else {
+ mAlive = false;
+ }
+ }
+ }
+
+ //update child particles
+ for ( ParticleIterator p = mChildParticles.begin();
+ p != mChildParticles.end();
+
+ )
+ {
+ if ((*p)->update())
+ {
+ p++;
+ }else {
+ delete (*p);
+ p = mChildParticles.erase(p);
+ }
+ }
+
+ if (!mAlive && mChildParticles.empty() && mAutoDelete)
+ {
+ return false;
+ };
+
+ return true;
+}
+
+
+void Particle::draw(Graphics *graphics, int offsetX, int offsetY) const
+{
+}
+
+
+Particle*
+Particle::addEffect (std::string particleEffectFile, int pixelX, int pixelY)
+{
+ Particle *newParticle = NULL;
+
+ // XML parser initialisation stuff
+ int size;
+ ResourceManager *resman = ResourceManager::getInstance();
+ char *data = (char*) resman->loadFile(particleEffectFile.c_str(), size);
+
+ if (!data) {
+ logger->log("Warning: Particle engine could not find %s !",
+ particleEffectFile.c_str());
+ return NULL;
+ }
+
+ xmlDocPtr doc = xmlParseMemory(data, size);
+ free(data);
+
+ if (!doc) {
+ logger->log("Warning: Particle engine found syntax error in %s!",
+ particleEffectFile.c_str());
+ return NULL;
+ }
+
+ xmlNodePtr rootNode = xmlDocGetRootElement(doc);
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "effect")) {
+ logger->log("Warning: %s is not a valid particle effect definition file!",
+ particleEffectFile.c_str());
+ return NULL;
+ }
+
+ // parse particles
+ for_each_xml_child_node(effectChildNode, rootNode)
+ {
+ // We're only interested in particles
+ if (!xmlStrEqual(effectChildNode->name, BAD_CAST "particle"))
+ continue;
+
+ // Determine the exact particle type
+ xmlNodePtr node;
+
+ // Animation
+ if ((node = XML::findFirstChildByName(
+ effectChildNode, "animation"))) {
+ newParticle = new AnimationParticle(mMap, node);
+ }
+ // Image
+ else if ((node = XML::findFirstChildByName(
+ effectChildNode, "image"))) {
+ Image *img= resman->getImage((const char*)
+ node->xmlChildrenNode->content);
+
+ newParticle = new ImageParticle(mMap, img);
+ }
+ // Other
+ else {
+ newParticle = new Particle(mMap);
+ }
+
+ // Read and set the basic properties of the particle
+ int offsetX = XML::getProperty(effectChildNode, "position-x", 0);
+ int offsetY = XML::getProperty(effectChildNode, "position-y", 0);
+ int offsetZ = XML::getProperty(effectChildNode, "position-z", 0);
+
+ int particleX = (int)mPosX + pixelX + offsetX;
+ int particleY = (int)mPosY + pixelY + offsetY;
+ int particleZ = (int)mPosZ + offsetZ;
+
+ int lifetime = XML::getProperty(effectChildNode, "lifetime", -1);
+
+ newParticle->setPosition(particleX, particleY, particleZ);
+ newParticle->setLifetime(lifetime);
+
+ // Look for additional emitters for this particle
+ for_each_xml_child_node(emitterNode, effectChildNode)
+ {
+ if (!xmlStrEqual(emitterNode->name, BAD_CAST "emitter"))
+ continue;
+
+ ParticleEmitter *newEmitter;
+ newEmitter = new ParticleEmitter(emitterNode, newParticle, mMap);
+ newParticle->addEmitter(newEmitter);
+ }
+
+ mChildParticles.push_back(newParticle);
+ }
+
+ return newParticle;
+}
+
+
+Particle*
+Particle::addTextSplashEffect(std::string text, gcn::Font *font, gcn::Color color, int x, int y)
+{
+ Particle *newParticle = new TextParticle(mMap, text, font, color);
+ newParticle->setPosition( x,
+ y,
+ 0
+ );
+ newParticle->setVector ( ((rand()%100) - 50) / 200.0f, //X Vector
+ ((rand()%100) - 50) / 200.0f, //Y Vector
+ ((rand()%100) / 200.0f) + 4.0f //Z Vector
+ );
+ newParticle->setGravity(0.1f);
+ newParticle->setBounce(0.5f);
+
+ mChildParticles.push_back(newParticle);
+
+ return newParticle;
+}
+
+
+void
+Particle::setMap(Map *map)
+{
+ mMap = map;
+ if (mMap) setSpriteIterator(mMap->addSprite(this));
+
+ // TODO: Create map emitters based on emitter data in map data
+}
+
+
+Particle::~Particle()
+{
+ //remove from map sprite list
+ if (mMap) mMap->removeSprite(mSpriteIterator);
+ //delete child emitters and child particles
+ clear();
+ Particle::particleCount--;
+}
+
+
+void
+Particle::clear()
+{
+ std::for_each(mChildEmitters.begin(), mChildEmitters.end(),
+ make_dtor(mChildEmitters));
+ mChildEmitters.clear();
+
+ std::for_each(mChildParticles.begin(), mChildParticles.end(),
+ make_dtor(mChildParticles));
+ mChildParticles.clear();
+}
diff --git a/src/particle.h b/src/particle.h new file mode 100644 index 00000000..f208225a --- /dev/null +++ b/src/particle.h @@ -0,0 +1,278 @@ +/*
+ * The Mana World
+ * Copyright 2006 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _PARTICLE_H
+#define _PARTICLE_H
+
+#include <list>
+#include <string>
+
+#include <guichan/color.hpp>
+
+#include "guichanfwd.h"
+#include "sprite.h"
+
+
+class Map;
+class Particle;
+class ParticleEmitter;
+
+typedef std::list<Particle *> Particles;
+typedef Particles::iterator ParticleIterator;
+typedef std::list<ParticleEmitter *> Emitters;
+typedef Emitters::iterator EmitterIterator;
+
+/**
+ * a particle spawned by a ParticleEmitter
+ */
+class Particle : public Sprite
+{
+ public:
+ static const float PARTICLE_SKY; /**< maximum Z position of particles */
+ static int fastPhysics; /**< mode of squareroot calculation */
+ static int particleCount; /**< current number of particles*/
+ static int maxCount; /**< maximum number of particles*/
+ static int emitterSkip; /**< duration of pause between two emitter updates in ticks */
+
+ Particle(Map *map);
+
+ ~Particle();
+
+ /**
+ * Deletes all child particles and emitters
+ */
+ void
+ clear();
+
+ /**
+ * Gives a particle the properties of an engine root particle and loads
+ * the particle-related config settings
+ */
+ void
+ setupEngine();
+
+ /**
+ * Updates particle position, returns false when the particle should
+ * be deleted
+ */
+ virtual bool
+ update();
+
+ /**
+ * Draws the particle image
+ */
+ virtual void
+ draw(Graphics *graphics, int offsetX, int offsetY) const;
+
+ /**
+ * Necessary for sorting with the other sprites
+ */
+ virtual int
+ getPixelY() const
+ {
+ return (int)(mPosY + mPosZ) - 64;
+ };
+
+ /*
+ Basic Particle properites:
+ */
+
+ /**
+ * Sets the map the particle is on
+ */
+ void setMap(Map *map);
+
+ /**
+ * Creates a child particle that hosts some emitters described in the
+ * particleEffectFile
+ */
+ Particle*
+ addEffect (std::string particleEffectFile, int pixelX, int pixelY);
+
+ /**
+ * Creates a standalone text particle
+ */
+ Particle*
+ addTextSplashEffect(std::string text, gcn::Font *font, gcn::Color color, int x, int y);
+
+ /**
+ * Adds an emitter to the particle
+ */
+ void
+ addEmitter (ParticleEmitter* emitter)
+ { mChildEmitters.push_back(emitter);};
+
+ /**
+ * Sets the position in 3 dimensional space in pixels relative to map
+ */
+ void
+ setPosition(float x, float y, float z)
+ { mPosX = x; mPosY = y; mPosZ = z; };
+
+ /**
+ * Sets the position in 2 dimensional space in pixels relative to map
+ */
+ void
+ setPosition(float x, float y)
+ { mPosX = x; mPosY = y; };
+
+ float getPosX() const
+ { return mPosX; };
+
+ float getPosY() const
+ { return mPosY; };
+
+ float getPosZ() const
+ { return mPosZ; };
+
+ /**
+ * Changes the particle position relative
+ */
+ void
+ moveBy(float x, float y, float z)
+ { mPosX += x; mPosY += y; mPosZ += z; };
+
+ /**
+ * Sets the time in game ticks until the particle is destroyed.
+ */
+ void
+ setLifetime(int lifetime)
+ { mLifetimeLeft = lifetime; mLifetimePast = 0; };
+
+ /**
+ * Sets the age of the pixel in game ticks where the particle has
+ * faded in completely
+ */
+ void
+ setFadeOut (int fadeOut)
+ { mFadeOut = fadeOut; };
+
+ /**
+ * Sets the remaining particle lifetime where the particle starts to
+ * fade out
+ */
+ void
+ setFadeIn (int fadeIn)
+ { mFadeIn = fadeIn; };
+
+ /**
+ * Sets the sprite iterator of the particle on the current map to make
+ * it easier to remove the particle from the map when it is destroyed
+ */
+ void
+ setSpriteIterator(std::list<Sprite*>::iterator spriteIterator)
+ { mSpriteIterator = spriteIterator; };
+
+ /**
+ * Gets the sprite iterator of the particle on the current map
+ */
+ std::list<Sprite*>::iterator
+ getSpriteIterator() const
+ { return mSpriteIterator; };
+
+ /**
+ * Sets the current velocity in 3 dimensional space
+ */
+ void
+ setVector(float x, float y, float z)
+ { mVectorX = x; mVectorY = y; mVectorZ = z; };
+
+ /**
+ * Sets the downward acceleration
+ */
+ void
+ setGravity(float g)
+ { mGravity = g; };
+
+ /**
+ * Sets the ammount of random vector changes
+ */
+ void
+ setRandomnes(int r)
+ { mRandomnes = r; };
+
+ /**
+ * Sets the ammount of velocity particles retain after
+ * hitting the ground.
+ */
+ void
+ setBounce(float bouncieness)
+ { mBounce = bouncieness; };
+
+ /**
+ * Makes the particle move toward another particle with a
+ * given acceleration and momentum
+ */
+ void setDestination(Particle *target, float accel, float moment)
+ { mTarget = target; mAcceleration = accel; mMomentum = moment; };
+
+ /**
+ * Sets the distance in pixel the particle can come near the target
+ * particle before it is destroyed. Does only make sense after a
+ * target particle has been set using setDestination.
+ */
+ void setDieDistance(float dist)
+ { mInvDieDistance = 1.0f / dist; };
+
+ /**
+ * Manually marks the particle for deletion
+ */
+ void kill()
+ { mAlive = false; mAutoDelete = true; };
+
+ /**
+ * After calling this function the particle will only request
+ * deletion when kill() is called
+ */
+ void disableAutoDelete()
+ { mAutoDelete = false; };
+
+ protected:
+ bool mAlive; /**< Is the particle supposed to be drawn and updated?*/
+ float mPosX, mPosY, mPosZ; /**< Position in 3 dimensonal space - pixel based relative to map */
+ int mLifetimeLeft; /**< Lifetime left in game ticks*/
+ int mLifetimePast; /**< Age of the particle in game ticks*/
+ int mFadeOut; /**< Lifetime in game ticks left where fading out begins*/
+ int mFadeIn; /**< Age in game ticks where fading in is finished*/
+
+ private:
+ // generic properties
+ bool mAutoDelete; /**< May the particle request its deletion by the parent particle?*/
+ Map *mMap; /**< Map the particle is on*/
+ std::list<Sprite*>::iterator mSpriteIterator; /**< iterator of the particle on the current map */
+ Emitters mChildEmitters; /**< List of child emitters*/
+ Particles mChildParticles; /**< List of particles controlled by this particle*/
+ //dynamic particle
+ float mVectorX, mVectorY, mVectorZ; /**< Speed in 3 dimensional space in pixels per game-tick */
+ float mGravity; /**< Downward acceleration in pixels per game-tickČ*/
+ int mRandomnes; /**< Ammount of random vector change*/
+ float mBounce; /**< How much the particle bounces off when hitting the ground*/
+ //follow-point particles
+ Particle *mTarget; /**< The particle that attracts this particle*/
+ float mAcceleration; /**< Acceleration towards the target particle in pixels per game-tickČ*/
+ float mInvDieDistance; /**< Distance in pixels from the target particle that causes the destruction of the particle*/
+ float mMomentum; /**< How much speed the particle retains after each game tick*/
+};
+
+extern Particle *particleEngine;
+
+#endif
diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp new file mode 100644 index 00000000..62ac6bd8 --- /dev/null +++ b/src/particleemitter.cpp @@ -0,0 +1,313 @@ +/*
+ * The Mana World
+ * Copyright 2006 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "particleemitter.h"
+
+#include "animationparticle.h"
+#include "imageparticle.h"
+#include "log.h"
+#include "particle.h"
+
+#include "resources/animation.h"
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+#include "resources/imageset.h"
+
+#include <cmath>
+
+#define SIN45 0.707106781f
+#define DEG_RAD_FACTOR 0.017453293f
+
+ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map)
+{
+ mMap = map;
+ mParticleTarget = target;
+
+ //initializing default values
+ mParticlePosX.set (0.0f);
+ mParticlePosY.set (0.0f);
+ mParticlePosZ.set (0.0f);
+ mParticleAngleHorizontal.set (0.0f);
+ mParticleAngleVertical.set (0.0f);
+ mParticlePower.set (0.0f);
+ mParticleGravity.set (0.0f);
+ mParticleRandomnes.set (0);
+ mParticleBounce.set(0.0f);
+ mParticleAcceleration.set (0.0f);
+ mParticleDieDistance.set(-1.0f);
+ mParticleMomentum.set (1.0f);
+ mParticleLifetime.set (-1);
+ mParticleFadeOut.set (0);
+ mParticleFadeIn.set (0);
+ mOutput.set (1);
+ mParticleImage = "";
+
+ for_each_xml_child_node(propertyNode, emitterNode)
+ {
+ if (xmlStrEqual(propertyNode->name, BAD_CAST "property"))
+ {
+ std::string name = XML::getProperty(propertyNode, "name", "");
+
+ if (name == "position-x")
+ {
+ mParticlePosX = readMinMax(propertyNode, 0.0f);
+ }
+ else if (name == "position-y")
+ {
+
+ mParticlePosY = readMinMax(propertyNode, 0.0f);
+ }
+ else if (name == "position-z")
+ {
+ mParticlePosZ = readMinMax(propertyNode, 0.0f);
+ }
+ else if (name == "image")
+ {
+ mParticleImage = XML::getProperty(propertyNode, "value", "");
+ }
+ else if (name == "horizontal-angle")
+ {
+ mParticleAngleHorizontal = readMinMax(propertyNode, 0.0f);
+ mParticleAngleHorizontal.minVal *= DEG_RAD_FACTOR;
+ mParticleAngleHorizontal.maxVal *= DEG_RAD_FACTOR;
+ }
+ else if (name == "vertical-angle")
+ {
+ mParticleAngleVertical = readMinMax(propertyNode, 0.0f);
+ mParticleAngleVertical.minVal *= DEG_RAD_FACTOR;
+ mParticleAngleVertical.maxVal *= DEG_RAD_FACTOR;
+ }
+ else if (name == "power")
+ {
+ mParticlePower = readMinMax(propertyNode, 0.0f);
+ }
+ else if (name == "gravity")
+ {
+ mParticleGravity = readMinMax(propertyNode, 0.0f);
+ }
+ else if (name == "randomnes")
+ {
+ mParticleRandomnes = readMinMax(propertyNode, 0);
+ }
+ else if (name == "bounce")
+ {
+ mParticleBounce = readMinMax(propertyNode, 0.0f);
+ }
+ else if (name == "lifetime")
+ {
+ mParticleLifetime = readMinMax(propertyNode, 0);
+ mParticleLifetime.minVal += 1;
+ }
+ else if (name == "output")
+ {
+ mOutput = readMinMax(propertyNode, 0);
+ mOutput.maxVal +=1;
+ }
+ else if (name == "acceleration")
+ {
+ mParticleAcceleration = readMinMax(propertyNode, 0.0f);
+ }
+ else if (name == "die-distance")
+ {
+ mParticleDieDistance = readMinMax(propertyNode, 0.0f);
+ }
+ else if (name == "momentum")
+ {
+ mParticleMomentum = readMinMax(propertyNode, 1.0f);
+ }
+ else if (name == "fade-out")
+ {
+ mParticleFadeOut = readMinMax(propertyNode, 0);
+ }
+ else if (name == "fade-in")
+ {
+ mParticleFadeIn = readMinMax(propertyNode, 0);
+ }
+ else
+ {
+ logger->log("Particle Engine: Warning, unknown emitter property \"%s\"",
+ name.c_str()
+ );
+ }
+ }
+ else if (xmlStrEqual(propertyNode->name, BAD_CAST "emitter"))
+ {
+ ParticleEmitter newEmitter(propertyNode, mParticleTarget, map);
+ mParticleChildEmitters.push_back(newEmitter);
+ }
+ else if (xmlStrEqual(propertyNode->name, BAD_CAST "animation"))
+ {
+ ImageSet *imageset = ResourceManager::getInstance()->getImageSet(
+ XML::getProperty(propertyNode, "imageset", ""),
+ XML::getProperty(propertyNode, "width", 0),
+ XML::getProperty(propertyNode, "height", 0)
+ );
+
+ // Get animation frames
+ for_each_xml_child_node(frameNode, propertyNode)
+ {
+ int delay = XML::getProperty(frameNode, "delay", 0);
+ int offsetX = XML::getProperty(frameNode, "offsetX", 0);
+ int offsetY = XML::getProperty(frameNode, "offsetY", 0);
+ offsetY -= imageset->getHeight() - 32;
+ offsetX -= imageset->getWidth() / 2 - 16;
+
+ if (xmlStrEqual(frameNode->name, BAD_CAST "frame"))
+ {
+ int index = XML::getProperty(frameNode, "index", -1);
+
+ if (index < 0)
+ {
+ logger->log("No valid value for 'index'");
+ continue;
+ }
+
+ Image *img = imageset->get(index);
+
+ if (!img)
+ {
+ logger->log("No image at index " + (index));
+ continue;
+ }
+
+ mParticleAnimation.addFrame(img, delay, offsetX, offsetY);
+ }
+ else if (xmlStrEqual(frameNode->name, BAD_CAST "sequence"))
+ {
+ int start = XML::getProperty(frameNode, "start", -1);
+ int end = XML::getProperty(frameNode, "end", -1);
+
+ if (start < 0 || end < 0)
+ {
+ logger->log("No valid value for 'start' or 'end'");
+ continue;
+ }
+
+ while (end >= start)
+ {
+ Image *img = imageset->get(start);
+
+ if (!img)
+ {
+ logger->log("No image at index " +
+ (start));
+ continue;
+ }
+
+ mParticleAnimation.addFrame(img, delay, offsetX, offsetY);
+ start++;
+ }
+ }
+ else if (xmlStrEqual(frameNode->name, BAD_CAST "end"))
+ {
+ mParticleAnimation.addTerminator();
+ }
+ } // for frameNode
+ }
+ }
+}
+
+
+template <typename T> MinMax<T>
+ParticleEmitter::readMinMax(xmlNodePtr propertyNode, T def)
+{
+ MinMax<T> retval;
+
+ def = (T)XML::getFloatProperty(propertyNode, "value", (double)def);
+ retval.set ( (T)XML::getFloatProperty(propertyNode, "min", (double)def),
+ (T)XML::getFloatProperty(propertyNode, "max", (double)def)
+ );
+
+ return retval;
+}
+
+
+std::list<Particle *>
+ParticleEmitter::createParticles()
+{
+ std::list<Particle *> newParticles;
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ for (int i = mOutput.value(); i > 0; i--)
+ {
+ //limit maximum particles
+ if (Particle::particleCount > Particle::maxCount) break;
+
+ Particle *newParticle;
+ if (mParticleImage != "")
+ {
+ newParticle = new ImageParticle(mMap,
+ resman->getImage(mParticleImage));
+ }
+ else if (mParticleAnimation.getLength() > 0)
+ {
+ Animation *newAnimation = new Animation(mParticleAnimation);
+ newParticle = new AnimationParticle(mMap, newAnimation);
+ }
+ else
+ {
+ newParticle = new Particle(mMap);
+ }
+
+
+ newParticle->setPosition(
+ mParticlePosX.value(),
+ mParticlePosY.value(),
+ mParticlePosZ.value()
+ );
+
+ float angleH = mParticleAngleHorizontal.value();
+ float angleV = mParticleAngleVertical.value();
+ float power = mParticlePower.value();
+ newParticle->setVector(
+ cos(angleH) * cos(angleV) * power,
+ sin(angleH) * cos(angleV) * SIN45 * power,
+ sin(angleV) * SIN45 * power
+ );
+
+ newParticle->setRandomnes(mParticleRandomnes.value());
+ newParticle->setGravity(mParticleGravity.value());
+ newParticle->setBounce(mParticleBounce.value());
+
+ newParticle->setDestination(mParticleTarget,
+ mParticleAcceleration.value(),
+ mParticleMomentum.value()
+ );
+ newParticle->setDieDistance(mParticleDieDistance.value());
+
+ newParticle->setLifetime(mParticleLifetime.value());
+ newParticle->setFadeOut(mParticleFadeOut.value());
+ newParticle->setFadeIn(mParticleFadeIn.value());
+
+ for ( std::list<ParticleEmitter>::iterator i = mParticleChildEmitters.begin();
+ i != mParticleChildEmitters.end();
+ i++
+ )
+ {
+ newParticle->addEmitter(new ParticleEmitter(*i));
+ }
+
+ newParticles.push_back(newParticle);
+ }
+
+ return newParticles;
+}
diff --git a/src/particleemitter.h b/src/particleemitter.h new file mode 100644 index 00000000..dcc7069b --- /dev/null +++ b/src/particleemitter.h @@ -0,0 +1,108 @@ +/*
+ * The Mana World
+ * Copyright 2006 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _PARTICLEEMITTER_H
+#define _PARTICLEEMITTER_H
+
+#include <list>
+
+#include "utils/xml.h"
+#include "utils/minmax.h"
+
+#include "resources/animation.h"
+
+class Map;
+class Particle;
+
+/**
+ * Every Particle can have one or more particle emitters that create new
+ * particles when they are updated
+ */
+class ParticleEmitter
+{
+ public:
+
+ ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map);
+
+ /**
+ * Spawns new particles
+ * @return: a list of created particles
+ */
+ std::list<Particle *> createParticles();
+
+ /**
+ * Sets the target of the particles that are created
+ */
+ void
+ setTarget(Particle *target)
+ { mParticleTarget = target; };
+
+ private:
+ template <typename T> MinMax<T> readMinMax(xmlNodePtr propertyNode, T def);
+
+ /**
+ * initial position of particles:
+ */
+ MinMax<float> mParticlePosX, mParticlePosY, mParticlePosZ;
+
+ /**
+ * initial vector of particles:
+ */
+ MinMax<float> mParticleAngleHorizontal, mParticleAngleVertical;
+
+ /**
+ * Initial velocity of particles
+ */
+ MinMax<float> mParticlePower;
+
+ /**
+ * vector changing of particles:
+ */
+ MinMax<float> mParticleGravity;
+ MinMax<int> mParticleRandomnes;
+ MinMax<float> mParticleBounce;
+
+ /**
+ * Properties of targeting particles:
+ */
+ Particle *mParticleTarget;
+ MinMax<float> mParticleAcceleration;
+ MinMax<float> mParticleDieDistance;
+ MinMax<float> mParticleMomentum;
+
+ /**
+ * Behavior over time of the particles:
+ */
+ MinMax<int> mParticleLifetime;
+ MinMax<int> mParticleFadeOut;
+ MinMax<int> mParticleFadeIn;
+
+ Map *mMap; /**< Map the particles are supposed to spawn on */
+
+ MinMax<int> mOutput; /**< Number of particles spawned per update */
+
+ std::string mParticleImage; /**< Filename of particle image */
+ Animation mParticleAnimation; /**< Filename of particle animation file */
+
+ std::list<ParticleEmitter> mParticleChildEmitters; /** List of emitters the spawned particles are equipped with */
+};
+#endif
diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index fda8916d..2230cb6a 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -231,6 +231,30 @@ MapReader::readMap(xmlNodePtr node, const std::string &path) { readProperties(childNode, map); } + else if (xmlStrEqual(childNode->name, BAD_CAST "objectgroup")) + { + for_each_xml_child_node(objectNode, childNode) + { + if (xmlStrEqual(objectNode->name, BAD_CAST "object")) + { + std::string objName = XML::getProperty(objectNode, "name", ""); + std::string objType = XML::getProperty(objectNode, "type", ""); + int objX = XML::getProperty(objectNode, "x", 0); + int objY = XML::getProperty(objectNode, "y", 0); + + logger->log("- Loading object name: %s type: %s at %d:%d", + objName.c_str(), objType.c_str(), objX, objY); + if (objType == "PARTICLE_EFFECT") + { + map->addParticleEffect(objName, objX, objY); + } + else + { + logger->log(" Warning: Unknown object type"); + } + } + } + } } map->initializeOverlays(); diff --git a/src/simpleanimation.cpp b/src/simpleanimation.cpp index 5fc35bcd..f52fd172 100644 --- a/src/simpleanimation.cpp +++ b/src/simpleanimation.cpp @@ -23,10 +23,95 @@ #include "simpleanimation.h" +#include "graphics.h" +#include "log.h" + +#include "resources/image.h" +#include "resources/resourcemanager.h" +#include "resources/imageset.h" + + +SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): + mAnimationTime(0), + mAnimationPhase(0) +{ + mAnimation = new Animation(); + + ImageSet *imageset = ResourceManager::getInstance()->getImageSet( + XML::getProperty(animationNode, "imageset", ""), + XML::getProperty(animationNode, "width", 0), + XML::getProperty(animationNode, "height", 0) + ); + + // Get animation frames + for ( xmlNodePtr frameNode = animationNode->xmlChildrenNode; + frameNode != NULL; + frameNode = frameNode->next) + { + int delay = XML::getProperty(frameNode, "delay", 0); + int offsetX = XML::getProperty(frameNode, "offsetX", 0); + int offsetY = XML::getProperty(frameNode, "offsetY", 0); + offsetY -= imageset->getHeight() - 32; + offsetX -= imageset->getWidth() / 2 - 16; + + if (xmlStrEqual(frameNode->name, BAD_CAST "frame")) + { + int index = XML::getProperty(frameNode, "index", -1); + + if (index < 0) + { + logger->log("No valid value for 'index'"); + continue; + } + + Image *img = imageset->get(index); + + if (!img) + { + logger->log("No image at index " + (index)); + continue; + } + + mAnimation->addFrame(img, delay, offsetX, offsetY); + } + else if (xmlStrEqual(frameNode->name, BAD_CAST "sequence")) + { + int start = XML::getProperty(frameNode, "start", -1); + int end = XML::getProperty(frameNode, "end", -1); + + if (start < 0 || end < 0) + { + logger->log("No valid value for 'start' or 'end'"); + continue; + } + + while (end >= start) + { + Image *img = imageset->get(start); + + if (!img) + { + logger->log("No image at index " + + (start)); + continue; + } + + mAnimation->addFrame(img, delay, offsetX, offsetY); + start++; + } + } + else if (xmlStrEqual(frameNode->name, BAD_CAST "end")) + { + mAnimation->addTerminator(); + } + } + + mCurrentFrame = mAnimation->getFrame(0); +} void SimpleAnimation::update(unsigned int timePassed) { - mAnimationTime += timePassed; + mAnimationTime+=timePassed; while (mAnimationTime > mCurrentFrame->delay) { mAnimationTime -= mCurrentFrame->delay; diff --git a/src/simpleanimation.h b/src/simpleanimation.h index a56c31da..14793c2f 100644 --- a/src/simpleanimation.h +++ b/src/simpleanimation.h @@ -26,7 +26,10 @@ #include "resources/animation.h" +#include "utils/xml.h" + class Frame; +class Graphics; /** * This class is a leightweight alternative to the AnimatedSprite class. @@ -35,6 +38,10 @@ class Frame; class SimpleAnimation { public: + + /** + * Creates a simple animation with an already created animation + */ SimpleAnimation(Animation *animation): mAnimation(animation), mAnimationTime(0), @@ -42,6 +49,11 @@ class SimpleAnimation mCurrentFrame(mAnimation->getFrame(0)) {}; + /** + * Creates a simple animation that creates its animation from XML Data + */ + SimpleAnimation(xmlNodePtr animationNode); + ~SimpleAnimation(); void update(unsigned int timePassed); @@ -49,17 +61,10 @@ class SimpleAnimation Image *getCurrentImage() const; private: - /** The hosted animation. */ - Animation *mAnimation; - - /** Time in game ticks the current frame is shown. */ - unsigned int mAnimationTime; - - /** Index of current animation frame. */ - unsigned int mAnimationPhase; - - /** Current animation frame. */ - Frame *mCurrentFrame; + Animation *mAnimation; /**< The hosted animation */ + unsigned int mAnimationTime; /**< Time in game ticks the current frame is shown*/ + unsigned int mAnimationPhase; /**< Index of current animation phase*/ + Frame *mCurrentFrame; /**< Current animation phase */ }; #endif diff --git a/src/utils/fastsqrt.h b/src/utils/fastsqrt.h new file mode 100644 index 00000000..8ba6f8ce --- /dev/null +++ b/src/utils/fastsqrt.h @@ -0,0 +1,23 @@ +/* A very fast function to calculate the approximate inverse square root of a
+ * floating point value and a helper function that uses it for getting the
+ * normal squareroot. For an explanation of the inverse squareroot function
+ * read:
+ * http://www.math.purdue.edu/~clomont/Math/Papers/2003/InvSqrt.pdf
+ *
+ * Unfortunately the original creator of this function seems to be unknown.
+ */
+
+float fastInvSqrt(float x)
+{
+ float xhalf = 0.5f*x;
+ int i = *(int*)&x;
+ i = 0x5f375a86- (i>>1);
+ x = *(float*)&i;
+ x = x*(1.5f-xhalf*x*x);
+ return x;
+}
+
+float fastSqrt(float x)
+{
+ return 1.0f/fastInvSqrt(x);
+}
diff --git a/src/utils/minmax.h b/src/utils/minmax.h new file mode 100644 index 00000000..1add2b7e --- /dev/null +++ b/src/utils/minmax.h @@ -0,0 +1,47 @@ +/*
+ * The Mana World
+ * Copyright 2006 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/**
+ * Returns a random numeric value that is larger than or equal min and smaller
+ * than max
+ */
+
+template <typename T> struct MinMax
+{
+ void set(T min, T max)
+ {
+ minVal=min; maxVal=max;
+ }
+
+ void set(T val)
+ {
+ set(val, val);
+ }
+
+ T value()
+ {
+ return (T)(minVal + (maxVal - minVal) * (rand() / ((double) RAND_MAX + 1)));
+ }
+
+ T minVal;
+ T maxVal;
+};
diff --git a/src/utils/wingettimeofday.h b/src/utils/wingettimeofday.h index a5537f39..28afb7e5 100644 --- a/src/utils/wingettimeofday.h +++ b/src/utils/wingettimeofday.h @@ -1,113 +1,113 @@ -/*
- * The Mana World
- * Copyright 2004 The Mana World Development Team
- *
- * This file is part of The Mana World.
- *
- * The Mana World is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * The Mana World is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with The Mana World; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * $Id$
- */
-
-#ifndef _TMW_WINGETTIMEOFDAY_H_
-#define _TMW_WINGETTIMEOFDAY_H_
-
-#ifdef WIN32
-
-#include <windows.h>
-
-/*
- * the function gettimeofday() is available on UNIX but not on windows.
- * this header defines a windows implementation as a
- * GetSystemTimeAsFileTime() wrapper.
- */
-
-int gettimeofday(struct timeval* tv, void *tz)
-/*---------------------------------------------------------------
- * Copyright (c) 1999,2000,2001,2002,2003
- * The Board of Trustees of the University of Illinois
- * All Rights Reserved.
- *---------------------------------------------------------------
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software (Iperf) and associated
- * documentation files (the "Software"), to deal in the Software
- * without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute,
- * sublicense, and/or sell copies of the Software, and to permit
- * persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- *
- * Redistributions of source code must retain the above
- * copyright notice, this list of conditions and
- * the following disclaimers.
- *
- *
- * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimers in the documentation and/or other materials
- * provided with the distribution.
- *
- *
- * Neither the names of the University of Illinois, NCSA,
- * nor the names of its contributors may be used to endorse
- * or promote products derived from this Software without
- * specific prior written permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- * ________________________________________________________________
- * National Laboratory for Applied Network Research
- * National Center for Supercomputing Applications
- * University of Illinois at Urbana-Champaign
- * http://www.ncsa.uiuc.edu
- * ________________________________________________________________
- *
- * gettimeofday.c
- * by Mark Gates <mgates@nlanr.net>
- * -------------------------------------------------------------------
- * A (hack) implementation of gettimeofday for Windows.
- * Since I send sec/usec in UDP packets, this made the most sense.
- * ------------------------------------------------------------------- */
-{
- FILETIME time;
- double timed;
-
- GetSystemTimeAsFileTime( &time );
-
- // Apparently Win32 has units of 1e-7 sec (tenths of microsecs)
- // 4294967296 is 2^32, to shift high word over
- // 11644473600 is the number of seconds between
- // the Win32 epoch 1601-Jan-01 and the Unix epoch 1970-Jan-01
- // Tests found floating point to be 10x faster than 64bit int math.
-
- timed = ((time.dwHighDateTime * 4294967296e-7) - 11644473600.0) +
- (time.dwLowDateTime * 1e-7);
-
- tv->tv_sec = (long) timed;
- tv->tv_usec = (long) ((timed - tv->tv_sec) * 1e6);
-
- return 0;
-}
-
-
-#endif // WIN32
-#endif
+/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMW_WINGETTIMEOFDAY_H_ +#define _TMW_WINGETTIMEOFDAY_H_ + +#ifdef WIN32 + +#include <windows.h> + +/* + * the function gettimeofday() is available on UNIX but not on windows. + * this header defines a windows implementation as a + * GetSystemTimeAsFileTime() wrapper. + */ + +int gettimeofday(struct timeval* tv, void *tz) +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) and associated + * documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * + * gettimeofday.c + * by Mark Gates <mgates@nlanr.net> + * ------------------------------------------------------------------- + * A (hack) implementation of gettimeofday for Windows. + * Since I send sec/usec in UDP packets, this made the most sense. + * ------------------------------------------------------------------- */ +{ + FILETIME time; + double timed; + + GetSystemTimeAsFileTime( &time ); + + // Apparently Win32 has units of 1e-7 sec (tenths of microsecs) + // 4294967296 is 2^32, to shift high word over + // 11644473600 is the number of seconds between + // the Win32 epoch 1601-Jan-01 and the Unix epoch 1970-Jan-01 + // Tests found floating point to be 10x faster than 64bit int math. + + timed = ((time.dwHighDateTime * 4294967296e-7) - 11644473600.0) + + (time.dwLowDateTime * 1e-7); + + tv->tv_sec = (long) timed; + tv->tv_usec = (long) ((timed - tv->tv_sec) * 1e6); + + return 0; +} + + +#endif // WIN32 +#endif diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp index 7c917dc0..e30450f0 100644 --- a/src/utils/xml.cpp +++ b/src/utils/xml.cpp @@ -39,6 +39,20 @@ namespace XML return ret; } + double + getFloatProperty(xmlNodePtr node, const char* name, double def) + { + double &ret = def; + + xmlChar *prop = xmlGetProp(node, BAD_CAST name); + if (prop) { + ret = atof((char*)prop); + xmlFree(prop); + } + + return ret; + } + std::string getProperty(xmlNodePtr node, const char *name, const std::string &def) { @@ -51,4 +65,13 @@ namespace XML return def; } + + xmlNodePtr findFirstChildByName(xmlNodePtr parent, const char *name) + { + for_each_xml_child_node(child, parent) + if (xmlStrEqual(child->name, BAD_CAST name)) + return child; + + return NULL; + } } diff --git a/src/utils/xml.h b/src/utils/xml.h index db4c264a..ef3bad3d 100644 --- a/src/utils/xml.h +++ b/src/utils/xml.h @@ -40,10 +40,21 @@ namespace XML getProperty(xmlNodePtr node, const char *name, int def); /** + * Gets an floating point property from an xmlNodePtr. + */ + double + getFloatProperty(xmlNodePtr node, const char *name, double def); + + /** * Gets a string property from an xmlNodePtr. */ std::string getProperty(xmlNodePtr node, const char *name, const std::string &def); + + /** + * Finds the first child node with the given name + */ + xmlNodePtr findFirstChildByName(xmlNodePtr parent, const char *name); } #define for_each_xml_child_node(var, parent) \ |