~ubuntu-branches/ubuntu/trusty/manaplus/trusty-proposed

« back to all changes in this revision

Viewing changes to src/particle/particleemitter.cpp

  • Committer: Package Import Robot
  • Author(s): Patrick Matthäi
  • Date: 2013-09-17 10:35:51 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20130917103551-az7p3nz9jgxwqjfn
Tags: 1.3.9.15-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-2013  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 "particle/particleemitter.h"
 
24
 
 
25
#include "logger.h"
 
26
 
 
27
#include "particle/animationparticle.h"
 
28
#include "particle/rotationalparticle.h"
 
29
 
 
30
#include "resources/dye.h"
 
31
#include "resources/image.h"
 
32
#include "resources/imageset.h"
 
33
#include "resources/resourcemanager.h"
 
34
 
 
35
#include <cmath>
 
36
 
 
37
#include "debug.h"
 
38
 
 
39
static const float SIN45 = 0.707106781f;
 
40
static const float DEG_RAD_FACTOR = 0.017453293f;
 
41
 
 
42
typedef std::vector<ImageSet*>::const_iterator ImageSetVectorCIter;
 
43
typedef std::list<ParticleEmitter>::const_iterator ParticleEmitterListCIter;
 
44
 
 
45
ParticleEmitter::ParticleEmitter(const XmlNodePtr emitterNode,
 
46
                                 Particle *const target,
 
47
                                 Map *const map, const int rotation,
 
48
                                 const std::string& dyePalettes) :
 
49
    mParticleTarget(target),
 
50
    mMap(map),
 
51
    mParticleImage(nullptr),
 
52
    mOutputPauseLeft(0),
 
53
    mDeathEffectConditions(0),
 
54
    mParticleFollow(false)
 
