GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/sprite/spritedef.cpp Lines: 198 303 65.3 %
Date: 2017-11-29 Branches: 151 452 33.4 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  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 "resources/sprite/spritedef.h"
24
25
#include "configuration.h"
26
#include "settings.h"
27
28
#include "const/resources/spriteaction.h"
29
30
#include "const/resources/map/map.h"
31
32
#include "utils/checkutils.h"
33
#include "utils/foreach.h"
34
35
#include "resources/action.h"
36
#include "resources/imageset.h"
37
38
#include "resources/animation/animation.h"
39
40
#include "resources/dye/dye.h"
41
42
#include "resources/loaders/imagesetloader.h"
43
#include "resources/loaders/xmlloader.h"
44
45
#include "resources/sprite/spritereference.h"
46
47
#include "debug.h"
48
49
SpriteReference *SpriteReference::Empty = nullptr;
50
51
2316
const Action *SpriteDef::getAction(const std::string &action,
52
                                   const unsigned num) const
53
{
54
4632
    Actions::const_iterator i = mActions.find(num);
55

4632
    if (i == mActions.end() && num != 100)
56
        i = mActions.find(100);
57
58

6948
    if (i == mActions.end() || ((*i).second == nullptr))
59
        return nullptr;
60
61
2316
    const ActionMap *const actMap = (*i).second;
62
    if (actMap == nullptr)
63
        return nullptr;
64
2316
    const ActionMap::const_iterator it = actMap->find(action);
65
66
2316
    if (it == actMap->end())
67
    {
68
        logger->log("Warning: no action \"%s\" defined!", action.c_str());
69
        return nullptr;
70
    }
71
72
2316
    return (*it).second;
73
}
74
75
unsigned SpriteDef::findNumber(const unsigned num) const
76
{
77
    unsigned min = 101;
78
    FOR_EACH (Actions::const_iterator, it, mActions)
79
    {
80
        const unsigned n = (*it).first;
81
        if (n >= num && n < min)
82
            min = n;
83
    }
84
    if (min == 101)
85
        return 0;
86
    return min;
87
}
88
89
2310
SpriteDef *SpriteDef::load(const std::string &animationFile,
90
                           const int variant, const bool prot)
91
{
92
    BLOCK_START("SpriteDef::load")
93
2310
    const size_t pos = animationFile.find('|');
94
4620
    std::string palettes;
95
2310
    if (pos != std::string::npos)
96
        palettes = animationFile.substr(pos + 1);
97
98
4620
    XML::Document *const doc = Loader::getXml(animationFile.substr(0, pos),
99
        UseVirtFs_true,
100
2310
        SkipError_false);
101
2310
    if (doc == nullptr)
102
        return nullptr;
103
2310
    XmlNodePtrConst rootNode = doc->rootNode();
104
105

2310
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "sprite"))
106
    {
107
        reportAlways("Error, failed to parse sprite %s",
108
            animationFile.c_str());
109
        const std::string errorFile = pathJoin(paths.getStringValue("sprites"),
110
            paths.getStringValue("spriteErrorFile"));
111
        BLOCK_END("SpriteDef::load")
112
        doc->decRef();
113
        if (animationFile != errorFile)
114
            return load(errorFile, 0, prot);
115
        return nullptr;
116
    }
117
118

4620
    SpriteDef *const def = new SpriteDef;
119
4620
    def->mSource = animationFile;
120
4620
    def->mProcessedFiles.insert(animationFile);
121
2310
    def->loadSprite(rootNode, variant, palettes);
122
2310
    def->substituteActions();
123
2310
    if (settings.fixDeadAnimation)
124
2310
        def->fixDeadAction();
125
2310
    if (prot)
126
    {
127
        def->incRef();
128
        def->mProtected = true;
129
    }
130
2310
    doc->decRef();
131
    BLOCK_END("SpriteDef::load")
132
    return def;
