ManaPlus
particleengine.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2006-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2018 The ManaPlus Developers
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "configuration.h"
24 
25 #include "gui/viewport.h"
26 
30 #include "particle/textparticle.h"
31 
32 #include "resources/dye/dye.h"
33 
36 
37 #include "utils/dtor.h"
38 
39 #include "debug.h"
40 
42 
43 class Image;
44 
49 bool ParticleEngine::enabled = true;
50 const float ParticleEngine::PARTICLE_SKY = 800.0F;
51 
53  mChildParticles(),
54  mChildMoveParticles(),
55  mMap(nullptr)
56 {
58 }
59 
61 {
62  // Delete child emitters and child particles
63  clear();
65 }
66 
68 {
69  ParticleEngine::maxCount = config.getIntValue("particleMaxCount");
71  "particleFastPhysics"),
74  config.getIntValue("particleEmitterSkip") + 1;
75  if (ParticleEngine::emitterSkip == 0)
76  ParticleEngine::emitterSkip = 1;
77  ParticleEngine::enabled = config.getBoolValue("particleeffects");
78  logger->log1("Particle engine set up");
79 }
80 
82 {
83  if (mChildParticles.empty() || (mMap == nullptr))
84  return true;
85 
86  // Update child particles
87 
88  const int cameraX = viewport->getCameraX();
89  const int cameraY = viewport->getCameraY();
90  const float x1 = static_cast<float>(cameraX - 3000);
91  const float y1 = static_cast<float>(cameraY - 2000);
92  const float x2 = static_cast<float>(cameraX + 3000);
93  const float y2 = static_cast<float>(cameraY + 2000);
94 
95  for (ParticleIterator p = mChildParticles.begin(),
96  fp2 = mChildParticles.end(); p != fp2; )
97  {
98  Particle *restrict const particle = *p;
99  const float posX = particle->mPos.x;
100  const float posY = particle->mPos.y;
101  if (posX < x1 || posX > x2 || posY < y1 || posY > y2)
102  {
103  ++p;
104  continue;
105  }
106  // update particle
107  if (particle->update())
108  {
109  ++p;
110  }
111  else
112  {
113  mChildMoveParticles.remove(*p);
114  delete particle;
115  p = mChildParticles.erase(p);
116  }
117  }
118  return true;
119 }
120 
122 {
123  Particle *const newParticle = new Particle;
124  newParticle->setMap(mMap);
125  mChildParticles.push_back(newParticle);
126  return newParticle;
127 }
128 
130  particleEffectFile,
131  const int pixelX,
132  const int pixelY,
133  const int rotation) restrict2
134 {
135  Particle *newParticle = nullptr;
136 
137  const size_t pos = particleEffectFile.find('|');
138  const std::string dyePalettes = (pos != std::string::npos)
139  ? particleEffectFile.substr(pos + 1) : "";
141  particleEffectFile.substr(0, pos),
144  if (doc == nullptr)
145  return nullptr;
146 
147  XmlNodeConstPtrConst rootNode = doc->rootNode();
148 
149  if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "effect"))
150  {
151  logger->log("Error loading particle: %s", particleEffectFile.c_str());
152  doc->decRef();
153  return nullptr;
154  }
155 
156  // Parse particles
157  for_each_xml_child_node(effectChildNode, rootNode)
158  {
159  // We're only interested in particles
160  if (!xmlNameEqual(effectChildNode, "particle"))
161  continue;
162 
163  // Determine the exact particle type
164  XmlNodePtr node;
165 
166  // Animation
167  if ((node = XML::findFirstChildByName(effectChildNode, "animation")) !=
168  nullptr)
169  {
170  newParticle = new AnimationParticle(node, dyePalettes);
171  newParticle->setMap(mMap);
172  }
173  // Rotational
174  else if ((node = XML::findFirstChildByName(
175  effectChildNode, "rotation")) != nullptr)
176  {
177  newParticle = new RotationalParticle(node, dyePalettes);
178  newParticle->setMap(mMap);
179  }
180  // Image
181  else if ((node = XML::findFirstChildByName(effectChildNode,
182  "image")) != nullptr)
183  {
184  std::string imageSrc;
185  if (XmlHaveChildContent(node))
186  imageSrc = XmlChildContent(node);
187  if (!imageSrc.empty() && !dyePalettes.empty())
188  Dye::instantiate(imageSrc, dyePalettes);
189  Image *const img = Loader::getImage(imageSrc);
190 
191  newParticle = new ImageParticle(img);
192  newParticle->setMap(mMap);
193  }
194  // Other
195  else
196  {
197  newParticle = new Particle;
198  newParticle->setMap(mMap);
199  }
200 
201  // Read and set the basic properties of the particle
202  const float offsetX = XML::getFloatProperty(
203  effectChildNode, "position-x", 0);
204  const float offsetY = XML::getFloatProperty(
205  effectChildNode, "position-y", 0);
206  const float offsetZ = XML::getFloatProperty(
207  effectChildNode, "position-z", 0);
208  const Vector position(static_cast<float>(pixelX) + offsetX,
209  static_cast<float>(pixelY) + offsetY,
210  offsetZ);
211  newParticle->moveTo(position);
212 
213  const int lifetime = XML::getProperty(effectChildNode, "lifetime", -1);
214  newParticle->setLifetime(lifetime);
215  const bool resizeable = "false" != XML::getProperty(effectChildNode,
216  "size-adjustable", "false");
217 
218  newParticle->setAllowSizeAdjust(resizeable);
219 
220  // Look for additional emitters for this particle
221  for_each_xml_child_node(emitterNode, effectChildNode)
222  {
223  if (xmlNameEqual(emitterNode, "emitter"))
224  {
225  ParticleEmitter *restrict const newEmitter =
226  new ParticleEmitter(
227  emitterNode,
228  newParticle,
229  mMap,
230  rotation,
231  dyePalettes);
232  newParticle->addEmitter(newEmitter);
233  }
234  else if (xmlNameEqual(emitterNode, "deatheffect"))
235  {
236  std::string deathEffect;
237  if ((node != nullptr) && XmlHaveChildContent(node))
238  deathEffect = XmlChildContent(emitterNode);
239 
240  char deathEffectConditions = 0x00;
241  if (XML::getBoolProperty(emitterNode, "on-floor", true))
242  {
243  deathEffectConditions += CAST_S8(
245  }
246  if (XML::getBoolProperty(emitterNode, "on-sky", true))
247  {
248  deathEffectConditions += CAST_S8(
250  }
251  if (XML::getBoolProperty(emitterNode, "on-other", false))
252  {
253  deathEffectConditions += CAST_S8(
255  }
256  if (XML::getBoolProperty(emitterNode, "on-impact", true))
257  {
258  deathEffectConditions += CAST_S8(
260  }
261  if (XML::getBoolProperty(emitterNode, "on-timeout", true))
262  {
263  deathEffectConditions += CAST_S8(
265  }
266  newParticle->setDeathEffect(
267  deathEffect, deathEffectConditions);
268  }
269  }
270 
271  mChildParticles.push_back(newParticle);
272  }
273 
274  doc->decRef();
275  return newParticle;
276 }
277 
279  const int x,
280  const int y,
281  const Color *restrict const
282  color,
283  Font *restrict const font,
284  const bool outline) restrict2
285 {
286  Particle *const newParticle = new TextParticle(
287  text,
288  color,
289  font,
290  outline);
291  newParticle->setMap(mMap);
292  newParticle->moveTo(static_cast<float>(x),
293  static_cast<float>(y));
294  newParticle->setVelocity(
295  static_cast<float>((rand() % 100) - 50) / 200.0F, // X
296  static_cast<float>((rand() % 100) - 50) / 200.0F, // Y
297  (static_cast<float>((rand() % 100)) / 200.0F) + 4.0F); // Z
298 
299  newParticle->setGravity(0.1F);
300  newParticle->setBounce(0.5F);
301  newParticle->setLifetime(200);
302  newParticle->setFadeOut(100);
303 
304  mChildParticles.push_back(newParticle);
305 
306  return newParticle;
307 }
308 
310  text,
311  const int x,
312  const int y,
313  const Color *restrict const
314  color,
315  Font *restrict const font,
316  const bool outline)
317  restrict2
318 {
319  Particle *const newParticle = new TextParticle(
320  text,
321  color,
322  font,
323  outline);
324  newParticle->setMap(mMap);
325  newParticle->moveTo(static_cast<float>(x),
326  static_cast<float>(y));
327  newParticle->setVelocity(0.0F, 0.0F, 0.5F);
328  newParticle->setGravity(0.0015F);
329  newParticle->setLifetime(300);
330  newParticle->setFadeOut(100);
331  newParticle->setFadeIn(0);
332 
333  mChildParticles.push_back(newParticle);
334 
335  return newParticle;
336 }
337 
339 {
341  mChildParticles.clear();
342  mChildMoveParticles.clear();
343 }
static void instantiate(std::string &target, const std::string &palettes)
Definition: dye.cpp:96
static bool enabled
const bool SkipError_false
Definition: skiperror.h:29
void log1(const char *const log_text)
Definition: logger.cpp:233
void setVelocity(const float x, const float y, const float z)
Definition: particle.h:142
float getFloatProperty(const xmlNodePtr node, const char *const name, float def)
Definition: libxml.cpp:210
Particle * addEffect(const std::string &particleEffectFile, const int pixelX, const int pixelY, const int rotation)
Definition: font.h:88
virtual void setDeathEffect(const std::string &effectFile, const signed char conditions)
Definition: particle.h:239
#define fromInt(val, name)
Definition: intdefines.h:45
virtual void decRef()
Definition: resource.cpp:49
Definition: vector.h:38
void setAllowSizeAdjust(const bool adjust)
Definition: particle.h:202
ParticleEngine * particleEngine
Configuration config
int getProperty(const xmlNodePtr node, const char *const name, int def)
Definition: libxml.cpp:173
void setBounce(const float bouncieness)
Definition: particle.h:163
static int emitterSkip
int getIntValue(const std::string &key) const
Particle * addTextRiseFadeOutEffect(const std::string &text, const int x, const int y, const Color *const color, Font *const font, const bool outline)
Particles mChildParticles
Particles mChildMoveParticles
Logger * logger
Definition: logger.cpp:88
static int particleCount
ParticlePhysics ::T ParticlePhysicsT
const bool UseVirtFs_true
Definition: usevirtfs.h:29
bool getBoolValue(const std::string &key) const
void delete_all(Container &c)
Definition: dtor.h:55
Particles::iterator ParticleIterator
void setFadeIn(const int fadeIn)
Definition: particle.h:136
void moveTo(const Vector &pos)
Definition: particle.h:106
xmlNodePtr findFirstChildByName(const xmlNode *const parent, const char *const name)
Definition: libxml.cpp:288
Image * getImage(const std::string &idPath)
Definition: imageloader.cpp:85
static const float PARTICLE_SKY
bool getBoolProperty(const xmlNodePtr node, const char *const name, const bool def)
Definition: libxml.cpp:268
static ParticlePhysicsT fastPhysics
int getCameraY() const
Definition: viewport.h:120
void setFadeOut(const int fadeOut)
Definition: particle.h:129
#define nullptr
Definition: localconsts.h:44
#define CAST_S8
Definition: cast.h:25
virtual void setMap(Map *const map)
Definition: actor.cpp:47
static int maxCount
void setGravity(const float gravity)
Definition: particle.h:150
XML::Document * getXml(const std::string &idPath, const UseVirtFs useResman, const SkipError skipError)
Definition: xmlloader.cpp:55
xmlNodePtr rootNode()
Definition: libxml.cpp:168
int getCameraX() const
Definition: viewport.h:114
#define for_each_xml_child_node(var, parent)
Definition: libxml.h:160
void addEmitter(ParticleEmitter *const emitter)
Definition: particle.h:100
std::string mMap
Definition: gamerecv.cpp:45
Definition: image.h:61
Definition: color.h:74
#define restrict
Definition: localconsts.h:164
void setLifetime(const int lifetime)
Definition: particle.h:122
void log(const char *const log_text,...)
Definition: logger.cpp:264
Particle * addTextSplashEffect(const std::string &text, const int x, const int y, const Color *const color, Font *const font, const bool outline)
#define restrict2
Definition: localconsts.h:165
Viewport * viewport
Definition: viewport.cpp:35
Particle * createChild()