55
{
 
56
    // Initializing default values
 
57
    mParticlePosX.set(0.0f);
 
58
    mParticlePosY.set(0.0f);
 
59
    mParticlePosZ.set(0.0f);
 
60
    mParticleAngleHorizontal.set(0.0f);
 
61
    mParticleAngleVertical.set(0.0f);
 
62
    mParticlePower.set(0.0f);
 
63
    mParticleGravity.set(0.0f);
 
64
    mParticleRandomness.set(0);
 
65
    mParticleBounce.set(0.0f);
 
66
    mParticleAcceleration.set(0.0f);
 
67
    mParticleDieDistance.set(-1.0f);
 
68
    mParticleMomentum.set(1.0f);
 
69
    mParticleLifetime.set(-1);
 
70
    mParticleFadeOut.set(0);
 
71
    mParticleFadeIn.set(0);
 
72
    mOutput.set(1);
 
73
    mOutputPause.set(0);
 
74
    mParticleAlpha.set(1.0f);
 
75
 
 
76
    for_each_xml_child_node(propertyNode, emitterNode)
 
77
    {
 
78
        if (xmlNameEqual(propertyNode, "property"))
 
79
        {
 
80
            const std::string name = XML::getProperty(
 
81
                propertyNode, "name", "");
 
82
 
 
83
            if (name == "position-x")
 
84
            {
 
85
                mParticlePosX = readParticleEmitterProp(propertyNode, 0.0f);
 
86
            }
 
87
            else if (name == "position-y")
 
88
            {
 
89
                mParticlePosY = readParticleEmitterProp(propertyNode, 0.0f);
 
90
                mParticlePosY.minVal *= SIN45;
 
91
                mParticlePosY.maxVal *= SIN45;
 
92
                mParticlePosY.changeAmplitude *= SIN45;
 
93
            }
 
94
            else if (name == "position-z")
 
95
            {
 
96
                mParticlePosZ = readParticleEmitterProp(propertyNode, 0.0f);
 
97
                mParticlePosZ.minVal *= SIN45;
 
98
                mParticlePosZ.maxVal *= SIN45;
 
99
                mParticlePosZ.changeAmplitude *= SIN45;
 
100
            }
 
101
            else if (name == "image")
 
102
            {
 
103
                std::string image = XML::getProperty(
 
104
                    propertyNode, "value", "");
 
105
                // Don't leak when multiple images are defined
 
106
                if (!image.empty() && !mParticleImage)
 
107
                {
 
108
                    if (!dyePalettes.empty())
 
109
                        Dye::instantiate(image, dyePalettes);
 
110
 
 
111
                    ResourceManager *const resman
 
112
                        = ResourceManager::getInstance();
 
113
                    mParticleImage = resman->getImage(image);
 
114
                }
 
115
            }
 
116
            else if (name == "subimage")
 
117
            {
 
118
                std::string image = XML::getProperty(
 
119
                    propertyNode, "value", "");
 
120
                // Don't leak when multiple images are defined
 
121
                if (!image.empty() && !mParticleImage)
 
122
                {
 
123
                    if (!dyePalettes.empty())
 
124
                        Dye::instantiate(image, dyePalettes);
 
125
 
 
126
                    ResourceManager *const resman
 
127
                        = ResourceManager::getInstance();
 
128
                    Image *img = resman->getImage(image);
 
129
                    if (img)
 
130
                    {
 
131
                        mParticleImage = resman->getSubImage(img,
 
132
                            XML::getProperty(propertyNode, "x", 0),
 
133
                            XML::getProperty(propertyNode, "y", 0),
 
134
                            XML::getProperty(propertyNode, "width", 0),
 
135
                            XML::getProperty(propertyNode, "height", 0));
 
136
                        img->decRef();
 
137
                    }
 
138
                    else
 
139
                    {
 
140
                        mParticleImage = nullptr;
 
141
                    }
 
142
                }
 
143
            }
 
144
            else if (name == "horizontal-angle")
 
145
            {
 
146
                mParticleAngleHorizontal =
 
147
                    readParticleEmitterProp(propertyNode, 0.0f);
 
148
                mParticleAngleHorizontal.minVal
 
149
                    += static_cast<float>(rotation);
 
150
                mParticleAngleHorizontal.minVal *= DEG_RAD_FACTOR;
 
151
                mParticleAngleHorizontal.maxVal
 
152
                    += static_cast<float>(rotation);
 
153
                mParticleAngleHorizontal.maxVal *= DEG_RAD_FACTOR;
 
154
                mParticleAngleHorizontal.changeAmplitude *= DEG_RAD_FACTOR;
 
155
            }
 
156
            else if (name == "vertical-angle")
 
157
            {
 
158
                mParticleAngleVertical =
 
159
                    readParticleEmitterProp(propertyNode, 0.0f);
 
160
                mParticleAngleVertical.minVal *= DEG_RAD_FACTOR;
 
161
                mParticleAngleVertical.maxVal *= DEG_RAD_FACTOR;
 
162
                mParticleAngleVertical.changeAmplitude *= DEG_RAD_FACTOR;
 
163
            }
 
164
            else if (name == "power")
 
165
            {
 
166
                mParticlePower = readParticleEmitterProp(propertyNode, 0.0f);
 
167
            }
 
168
            else if (name == "gravity")
 
169
            {
 
170
                mParticleGravity = readParticleEmitterProp(propertyNode, 0.0f);
 
171
            }
 
172
            else if (name == "randomnes"
 
173
                     || name == "randomness")  // legacy bug
 
174
            {
 
175
                mParticleRandomness = readParticleEmitterProp(propertyNode, 0);
 
176
            }
 
177
            else if (name == "bounce")
 
178
            {
 
179
                mParticleBounce = readParticleEmitterProp(propertyNode, 0.0f);
 
180
            }
 
181
            else if (name == "lifetime")
 
182
            {
 
183
                mParticleLifetime = readParticleEmitterProp(propertyNode, 0);
 
184
                mParticleLifetime.minVal += 1;
 
185
            }
 
186
            else if (name == "output")
 
187
            {
 
188
                mOutput = readParticleEmitterProp(propertyNode, 0);
 
189
                mOutput.maxVal += 1;
 
190
            }
 
191
            else if (name == "output-pause")
 
192
            {
 
193
                mOutputPause = readParticleEmitterProp(propertyNode, 0);
 
194
                mOutputPauseLeft = mOutputPause.value(0);
 
195
            }
 
196
            else if (name == "acceleration")
 
197
            {
 
198
                mParticleAcceleration = readParticleEmitterProp(
 
199
                    propertyNode, 0.0f);
 
200
            }
 
201
            else if (name == "die-distance")
 
202
            {
 
203
                mParticleDieDistance = readParticleEmitterProp(
 
204
                    propertyNode, 0.0f);
 
205
            }
 
206
            else if (name == "momentum")
 
207
            {
 
208
                mParticleMomentum = readParticleEmitterProp(
 
209
                    propertyNode, 1.0f);
 
210
            }
 
211
            else if (name == "fade-out")
 
212
            {
 
213
                mParticleFadeOut = readParticleEmitterProp(propertyNode, 0);
 
214
            }
 
215
            else if (name == "fade-in")
 
216
            {
 
217
                mParticleFadeIn = readParticleEmitterProp(propertyNode, 0);
 
218
            }
 
219
            else if (name == "alpha")
 
220
            {
 
221
                mParticleAlpha = readParticleEmitterProp(propertyNode, 1.0f);
 
222
            }
 
223
            else if (name == "follow-parent")
 
224
            {
 
225
                mParticleFollow = true;
 
226
            }
 
227
            else
 
228
            {
 
229
                logger->log("Particle Engine: Warning, "
 
230
                            "unknown emitter property \"%s\"",
 
231
                            name.c_str());
 
232
            }
 
233
        }
 
234
        else if (xmlNameEqual(propertyNode, "emitter"))
 
235
        {
 
236
            ParticleEmitter newEmitter(propertyNode, mParticleTarget, map,
 
237
                                       rotation, dyePalettes);
 
238
            mParticleChildEmitters.push_back(newEmitter);
 
239
        }
 
240
        else if (xmlNameEqual(propertyNode, "rotation"))
 
241
        {
 
242
            ImageSet *const imageset = getImageSet(propertyNode);
 
243
            if (!imageset)
 
244
            {
 
245
                logger->log1("Error: no valid imageset");
 
246
                continue;
 
247
            }
 
248
            mTempSets.push_back(imageset);
 
249
 
 
250
            // Get animation frames
 
251
            for_each_xml_child_node(frameNode, propertyNode)
 
252
            {
 
253
                const int delay = XML::getIntProperty(
 
254
                    frameNode, "delay", 0, 0, 100000);
 
255
                const int offsetX = XML::getProperty(frameNode, "offsetX", 0)
 
256
                    - imageset->getWidth() / 2 + 16;
 
257
                const int offsetY = XML::getProperty(frameNode, "offsetY", 0)
 
258
                    - imageset->getHeight() + 32;
 
259
                const int rand = XML::getIntProperty(
 
260
                    frameNode, "rand", 100, 0, 100);
 
261
 
 
262
                if (xmlNameEqual(frameNode, "frame"))
 
263
                {
 
264
                    const int index = XML::getProperty(frameNode, "index", -1);
 
265
 
 
266
                    if (index < 0)
 
267
                    {
 
268
                        logger->log1("No valid value for 'index'");
 
269
                        continue;
 
270
                    }
 
271
 
 
272
                    Image *const img = imageset->get(index);
 
273
 
 
274
                    if (!img)
 
275
                    {
 
276
                        logger->log("No image at index %d", index);
 
277
                        continue;
 
278
                    }
 
279
 
 
280
                    mParticleRotation.addFrame(img, delay,
 
281
                        offsetX, offsetY, rand);
 
282
                }
 
283
                else if (xmlNameEqual(frameNode, "sequence"))
 
284
                {
 
285
                    int start = XML::getProperty(frameNode, "start", -1);
 
286
                    const int end = XML::getProperty(frameNode, "end", -1);
 
287
 
 
288
                    if (start < 0 || end < 0)
 
289
                    {
 
290
                        logger->log1("No valid value for 'start' or 'end'");
 
291
                        continue;
 
292
                    }
 
293
 
 
294
                    while (end >= start)
 
295
                    {
 
296
                        Image *const img = imageset->get(start);
 
297
                        if (!img)
 
298
                        {
 
299
                            logger->log("No image at index %d", start);
 
300
                            continue;
 
301
                        }
 
302
 
 
303
                        mParticleRotation.addFrame(img, delay,
 
304
                            offsetX, offsetY, rand);
 
305
                        start ++;
 
306
                    }
 
307
                }
 
308
                else if (xmlNameEqual(frameNode, "end"))
 
309
                {
 
310
                    mParticleRotation.addTerminator(rand);
 
311
                }
 
312
            }  // for frameNode
 
313
        }
 
314
        else if (xmlNameEqual(propertyNode, "animation"))
 
315
        {
 
316
            ImageSet *const imageset = getImageSet(propertyNode);
 
317
            if (!imageset)
 
318
            {
 
319
                logger->log1("Error: no valid imageset");
 
320
                continue;
 
321
            }
 
322
            mTempSets.push_back(imageset);
 
323
 
 
324
            // Get animation frames
 
325
            for_each_xml_child_node(frameNode, propertyNode)
 
326
            {
 
327
                const int delay = XML::getIntProperty(
 
328
                    frameNode, "delay", 0, 0, 100000);
 
329
                const int offsetX = XML::getProperty(frameNode, "offsetX", 0)
 
330
                    - imageset->getWidth() / 2 + 16;
 
331
                const int offsetY = XML::getProperty(frameNode, "offsetY", 0)
 
332
                    - imageset->getHeight() + 32;
 
333
                const int rand = XML::getIntProperty(
 
334
                    frameNode, "rand", 100, 0, 100);
 
335
 
 
336
                if (xmlNameEqual(frameNode, "frame"))
 
337
                {
 
338
                    const int index = XML::getProperty(frameNode, "index", -1);
 
339
                    if (index < 0)
 
340
                    {
 
341
                        logger->log1("No valid value for 'index'");
 
342
                        continue;
 
343
                    }
 
344
 
 
345
                    Image *const img = imageset->get(index);
 
346
 
 
347
                    if (!img)
 
348
                    {
 
349
                        logger->log("No image at index %d", index);
 
350
                        continue;
 
351
                    }
 
352
 
 
353
                    mParticleAnimation.addFrame(img, delay,
 
354
                        offsetX, offsetY, rand);
 
355
                }
 
356
                else if (xmlNameEqual(frameNode, "sequence"))
 
357
                {
 
358
                    int start = XML::getProperty(frameNode, "start", -1);
 
359
                    const int end = XML::getProperty(frameNode, "end", -1);
 
360
 
 
361
                    if (start < 0 || end < 0)
 
362
                    {
 
363
                        logger->log1("No valid value for 'start' or 'end'");
 
364
                        continue;
 
365
                    }
 
366
 
 
367
                    while (end >= start)
 
368
                    {
 
369
                        Image *const img = imageset->get(start);
 
370
 
 
371
                        if (!img)
 
372
                        {
 
373
                            logger->log("No image at index %d", start);
 
374
                            continue;
 
375
                        }
 
376
 
 
377
                        mParticleAnimation.addFrame(img, delay,
 
378
                            offsetX, offsetY, rand);
 
379
                        start++;
 
380
                    }
 
381
                }
 
382
                else if (xmlNameEqual(frameNode, "end"))
 
383
                {
 
384
                    mParticleAnimation.addTerminator(rand);
 
385
                }
 
386
            }  // for frameNode
 
387
        }
 
388
        else if (xmlNameEqual(propertyNode, "deatheffect"))
 
389
        {
 
390
            mDeathEffect = reinterpret_cast<const char*>(
 
391
                propertyNode->xmlChildrenNode->content);
 
392
            mDeathEffectConditions = 0x00;
 
393
            if (XML::getBoolProperty(propertyNode, "on-floor", true))
 
394
            {
 
395
                mDeathEffectConditions += static_cast<signed char>(
 
396
                    Particle::DEAD_FLOOR);
 
397
            }
 
398
            if (XML::getBoolProperty(propertyNode, "on-sky", true))
 
399
            {
 
400
                mDeathEffectConditions += static_cast<signed char>(
 
401
                    Particle::DEAD_SKY);
 
402
            }
 
403
            if (XML::getBoolProperty(propertyNode, "on-other", false))
 
404
            {
 
405
                mDeathEffectConditions += static_cast<signed char>(
 
406
                    Particle::DEAD_OTHER);
 
407
            }
 
408
            if (XML::getBoolProperty(propertyNode, "on-impact", true))
 
409
            {
 
410
                mDeathEffectConditions += static_cast<signed char>(
 
411
                    Particle::DEAD_IMPACT);
 
412
            }
 
413
            if (XML::getBoolProperty(propertyNode, "on-timeout", true))
 
414
            {
 
415
                mDeathEffectConditions += static_cast<signed char>(
 
416
                    Particle::DEAD_TIMEOUT);
 
417
            }
 
418
        }
 
419
    }
 
420
}
 