133
}
134
135
2310
void SpriteDef::fixDeadAction()
136
{
137
6930
    FOR_EACH (ActionsIter, it, mActions)
138
    {
139
2310
        ActionMap *const d = (*it).second;
140
2310
        if (d == nullptr)
141
            continue;
142
2310
        const ActionMap::iterator i = d->find(SpriteAction::DEAD);
143
2310
        const ActionMap::iterator i2 = d->find(SpriteAction::STAND);
144
        // search dead action and check what it not same with stand action
145
4620
        if (i != d->end() &&
146

6930
            i->second != nullptr &&
147
6930
            (i2 == d->end() || i->second != i2->second))
148
        {
149
            (i->second)->setLastFrameDelay(0);
150
        }
151
    }
152
2310
}
153
154
66990
void SpriteDef::substituteAction(const std::string &restrict complete,
155
                                 const std::string &restrict with)
156
{
157
334950
    FOR_EACH (ActionsConstIter, it, mActions)
158
    {
159
66990
        ActionMap *const d = (*it).second;
160

66990
        if (reportTrue(d == nullptr))
161
            continue;
162
133980
        if (d->find(complete) == d->end())
163
        {
164
64676
            const ActionMap::iterator i = d->find(with);
165
64676
            if (i != d->end())
166
64676
                (*d)[complete] = i->second;
167
        }
168
    }
169
66990
}
170
171
2310
void SpriteDef::substituteActions()
172
{
173
2310
    substituteAction(SpriteAction::STAND, SpriteAction::DEFAULT);
174
2310
    substituteAction(SpriteAction::MOVE, SpriteAction::STAND);
175
2310
    substituteAction(SpriteAction::ATTACK, SpriteAction::STAND);
176
2310
    substituteAction(SpriteAction::CAST, SpriteAction::ATTACK);
177
2310
    substituteAction(SpriteAction::SIT, SpriteAction::STAND);
178
2310
    substituteAction(SpriteAction::SITTOP, SpriteAction::SIT);
179
2310
    substituteAction(SpriteAction::DEAD, SpriteAction::STAND);
180
2310
    substituteAction(SpriteAction::SPAWN, SpriteAction::STAND);
181
2310
    substituteAction(SpriteAction::FLY, SpriteAction::MOVE);
182
2310
    substituteAction(SpriteAction::SWIM, SpriteAction::MOVE);
183
2310
    substituteAction(SpriteAction::RIDE, SpriteAction::MOVE);
184
2310
    substituteAction(SpriteAction::STANDSKY, SpriteAction::STAND);
185
2310
    substituteAction(SpriteAction::STANDWATER, SpriteAction::STAND);
186
2310
    substituteAction(SpriteAction::STANDRIDE, SpriteAction::STAND);
187
2310
    substituteAction(SpriteAction::SITSKY, SpriteAction::SIT);
188
2310
    substituteAction(SpriteAction::SITWATER, SpriteAction::SIT);
189
2310
    substituteAction(SpriteAction::SITRIDE, SpriteAction::SIT);
190
2310
    substituteAction(SpriteAction::ATTACKSKY, SpriteAction::ATTACK);
191
2310
    substituteAction(SpriteAction::ATTACKWATER, SpriteAction::ATTACK);
192
2310
    substituteAction(SpriteAction::ATTACKRIDE, SpriteAction::ATTACK);
193
2310
    substituteAction(SpriteAction::CASTSKY, SpriteAction::CAST);
194
2310
    substituteAction(SpriteAction::CASTWATER, SpriteAction::CAST);
195
2310
    substituteAction(SpriteAction::CASTRIDE, SpriteAction::CAST);
196
2310
    substituteAction(SpriteAction::SPAWNSKY, SpriteAction::SPAWN);
197
2310
    substituteAction(SpriteAction::SPAWNWATER, SpriteAction::SPAWN);
198
2310
    substituteAction(SpriteAction::SPAWNRIDE, SpriteAction::SPAWN);
199
2310
    substituteAction(SpriteAction::DEADSKY, SpriteAction::DEAD);
200
2310
    substituteAction(SpriteAction::DEADWATER, SpriteAction::DEAD);
201
2310
    substituteAction(SpriteAction::DEADRIDE, SpriteAction::DEAD);
202
2310
}
203
204
2310
void SpriteDef::loadSprite(XmlNodeConstPtr spriteNode,
205
                           const int variant,
206
                           const std::string &palettes)