421
 
 
422
ParticleEmitter::ParticleEmitter(const ParticleEmitter &o)
 
423
{
 
424
    *this = o;
 
425
}
 
426
 
 
427
ImageSet *ParticleEmitter::getImageSet(XmlNodePtr node)
 
428
{
 
429
    ResourceManager *const resman = ResourceManager::getInstance();
 
430
    ImageSet *imageset = nullptr;
 
431
    const int subX = XML::getProperty(node, "subX", -1);
 
432
    if (subX != -1)
 
433
    {
 
434
        Image *const img = resman->getImage(XML::getProperty(
 
435
            node, "imageset", ""));
 
436
        if (!img)
 
437
            return nullptr;
 
438
 
 
439
        Image *const img2 = resman->getSubImage(img, subX,
 
440
            XML::getProperty(node, "subY", 0),
 
441
            XML::getProperty(node, "subWidth", 0),
 
442
            XML::getProperty(node, "subHeight", 0));
 
443
        if (!img2)
 
444
        {
 
445
            img->decRef();
 
446
            return nullptr;
 
447
        }
 
448
 
 
449
        imageset = resman->getSubImageSet(img2,
 
450
            XML::getProperty(node, "width", 0),
 
451
            XML::getProperty(node, "height", 0));
 
452
        img2->decRef();
 
453
        img->decRef();
 
454
    }
 
455
    else
 
456
    {
 
457
        imageset = resman->getImageSet(
 
458
            XML::getProperty(node, "imageset", ""),
 
459
            XML::getProperty(node, "width", 0),
 
460
            XML::getProperty(node, "height", 0));
 
461
    }
 
462
    return imageset;
 
463
}
 
464
 
 
465
ParticleEmitter & ParticleEmitter::operator=(const ParticleEmitter &o)
 
466
{
 
467
    mParticlePosX = o.mParticlePosX;
 
468
    mParticlePosY = o.mParticlePosY;
 
469
    mParticlePosZ = o.mParticlePosZ;
 
470
    mParticleAngleHorizontal = o.mParticleAngleHorizontal;
 
471
    mParticleAngleVertical = o.mParticleAngleVertical;
 
472
    mParticlePower = o.mParticlePower;
 
473
    mParticleGravity = o.mParticleGravity;
 
474
    mParticleRandomness = o.mParticleRandomness;
 
475
    mParticleBounce = o.mParticleBounce;
 
476
    mParticleFollow = o.mParticleFollow;
 
477
    mParticleTarget = o.mParticleTarget;
 
478
    mParticleAcceleration = o.mParticleAcceleration;
 
479
    mParticleDieDistance = o.mParticleDieDistance;
 
480
    mParticleMomentum = o.mParticleMomentum;
 
481
    mParticleLifetime = o.mParticleLifetime;
 
482
    mParticleFadeOut = o.mParticleFadeOut;
 
483
    mParticleFadeIn = o.mParticleFadeIn;
 
484
    mParticleAlpha = o.mParticleAlpha;
 
485
    mMap = o.mMap;
 
486
    mOutput = o.mOutput;
 
487
    mOutputPause = o.mOutputPause;
 
488
    mParticleImage = o.mParticleImage;
 
489
    mParticleAnimation = o.mParticleAnimation;
 
490
    mParticleRotation = o.mParticleRotation;
 
491
    mParticleChildEmitters = o.mParticleChildEmitters;
 
492
    mDeathEffectConditions = o.mDeathEffectConditions;
 
493
    mDeathEffect = o.mDeathEffect;
 
494
    mTempSets = o.mTempSets;
 
495
 
 
496
    FOR_EACH (ImageSetVectorCIter, i, mTempSets)
 
497
    {
 
498
        if (*i)
 
499
            (*i)->incRef();
 
500
    }
 
501
 
 
502
    mOutputPauseLeft = 0;
 
503
 
 
504
    if (mParticleImage)
 
505
        mParticleImage->incRef();
 
506
 
 
507
    return *this;
 
508
}
 