207
{
208
    BLOCK_START("SpriteDef::loadSprite")
209
2310
    if (spriteNode == nullptr)
210
    {
211
        BLOCK_END("SpriteDef::loadSprite")
212
        return;
213
    }
214
    // Get the variant
215
2310
    const int variantCount = XML::getProperty(spriteNode, "variants", 0);
216
2310
    int variant_offset = 0;
217
218
2310
    if (variantCount > 0 && variant < variantCount)
219
    {
220
        variant_offset = variant * XML::getProperty(spriteNode,
221
            "variant_offset",
222
            0);
223
    }
224
225
13876
    for_each_xml_child_node(node, spriteNode)
226
    {
227
11566
        if (xmlNameEqual(node, "imageset"))
228
2310
            loadImageSet(node, palettes);
229
9256
        else if (xmlNameEqual(node, "action"))
230
2318
            loadAction(node, variant_offset);
231
6938
        else if (xmlNameEqual(node, "include"))
232
            includeSprite(node, variant);
233
    }
234
    BLOCK_END("SpriteDef::loadSprite")
235
}
236
237
2310
void SpriteDef::loadImageSet(XmlNodeConstPtr node,
238
                             const std::string &palettes)
239
{
240

11550
    const std::string name = XML::getProperty(node, "name", "");
241
242
    // We don't allow redefining image sets. This way, an included sprite
243
    // definition will use the already loaded image set with the same name.
244
6930
    if (mImageSets.find(name) != mImageSets.end())
245
        return;
246
247
2310
    const int width = XML::getProperty(node, "width", 0);
248
2310
    const int height = XML::getProperty(node, "height", 0);
249

11550
    std::string imageSrc = XML::getProperty(node, "src", "");
250
2310
    Dye::instantiate(imageSrc, palettes);
251
252
    ImageSet *const imageSet = Loader::getImageSet(imageSrc,
253
2310
        width, height);
254
255
2310
    if (imageSet == nullptr)
256
    {
257
        reportAlways("%s: Couldn't load imageset: %s",
258
            mSource.c_str(),
259
            imageSrc.c_str());
260
        return;
261
    }
262
263
4620
    imageSet->setOffsetX(XML::getProperty(node, "offsetX", 0));
264
4620
    imageSet->setOffsetY(XML::getProperty(node, "offsetY", 0));
265
2310
    mImageSets[name] = imageSet;
266
}
267
268
2318
const ImageSet *SpriteDef::getImageSet(const std::string &imageSetName) const
269
{
270
4636
    const ImageSetCIterator si = mImageSets.find(imageSetName);
271
4636
    if (si == mImageSets.end())
272
    {
273
        reportAlways("%s: Imageset \"%s\" not defined in %s",
274
            mSource.c_str(),
275
            imageSetName.c_str(),
276
            mIdPath.c_str());
277
        return nullptr;
278
    }
279
2318
    return si->second;
280
}
281
282
2318
void SpriteDef::loadAction(XmlNodeConstPtr node,
283
                           const int variant_offset)
284
{
285
2318
    if (node == nullptr)
286
        return;
287
288

11590
    const std::string actionName = XML::getProperty(node, "name", "");
289

11590
    const std::string imageSetName = XML::getProperty(node, "imageset", "");
290
2318
    const unsigned hp = XML::getProperty(node, "hp", 100);
291
2318
    const ImageSet *const imageSet = getImageSet(imageSetName);
292
293
    if (actionName == SpriteAction::INVALID)
294
    {
295
        reportAlways("%s: Unknown action \"%s\" defined in %s",
296
            mSource.c_str(),
297
            actionName.c_str(),
298
            mIdPath.c_str());
299
        return;
300
    }
301
2318
    Action *const action = new Action(actionName);
302
4636
    action->setNumber(hp);
303
2318
    addAction(hp, actionName, action);
304
305
    // dirty hack to fix bad resources in tmw server
306
2318
    if (actionName == "attack_stab")
307
    {
308
        reportAlways("Found legacy attribute attack_stab in animation");
309
        addAction(hp, "attack", action);
310
    }
311
312
    // When first action, set it as default direction.
313
    // i here always correct, because hp was added above.
314
6954
    const Actions::const_iterator i = mActions.find(hp);
315
4636
    if ((*i).second->size() == 1)
316
2310
        addAction(hp, SpriteAction::DEFAULT, action);
317
318
    // Load animations
319
9272
    for_each_xml_child_node(animationNode, node)
320
    {
321

6954
        if (xmlNameEqual(animationNode, "animation"))
322
2318
            loadAnimation(animationNode, action, imageSet, variant_offset);
323
    }
324
}
325
326
2318
void SpriteDef::loadAnimation(XmlNodeConstPtr animationNode,
327
                              Action *const action,
328
                              const ImageSet *const imageSet0,
329
                              const int variant_offset) const