509
 
 
510
ParticleEmitter::~ParticleEmitter()
 
511
{
 
512
    FOR_EACH (ImageSetVectorCIter, i, mTempSets)
 
513
    {
 
514
        if (*i)
 
515
            (*i)->decRef();
 
516
    }
 
517
    mTempSets.clear();
 
518
 
 
519
    if (mParticleImage)
 
520
    {
 
521
        mParticleImage->decRef();
 
522
        mParticleImage = nullptr;
 
523
    }
 
524
}
 
525
 
 
526
template <typename T> ParticleEmitterProp<T>
 
527
ParticleEmitter::readParticleEmitterProp(XmlNodePtr propertyNode, T def)
 
528
{
 
529
    ParticleEmitterProp<T> retval;
 
530
 
 
531
    def = static_cast<T>(XML::getFloatProperty(propertyNode, "value",
 
532
        static_cast<double>(def)));
 
533
    retval.set(static_cast<T>(XML::getFloatProperty(propertyNode, "min",
 
534
        static_cast<double>(def))), static_cast<T>(XML::getFloatProperty(
 
535
        propertyNode, "max", static_cast<double>(def))));
 
536
 
 
537
    const std::string change = XML::getProperty(
 
538
        propertyNode, "change-func", "none");
 
539
    T amplitude = static_cast<T>(XML::getFloatProperty(propertyNode,
 
540
        "change-amplitude", 0.0));
 
541
 
 
542
    const int period = XML::getProperty(propertyNode, "change-period", 0);
 
543
    const int phase = XML::getProperty(propertyNode, "change-phase", 0);
 
544
    if (change == "saw" || change == "sawtooth")
 
545
        retval.setFunction(FUNC_SAW, amplitude, period, phase);
 
546
    else if (change == "sine" || change == "sinewave")
 
547
        retval.setFunction(FUNC_SINE, amplitude, period, phase);
 
548
    else if (change == "triangle")
 
549
        retval.setFunction(FUNC_TRIANGLE, amplitude, period, phase);
 
550
    else if (change == "square")
 
551
        retval.setFunction(FUNC_SQUARE, amplitude, period, phase);
 
552
 
 
553
    return retval;
 
554
}
 
555
 
 
556
std::list<Particle *> ParticleEmitter::createParticles(const int tick)
 
557
{
 
558
    std::list<Particle *> newParticles;
 
559
 
 
560
    if (mOutputPauseLeft > 0)
 
561
    {
 
562
        mOutputPauseLeft --;
 
563
        return newParticles;
 
564
    }
 
565
    mOutputPauseLeft = mOutputPause.value(tick);
 
566
 
 
567
    for (int i = mOutput.value(tick); i > 0; i--)
 
568
    {
 
569
        // Limit maximum particles
 
570
        if (Particle::particleCount > Particle::maxCount)
 
571
            break;
 
572
 
 
573
        Particle *newParticle;
 
574
        if (mParticleImage)
 
575
        {
 
576
            const std::string name = mParticleImage->getIdPath();
 
577
            if (ImageParticle::imageParticleCountByName.find(name) ==
 
578
                ImageParticle::imageParticleCountByName.end())
 
579
            {
 
580
                ImageParticle::imageParticleCountByName[name] = 0;
 
581
            }
 
582
 
 
583
            if (ImageParticle::imageParticleCountByName[name] > 200)
 
584
                break;
 
585
 
 
586
            newParticle = new ImageParticle(mMap, mParticleImage);
 
587
        }
 
588
        else if (!mParticleRotation.mFrames.empty())
 
589
        {
 
590
            Animation *const newAnimation = new Animation(mParticleRotation);
 
591
            newParticle = new RotationalParticle(mMap, newAnimation);
 
592
        }
 
593
        else if (!mParticleAnimation.mFrames.empty())
 
594
        {
 
595
            Animation *const newAnimation = new Animation(mParticleAnimation);
 
596
            newParticle = new AnimationParticle(mMap, newAnimation);
 
597
        }
 
598
        else
 
599
        {
 
600
            newParticle = new Particle(mMap);
 
601
        }
 
602
 
 
603
        const Vector position(mParticlePosX.value(tick),
 
604
            mParticlePosY.value(tick),
 
605
            mParticlePosZ.value(tick));
 
606
        newParticle->moveTo(position);
 
607
 
 
608
        const float angleH = mParticleAngleHorizontal.value(tick);
 
609
        const float cosAngleH = cos(angleH);
 
610
        const float sinAngleH = sin(angleH);
 
611
        const float angleV = mParticleAngleVertical.value(tick);
 
612
        const float cosAngleV = cos(angleV);
 
613
        const float sinAngleV = sin(angleV);
 
614
        const float power = mParticlePower.value(tick);
 
615
        newParticle->setVelocity(cosAngleH * cosAngleV * power,
 
616
            sinAngleH * cosAngleV * power,
 
617
            sinAngleV * power);
 
618
 
 
619
        newParticle->setRandomness(mParticleRandomness.value(tick));
 
620
        newParticle->setGravity(mParticleGravity.value(tick));
 
621
        newParticle->setBounce(mParticleBounce.value(tick));
 
622
        newParticle->setFollow(mParticleFollow);
 
623
 
 
624
        newParticle->setDestination(mParticleTarget,
 
625
            mParticleAcceleration.value(tick),
 
626
            mParticleMomentum.value(tick));
 
627
 
 
628
        newParticle->setDieDistance(mParticleDieDistance.value(tick));
 
629
 
 
630
        newParticle->setLifetime(mParticleLifetime.value(tick));
 
631
        newParticle->setFadeOut(mParticleFadeOut.value(tick));
 
632
        newParticle->setFadeIn(mParticleFadeIn.value(tick));
 
633
        newParticle->setAlpha(mParticleAlpha.value(tick));
 
634
 
 
635
        FOR_EACH (ParticleEmitterListCIter, it,  mParticleChildEmitters)
 
636
            newParticle->addEmitter(new ParticleEmitter(*it));
 
637
 
 
638
        if (!mDeathEffect.empty())
 
639
            newParticle->setDeathEffect(mDeathEffect, mDeathEffectConditions);
 
640
 
 
641
        newParticles.push_back(newParticle);
 
642
    }
 
643
 
 
644
    return newParticles;
 
645
}
 