330
{
331
4636
    if (action == nullptr ||
332
4636
        imageSet0 == nullptr ||
333
        animationNode == nullptr)
334
    {
335
        return;
336
    }
337
338
    const std::string directionName =
339

11590
        XML::getProperty(animationNode, "direction", "");
340
    const SpriteDirection::Type directionType
341
2318
        = makeSpriteDirection(directionName);
342
343
2318
    if (directionType == SpriteDirection::INVALID)
344
    {
345
        reportAlways("%s: Unknown direction \"%s\" used in %s",
346
            mSource.c_str(),
347
            directionName.c_str(),
348
            mIdPath.c_str());
349
        return;
350
    }
351
352
2318
    Animation *const animation = new Animation(directionName);
353
2318
    action->setAnimation(directionType, animation);
354
355
    // Get animation frames
356
9352
    for_each_xml_child_node(frameNode, animationNode)
357
    {
358
        const int delay = XML::getIntProperty(
359
7034
            frameNode, "delay", 0, 0, 100000);
360
        const std::string imageSetName = XML::getProperty(frameNode,
361
            "imageset",
362

35170
            "");
363
7034
        const ImageSet *imageSet = imageSet0;
364
7034
        if (!imageSetName.empty())
365
        {
366
            imageSet = getImageSet(imageSetName);
367
            if (imageSet == nullptr)
368
                imageSet = imageSet0;
369
        }
370
7034
        const int offsetX = XML::getProperty(frameNode, "offsetX", 0)
371
14068
            + imageSet->getOffsetX() - imageSet->getWidth() / 2
372
7034
            + mapTileSize / 2;
373
7034
        const int offsetY = XML::getProperty(frameNode, "offsetY", 0)
374
14068
            + imageSet->getOffsetY() - imageSet->getHeight() + mapTileSize;
375
7034
        const int rand = XML::getIntProperty(frameNode, "rand", 100, 0, 100);
376
377

7034
        if (xmlNameEqual(frameNode, "frame"))
378
        {
379
42
            const int index = XML::getProperty(frameNode, "index", -1);
380
381
42
            if (index < 0)
382
            {
383
                reportAlways(
384
                    "%s: No valid value for 'index' at direction '%s'",
385
                    mSource.c_str(),
386
                    directionName.c_str());
387
                continue;
388
            }
389
390
42
            Image *const img = imageSet->get(index + variant_offset);
391
42
            if (img == nullptr)
392
            {
393
                reportAlways("%s: No image at index %d at direction '%s'",
394
                    mSource.c_str(),
395
                    index + variant_offset,
396
                    directionName.c_str());
397
                continue;
398
            }
399
400
42
            animation->addFrame(img, delay, offsetX, offsetY, rand);
401
        }
402

6992
        else if (xmlNameEqual(frameNode, "sequence"))
403
        {
404
2304
            const int start = XML::getProperty(frameNode, "start", -1);
405
2304
            const int end = XML::getProperty(frameNode, "end", -1);
406

11520
            const std::string value = XML::getProperty(frameNode, "value", "");
407
            const int repeat = XML::getIntProperty(
408
2304
                frameNode, "repeat", 1, 0, 100);
409
410
2304
            if (repeat < 1)
411
            {
412
                reportAlways("%s: No valid value for 'repeat' at direction %s",
413
                    mSource.c_str(),
414
                    directionName.c_str());
415
                continue;
416
            }
417
418
2304
            if (value.empty())
419
            {
420

2304
                if (addSequence(start, end, delay, offsetX, offsetY,
421
                    variant_offset, repeat, rand, imageSet, animation))
422
                {
423
                    continue;
424
                }
425
            }
426
            else
427
            {
428
                StringVect vals;
429
                splitToStringVector(vals, value, ',');
430
                FOR_EACH (StringVectCIter, it, vals)
431
                {
432
                    const std::string str = *it;
433
                    const size_t idx = str.find('-');
434
                    if (str == "p")
435
                    {
436
                        animation->addPause(delay, rand);
437
                    }
438
                    else if (idx != std::string::npos)
439
                    {
440
                        const int v1 = atoi(str.substr(0, idx).c_str());
441
                        const int v2 = atoi(str.substr(idx + 1).c_str());
442
                        addSequence(v1, v2, delay, offsetX, offsetY,
443
                            variant_offset, repeat, rand, imageSet, animation);
444
                    }
445
                    else
446
                    {
447
                        Image *const img = imageSet->get(atoi(
448
                            str.c_str()) + variant_offset);
449
                        if (img != nullptr)
450
                        {
451
                            animation->addFrame(img, delay,
452
                                offsetX, offsetY, rand);
453
                        }
454
                    }
455
                }
456
            }
457
        }
458

4688
        else if (xmlNameEqual(frameNode, "pause"))
459
        {
460
            animation->addPause(delay, rand);
461
        }
462

4688
        else if (xmlNameEqual(frameNode, "end"))
463
        {
464
            animation->addTerminator(rand);
465
        }
466

4688
        else if (xmlNameEqual(frameNode, "jump"))
467
        {
468
            animation->addJump(XML::getProperty(
469
                frameNode, "action", ""), rand);
470
        }
471

4688
        else if (xmlNameEqual(frameNode, "label"))
472
        {
473

20
            const std::string name = XML::getProperty(frameNode, "name", "");
474
4
            if (!name.empty())
475
4
                animation->addLabel(name);
476
        }
477

4684
        else if (xmlNameEqual(frameNode, "goto"))
478
        {
479

40
            const std::string name = XML::getProperty(frameNode, "label", "");
480
8
            if (!name.empty())
481
8
                animation->addGoto(name, rand);
482
        }
483
    }  // for frameNode
484
}
485
486
void SpriteDef::includeSprite(XmlNodeConstPtr includeNode, const int variant)
487
{
488
    std::string filename = XML::getProperty(includeNode, "file", "");
489
490
    if (filename.empty())
491
        return;
492
    filename = pathJoin(paths.getStringValue("sprites"), filename);
493
494
    if (mProcessedFiles.find(filename) != mProcessedFiles.end())
495
    {
496
        reportAlways("%s: Tried to include %s which already is included.",
497
            mSource.c_str(),
498
            filename.c_str());
499
        return;
500
    }
501
    mProcessedFiles.insert(filename);
502
503
    XML::Document *const doc = Loader::getXml(filename,
504
        UseVirtFs_true,
505
        SkipError_false);
506
    if (doc == nullptr)
507
        return;
508
    XmlNodeConstPtr rootNode = doc->rootNode();
509
510
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "sprite"))
511
    {
512
        reportAlways("%s: No sprite root node in %s",
513
            mSource.c_str(),
514
            filename.c_str());
515
        doc->decRef();
516
        return;
517
    }