646
 
 
647
void ParticleEmitter::adjustSize(const int w, const int h)
 
648
{
 
649
    if (w == 0 || h == 0)
 
650
        return;  // new dimensions are illegal
 
651
 
 
652
    // calculate the old rectangle
 
653
    const int oldArea = static_cast<int>(
 
654
        mParticlePosX.maxVal - mParticlePosX.minVal) * static_cast<int>(
 
655
        mParticlePosX.maxVal - mParticlePosY.minVal);
 
656
    if (oldArea == 0)
 
657
    {
 
658
        // when the effect has no dimension it is
 
659
        // not designed to be resizeable
 
660
        return;
 
661
    }
 
662
 
 
663
    // set the new dimensions
 
664
    mParticlePosX.set(0, static_cast<float>(w));
 
665
    mParticlePosY.set(0, static_cast<float>(h));
 
666
    const int newArea = w * h;
 
667
    // adjust the output so that the particle density stays the same
 
668
    const float outputFactor = static_cast<float>(newArea)
 
669
        / static_cast<float>(oldArea);
 
670
    mOutput.minVal = static_cast<int>(static_cast<float>(
 
671
        mOutput.minVal) * outputFactor);
 
672
    mOutput.maxVal = static_cast<int>(static_cast<float>(
 
673
        mOutput.maxVal) * outputFactor);
 
674
}