518
519
    loadSprite(rootNode, variant);
520
    doc->decRef();
521
}
522
523
13860
SpriteDef::~SpriteDef()
524
{
525
    // Actions are shared, so ensure they are deleted only once.
526
4620
    std::set<Action*> actions;
527
6930
    FOR_EACH (Actions::iterator, i, mActions)
528
    {
529
9240
        FOR_EACHP (ActionMap::iterator, it, (*i).second)
530
138600
            actions.insert(it->second);
531
4620
        delete (*i).second;
532
    }
533
534
4620
    FOR_EACH (std::set<Action*>::const_iterator, i, actions)
535
2318
        delete *i;
536
537
4620
    mActions.clear();
538
539
6930
    FOR_EACH (ImageSetIterator, i, mImageSets)
540
    {
541
2310
        if (i->second != nullptr)
542
        {
543
2310
            i->second->decRef();
544
2310
            i->second = nullptr;
545
        }
546
    }
547
4620
    mImageSets.clear();
548
4620
}
549
550
2318
SpriteDirection::Type SpriteDef::makeSpriteDirection(const std::string
551
                                                     &direction)
552
{
553

4636
    if (direction.empty() || direction == "default")
554
        return SpriteDirection::DEFAULT;
555
    else if (direction == "up")
556
        return SpriteDirection::UP;
557
    else if (direction == "left")
558
        return SpriteDirection::LEFT;
559
    else if (direction == "right")
560
        return SpriteDirection::RIGHT;
561
    else if (direction == "down")
562
        return SpriteDirection::DOWN;
563
    else if (direction == "upleft")
564
        return SpriteDirection::UPLEFT;
565
    else if (direction == "upright")
566
        return SpriteDirection::UPRIGHT;
567
    else if (direction == "downleft")
568
        return SpriteDirection::DOWNLEFT;
569
    else if (direction == "downright")
570
        return SpriteDirection::DOWNRIGHT;
571
    else
572
        return SpriteDirection::INVALID;
573
}
574
575
4628
void SpriteDef::addAction(const unsigned hp, const std::string &name,
576
                          Action *const action)
577
{
578
13884
    const Actions::const_iterator i = mActions.find(hp);
579
9256
    if (i == mActions.end())
580
4620
        mActions[hp] = new ActionMap;
581
582
4628
    (*mActions[hp])[name] = action;
583
4628
}
584
585
2304
bool SpriteDef::addSequence(const int start,
586
                            const int end,
587
                            const int delay,
588
                            const int offsetX,
589
                            const int offsetY,
590
                            const int variant_offset,
591
                            int repeat,
592
                            const int rand,
593
                            const ImageSet *const imageSet,
594
                            Animation *const animation) const
595
{
596
2304
    if ((imageSet == nullptr) || (animation == nullptr))
597
        return true;
598
599
2304
    if (start < 0 || end < 0)
600
    {
601
        reportAlways("%s: No valid value for 'start' or 'end'",
602
            mSource.c_str());
603
        return true;
604
    }
605
606
2304
    if (start <= end)
607
    {
608
6912
        while (repeat > 0)
609
        {
610
            int pos = start;
611
79104
            while (end >= pos)
612
            {
613
38400
                Image *const img = imageSet->get(pos + variant_offset);
614
615
38400
                if (img == nullptr)
616
                {
617
                    reportAlways("%s: No image at index %d",
618
                        mSource.c_str(),
619
                        pos + variant_offset);
620
                    pos ++;
621
                    continue;
622
                }
623
624
38400
                animation->addFrame(img, delay,
625
                    offsetX, offsetY, rand);
626
38400
                pos ++;
627
            }
628
2304
            repeat --;
629
        }
630
    }
631
    else
632
    {
633
        while (repeat > 0)
634
        {
635
            int pos = start;
636
            while (end <= pos)
637
            {
638
                Image *const img = imageSet->get(pos + variant_offset);
639
640
                if (img == nullptr)
641
                {
642
                    reportAlways("%s: No image at index %d",
643
                        mSource.c_str(),
644
                        pos + variant_offset);
645
                    pos ++;
646
                    continue;
647
                }
648
649
                animation->addFrame(img, delay,
650
                    offsetX, offsetY, rand);
651
                pos --;
652
            }
653
            repeat --;
654
        }
655
    }
656
    return false;
657
}
658
659
int SpriteDef::calcMemoryLocal() const
660
{
661
    int sz = static_cast<int>(sizeof(SpriteDef) +
662
        sizeof(ImageSets) +
663
        sizeof(Actions) +
664
        sizeof(std::set<std::string>)) +
665
        Resource::calcMemoryLocal();
666
    FOR_EACH (std::set<std::string>::const_iterator, it, mProcessedFiles)
667
    {
668
        sz += static_cast<int>((*it).capacity());
669
    }
670
    return sz;
671
}
672
673
int SpriteDef::calcMemoryChilds(const int level) const
674
{
675
    int sz = 0;
676
    FOR_EACH (ImageSets::const_iterator, it, mImageSets)
677
    {
678
        sz += static_cast<int>((*it).first.capacity());
679
        const ImageSet *const imageSet = (*it).second;
680
        sz += imageSet->calcMemory(level + 1);
681
    }
682
    FOR_EACH (ActionsCIter, it, mActions)
683
    {
684
        sz += sizeof(unsigned);
685
        const ActionMap *const actionMap = (*it).second;
686
        FOR_EACHP (ActionMap::const_iterator, it2, actionMap)
687
        {
688
            sz += static_cast<int>((*it2).first.capacity());
689
            const Action *const action = (*it2).second;
690
            sz += action->calcMemory(level + 1);
691
        }
692
    }
693
    return sz;
694

6
}