1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "ultima/ultima4/gfx/image.h"
24 #include "ultima/ultima4/gfx/imageloader.h"
25 #include "ultima/ultima4/gfx/imagemgr.h"
26 #include "ultima/ultima4/controllers/intro_controller.h"
27 #include "ultima/ultima4/core/config.h"
28 #include "ultima/ultima4/core/settings.h"
29 #include "ultima/ultima4/ultima4.h"
30
31 namespace Ultima {
32 namespace Ultima4 {
33
hasBlackBackground()34 bool ImageInfo::hasBlackBackground() {
35 return this->_filetype == "image/x-u4raw";
36 }
37
38
39 class ImageSet {
40 public:
41 ~ImageSet();
42
43 Common::String _name;
44 Common::String _location;
45 Common::String _extends;
46 Std::map<Common::String, ImageInfo *> _info;
47 };
48
49 ImageMgr *ImageMgr::_instance = nullptr;
50
getInstance()51 ImageMgr *ImageMgr::getInstance() {
52 if (_instance == nullptr) {
53 _instance = new ImageMgr();
54 _instance->init();
55 }
56 return _instance;
57 }
58
destroy()59 void ImageMgr::destroy() {
60 if (_instance != nullptr) {
61 delete _instance;
62 _instance = nullptr;
63 }
64 }
65
ImageMgr()66 ImageMgr::ImageMgr() : _baseSet(nullptr), _abyssData(nullptr) {
67 settings.addObserver(this);
68 }
69
~ImageMgr()70 ImageMgr::~ImageMgr() {
71 settings.deleteObserver(this);
72
73 for (Std::map<Common::String, ImageSet *>::iterator i = _imageSets.begin(); i != _imageSets.end(); i++)
74 delete i->_value;
75
76 delete[] _abyssData;
77 }
78
init()79 void ImageMgr::init() {
80 /*
81 * register the "screen" image representing the entire screen
82 */
83 Image *screen = Image::createScreenImage();
84
85 _screenInfo._name = "screen";
86 _screenInfo._filename = "";
87 _screenInfo._width = screen->width();
88 _screenInfo._height = screen->height();
89 _screenInfo._depth = 0;
90 _screenInfo._prescale = 0;
91 _screenInfo._filetype = "";
92 _screenInfo._tiles = 0;
93 _screenInfo._introOnly = false;
94 _screenInfo._transparentIndex = -1;
95 _screenInfo._xu4Graphic = false;
96 _screenInfo._fixup = FIXUP_NONE;
97 _screenInfo._image = screen;
98
99 /*
100 * register all the images declared in the config files
101 */
102 const Config *config = Config::getInstance();
103 Std::vector<ConfigElement> graphicsConf = config->getElement("graphics").getChildren();
104 for (Std::vector<ConfigElement>::iterator conf = graphicsConf.begin(); conf != graphicsConf.end(); conf++) {
105 if (conf->getName() == "imageset") {
106 ImageSet *set = loadImageSetFromConf(*conf);
107 _imageSets[set->_name] = set;
108
109 // all image sets include the "screen" image
110 set->_info[_screenInfo._name] = &_screenInfo;
111 }
112 }
113
114 _imageSetNames.clear();
115 for (Std::map<Common::String, ImageSet *>::const_iterator set = _imageSets.begin(); set != _imageSets.end(); set++)
116 _imageSetNames.push_back(set->_key);
117
118 update(&settings);
119 }
120
loadImageSetFromConf(const ConfigElement & conf)121 ImageSet *ImageMgr::loadImageSetFromConf(const ConfigElement &conf) {
122 ImageSet *set;
123
124 set = new ImageSet();
125 set->_name = conf.getString("name");
126 set->_location = conf.getString("location");
127 set->_extends = conf.getString("extends");
128
129 Std::vector<ConfigElement> children = conf.getChildren();
130 for (Std::vector<ConfigElement>::iterator i = children.begin(); i != children.end(); i++) {
131 if (i->getName() == "image") {
132 ImageInfo *info = loadImageInfoFromConf(*i);
133 if (set->_info.contains(info->_name))
134 delete set->_info[info->_name];
135 set->_info[info->_name] = info;
136 }
137 }
138
139 return set;
140 }
141
loadImageInfoFromConf(const ConfigElement & conf)142 ImageInfo *ImageMgr::loadImageInfoFromConf(const ConfigElement &conf) {
143 ImageInfo *info;
144 static const char *fixupEnumStrings[] = { "none", "intro", "abyss", "abacus", "dungns", "blackTransparencyHack", "fmtownsscreen", nullptr };
145
146 info = new ImageInfo();
147 info->_name = conf.getString("name");
148 info->_filename = conf.getString("filename");
149 info->_width = conf.getInt("width", -1);
150 info->_height = conf.getInt("height", -1);
151 info->_depth = conf.getInt("depth", -1);
152 info->_prescale = conf.getInt("prescale");
153 info->_filetype = conf.getString("filetype");
154 info->_tiles = conf.getInt("tiles");
155 info->_introOnly = conf.getBool("introOnly");
156 info->_transparentIndex = conf.getInt("transparentIndex", -1);
157
158 info->_xu4Graphic = conf.getBool("xu4Graphic");
159 info->_fixup = static_cast<ImageFixup>(conf.getEnum("fixup", fixupEnumStrings));
160 info->_image = nullptr;
161
162 Std::vector<ConfigElement> children = conf.getChildren();
163 for (Std::vector<ConfigElement>::iterator i = children.begin(); i != children.end(); i++) {
164 if (i->getName() == "subimage") {
165 SubImage *subimage = loadSubImageFromConf(info, *i);
166 info->_subImages[subimage->_name] = subimage;
167 }
168 }
169
170 return info;
171 }
172
loadSubImageFromConf(const ImageInfo * info,const ConfigElement & conf)173 SubImage *ImageMgr::loadSubImageFromConf(const ImageInfo *info, const ConfigElement &conf) {
174 SubImage *subimage;
175 static int x = 0,
176 y = 0,
177 last_width = 0,
178 last_height = 0;
179
180 subimage = new SubImage();
181 subimage->_name = conf.getString("name");
182 subimage->setWidth(conf.getInt("width"));
183 subimage->setHeight(conf.getInt("height"));
184 subimage->_srcImageName = info->_name;
185 if (conf.exists("x") && conf.exists("y")) {
186 x = conf.getInt("x");
187 y = conf.getInt("y");
188 subimage->moveTo(x, y);
189 } else {
190 // Automatically increment our position through the base image
191 x += last_width;
192 if (x >= last_width) {
193 x = 0;
194 y += last_height;
195 }
196
197 subimage->moveTo(x, y);
198 }
199
200 // "remember" the width and height of this subimage
201 last_width = subimage->width();
202 last_height = subimage->height();
203
204 return subimage;
205 }
206
fixupIntro(Image * im,int prescale)207 void ImageMgr::fixupIntro(Image *im, int prescale) {
208 const byte *sigData;
209 int i, x, y;
210 bool alpha = im->isAlphaOn();
211 RGBA color;
212
213 sigData = g_intro->getSigData();
214 im->alphaOff();
215 if (settings._videoType != "VGA-ALLPNG" && settings._videoType != "new") {
216 /* ----------------------------
217 * update the position of "and"
218 * ---------------------------- */
219 im->drawSubRectOn(im, 148 * prescale, 17 * prescale,
220 153 * prescale,
221 17 * prescale,
222 11 * prescale,
223 4 * prescale);
224 im->drawSubRectOn(im, 159 * prescale, 17 * prescale,
225 165 * prescale,
226 18 * prescale,
227 1 * prescale,
228 4 * prescale);
229 im->drawSubRectOn(im, 160 * prescale, 17 * prescale,
230 164 * prescale,
231 17 * prescale,
232 16 * prescale,
233 4 * prescale);
234 /* ---------------------------------------------
235 * update the position of "Origin Systems, Inc."
236 * --------------------------------------------- */
237 im->drawSubRectOn(im, 86 * prescale, 21 * prescale,
238 88 * prescale,
239 21 * prescale,
240 114 * prescale,
241 9 * prescale);
242 im->drawSubRectOn(im, 199 * prescale, 21 * prescale,
243 202 * prescale,
244 21 * prescale,
245 6 * prescale,
246 9 * prescale);
247 im->drawSubRectOn(im, 207 * prescale, 21 * prescale,
248 208 * prescale,
249 21 * prescale,
250 28 * prescale,
251 9 * prescale);
252 /* ---------------------------------------------
253 * update the position of "Ultima IV"
254 * --------------------------------------------- */
255 // move this *prior* to moving "present"
256 im->drawSubRectOn(im, 59 * prescale, 33 * prescale,
257 61 * prescale,
258 33 * prescale,
259 204 * prescale,
260 46 * prescale);
261 /* ---------------------------------------------
262 * update the position of "Quest of the Avatar"
263 * --------------------------------------------- */
264 im->drawSubRectOn(im, 69 * prescale, 80 * prescale, // quEst
265 70 * prescale,
266 80 * prescale,
267 11 * prescale,
268 13 * prescale);
269 im->drawSubRectOn(im, 82 * prescale, 80 * prescale, // queST
270 84 * prescale,
271 80 * prescale,
272 27 * prescale,
273 13 * prescale);
274 im->drawSubRectOn(im, 131 * prescale, 80 * prescale, // oF
275 132 * prescale,
276 80 * prescale,
277 11 * prescale,
278 13 * prescale);
279 im->drawSubRectOn(im, 150 * prescale, 80 * prescale, // THE
280 149 * prescale,
281 80 * prescale,
282 40 * prescale,
283 13 * prescale);
284 im->drawSubRectOn(im, 166 * prescale, 80 * prescale, // tHe
285 165 * prescale,
286 80 * prescale,
287 11 * prescale,
288 13 * prescale);
289 im->drawSubRectOn(im, 200 * prescale, 80 * prescale, // AVATAR
290 201 * prescale,
291 80 * prescale,
292 81 * prescale,
293 13 * prescale);
294 im->drawSubRectOn(im, 227 * prescale, 80 * prescale, // avAtar
295 228 * prescale,
296 80 * prescale,
297 11 * prescale,
298 13 * prescale);
299 }
300 /* -----------------------------------------------------------------------------
301 * copy "present" to new location between "Origin Systems, Inc." and "Ultima IV"
302 * ----------------------------------------------------------------------------- */
303 // do this *after* moving "Ultima IV"
304 im->drawSubRectOn(im, 132 * prescale, 33 * prescale,
305 135 * prescale,
306 0 * prescale,
307 56 * prescale,
308 5 * prescale);
309
310 if (alpha) {
311 im->alphaOn();
312 }
313
314 /* ----------------------------
315 * erase the original "present"
316 * ---------------------------- */
317 im->fillRect(135 * prescale, 0 * prescale, 56 * prescale, 5 * prescale, 0, 0, 0);
318
319 /* -------------------------
320 * update the colors for VGA
321 * ------------------------- */
322 if (settings._videoType == "VGA") {
323 ImageInfo *borderInfo = imageMgr->get(BKGD_BORDERS, true);
324 // ImageInfo *charsetInfo = imageMgr->get(BKGD_CHARSET);
325 if (!borderInfo)
326 error("ERROR 1001: Unable to load the \"%s\" data file", BKGD_BORDERS);
327
328 delete borderInfo->_image;
329 borderInfo->_image = nullptr;
330 borderInfo = imageMgr->get(BKGD_BORDERS, true);
331
332 im->setPaletteFromImage(borderInfo->_image);
333
334 // update the color of "and" and "present"
335 (void)im->setPaletteIndex(15, im->setColor(226, 226, 255));
336
337 // update the color of "Origin Systems, Inc."
338 (void)im->setPaletteIndex(9, im->setColor(129, 129, 255));
339
340 #ifdef TODO
341 borderInfo->_image->save("border.png");
342 #endif
343 // update the border appearance
344 borderInfo->_image->alphaOff();
345 borderInfo->_image->drawSubRectOn(im, 0, 96, 0, 0, 16, 56);
346 for (i = 0; i < 9; i++) {
347 borderInfo->_image->drawSubRectOn(im, 16 + (i * 32), 96, 144, 0, 48, 48);
348 }
349 im->drawSubRectInvertedOn(im, 0, 144, 0, 104, 320, 40);
350 im->drawSubRectOn(im, 0, 184, 0, 96, 320, 8);
351 borderInfo->_image->alphaOn();
352
353 delete borderInfo->_image;
354 borderInfo->_image = nullptr;
355 }
356
357 /* -----------------------------
358 * draw "Lord British" signature
359 * ----------------------------- */
360 color = im->setColor(0, 255, 255); // cyan for EGA
361 int blue[16] = {255, 250, 226, 226, 210, 194, 161, 161,
362 129, 97, 97, 64, 64, 32, 32, 0
363 };
364 i = 0;
365 while (sigData[i] != 0) {
366 /* (x/y) are unscaled coordinates, i.e. in 320x200 */
367 x = sigData[i] + 0x14;
368 y = 0xBF - sigData[i + 1];
369
370 if (settings._videoType != "EGA") {
371 // yellow gradient
372 color = im->setColor(255, (y == 1 ? 250 : 255), blue[y]);
373 }
374
375 im->fillRect(x * prescale, y * prescale,
376 2 * prescale, prescale,
377 color.r, color.g, color.b);
378 i += 2;
379 }
380
381 /* --------------------------------------------------------------
382 * draw the red line between "Origin Systems, Inc." and "present"
383 * -------------------------------------------------------------- */
384 /* we're still working with an unscaled surface */
385 if (settings._videoType != "EGA") {
386 color = im->setColor(0, 0, 161); // dark blue
387 } else {
388 color = im->setColor(128, 0, 0); // dark red for EGA
389 }
390 for (i = 84; i < 236; i++) // 152 px wide
391 im->fillRect(i * prescale, 31 * prescale,
392 prescale, prescale,
393 color.r, color.g, color.b);
394 }
395
fixupAbyssVision(Image * im,int prescale)396 void ImageMgr::fixupAbyssVision(Image *im, int prescale) {
397 // Ignore fixups for xu4 PNG images - they're already correct
398 if (im->isIndexed())
399 return;
400
401 /*
402 * Each VGA vision components must be XORed with all the previous
403 * vision components to get the actual image.
404 */
405 if (_abyssData) {
406 for (int y = 0; y < im->height(); y++) {
407 for (int x = 0; x < im->width(); x++) {
408 uint index;
409 im->getPixelIndex(x, y, index);
410 index ^= _abyssData[y * im->width() + x];
411 im->putPixelIndex(x, y, index);
412 }
413 }
414 } else {
415 _abyssData = new uint[im->width() * im->height()];
416 }
417
418 for (int y = 0; y < im->height(); y++) {
419 for (int x = 0; x < im->width(); x++) {
420 uint index;
421 im->getPixelIndex(x, y, index);
422 _abyssData[y * im->width() + x] = index;
423 }
424 }
425 }
426
fixupAbacus(Image * im,int prescale)427 void ImageMgr::fixupAbacus(Image *im, int prescale) {
428
429 /*
430 * surround each bead with a row green pixels to avoid artifacts
431 * when scaling
432 */
433
434 im->fillRect(7 * prescale, 186 * prescale, prescale, 14 * prescale, 0, 255, 80); /* green */
435 im->fillRect(16 * prescale, 186 * prescale, prescale, 14 * prescale, 0, 255, 80); /* green */
436 im->fillRect(8 * prescale, 186 * prescale, prescale * 8, prescale, 0, 255, 80); /* green */
437 im->fillRect(8 * prescale, 199 * prescale, prescale * 8, prescale, 0, 255, 80); /* green */
438
439 im->fillRect(23 * prescale, 186 * prescale, prescale, 14 * prescale, 0, 255, 80); /* green */
440 im->fillRect(32 * prescale, 186 * prescale, prescale, 14 * prescale, 0, 255, 80); /* green */
441 im->fillRect(24 * prescale, 186 * prescale, prescale * 8, prescale, 0, 255, 80); /* green */
442 im->fillRect(24 * prescale, 199 * prescale, prescale * 8, prescale, 0, 255, 80); /* green */
443 }
444
fixupDungNS(Image * im,int prescale)445 void ImageMgr::fixupDungNS(Image *im, int prescale) {
446 for (int y = 0; y < im->height(); y++) {
447 for (int x = 0; x < im->width(); x++) {
448 uint index;
449 im->getPixelIndex(x, y, index);
450 if (index == 1)
451 im->putPixelIndex(x, y, 2);
452 else if (index == 2)
453 im->putPixelIndex(x, y, 1);
454 }
455 }
456 }
457
fixupFMTowns(Image * im,int prescale)458 void ImageMgr::fixupFMTowns(Image *im, int prescale) {
459 for (int y = 20; y < im->height(); y++) {
460 for (int x = 0; x < im->width(); x++) {
461 uint index;
462 im->getPixelIndex(x, y, index);
463 im->putPixelIndex(x, y - 20, index);
464 }
465 }
466 }
467
getSet(const Common::String & setname)468 ImageSet *ImageMgr::getSet(const Common::String &setname) {
469 Std::map<Common::String, ImageSet *>::iterator i = _imageSets.find(setname);
470 if (i != _imageSets.end())
471 return i->_value;
472 else
473 return nullptr;
474 }
475
getInfo(const Common::String & name)476 ImageInfo *ImageMgr::getInfo(const Common::String &name) {
477 return getInfoFromSet(name, _baseSet);
478 }
479
getInfoFromSet(const Common::String & name,ImageSet * imageset)480 ImageInfo *ImageMgr::getInfoFromSet(const Common::String &name, ImageSet *imageset) {
481 if (!imageset)
482 return nullptr;
483
484 /* if the image set contains the image we want, AND IT EXISTS we are done */
485 Std::map<Common::String, ImageInfo *>::iterator i = imageset->_info.find(name);
486 if (i != imageset->_info.end())
487 if (imageExists(i->_value))
488 return i->_value;
489
490 /* otherwise if this image set extends another, check the base image set */
491 while (imageset->_extends != "") {
492 imageset = getSet(imageset->_extends);
493 return getInfoFromSet(name, imageset);
494 }
495
496 //warning("Searched recursively from imageset %s through to %s and couldn't find %s", baseSet->name.c_str(), imageset->name.c_str(), name.c_str());
497 return nullptr;
498 }
499
guessFileType(const Common::String & filename)500 Common::String ImageMgr::guessFileType(const Common::String &filename) {
501 if (filename.size() >= 4 && filename.hasSuffixIgnoreCase(".png")) {
502 return "image/png";
503 } else {
504 return "";
505 }
506 }
507
imageExists(ImageInfo * info)508 bool ImageMgr::imageExists(ImageInfo *info) {
509 if (info->_filename == "") //If it is an abstract image like "screen"
510 return true;
511 Common::File *file = getImageFile(info);
512 if (file) {
513 delete file;
514 return true;
515 }
516 return false;
517 }
518
519
getImageFile(ImageInfo * info)520 Common::File *ImageMgr::getImageFile(ImageInfo *info) {
521 Common::String filename = info->_filename;
522
523 if (filename.empty())
524 return nullptr;
525
526 Common::File *file = new Common::File();
527 if (!info->_xu4Graphic) {
528 // It's a file in the game folder
529 if (file->open(filename))
530 return file;
531 }
532
533 if (file->open("data/graphics/" + filename))
534 return file;
535
536 delete file;
537 return nullptr;
538 }
539
get(const Common::String & name,bool returnUnscaled)540 ImageInfo *ImageMgr::get(const Common::String &name, bool returnUnscaled) {
541 ImageInfo *info = getInfo(name);
542 if (!info)
543 return nullptr;
544
545 /* return if already loaded */
546 if (info->_image != nullptr)
547 return info;
548
549 Common::File *file = getImageFile(info);
550 Image *unscaled = nullptr;
551 if (file) {
552 if (info->_filetype.empty())
553 info->_filetype = guessFileType(info->_filename);
554 Common::String filetype = info->_filetype;
555 ImageLoader *loader = g_ultima->_imageLoaders->getLoader(filetype);
556 if (loader == nullptr) {
557 warning("can't find loader to load image \"%s\" with type \"%s\"", info->_filename.c_str(), filetype.c_str());
558 } else {
559 unscaled = loader->load(*file, info->_width, info->_height, info->_depth);
560 if (info->_width == -1) {
561 // Write in the values for later use.
562 info->_width = unscaled->width();
563 info->_height = unscaled->height();
564 // ### info->depth = ???
565 }
566 }
567
568 delete file;
569 } else {
570 warning("Failed to open file %s for reading.", info->_filename.c_str());
571 return nullptr;
572 }
573
574 if (unscaled == nullptr)
575 return nullptr;
576
577 if (info->_transparentIndex != -1)
578 unscaled->setTransparentIndex(info->_transparentIndex);
579
580 if (info->_prescale == 0)
581 info->_prescale = 1;
582
583 /*
584 * fixup the image before scaling it
585 */
586 switch (info->_fixup) {
587 case FIXUP_NONE:
588 break;
589 case FIXUP_INTRO:
590 fixupIntro(unscaled, info->_prescale);
591 break;
592 case FIXUP_ABYSS:
593 fixupAbyssVision(unscaled, info->_prescale);
594 break;
595 case FIXUP_ABACUS:
596 fixupAbacus(unscaled, info->_prescale);
597 break;
598 case FIXUP_DUNGNS:
599 fixupDungNS(unscaled, info->_prescale);
600 break;
601 case FIXUP_FMTOWNSSCREEN:
602 fixupFMTowns(unscaled, info->_prescale);
603 break;
604 case FIXUP_BLACKTRANSPARENCYHACK:
605 //Apply transparency shadow hack to ultima4 ega and vga upgrade classic graphics.
606 Image *unscaled_original = unscaled;
607 unscaled = Image::duplicate(unscaled);
608 delete unscaled_original;
609 if (Settings::getInstance()._enhancements && Settings::getInstance()._enhancementsOptions._u4TileTransparencyHack) {
610 int transparency_shadow_size = Settings::getInstance()._enhancementsOptions._u4TrileTransparencyHackShadowBreadth;
611 int black_index = 0;
612 int opacity = Settings::getInstance()._enhancementsOptions._u4TileTransparencyHackPixelShadowOpacity;
613
614 int frames = info->_tiles;
615 for (int f = 0; f < frames; ++f)
616 unscaled->performTransparencyHack(black_index, frames, f, transparency_shadow_size, opacity);
617 }
618 break;
619 }
620
621 if (returnUnscaled) {
622 info->_image = unscaled;
623 return info;
624 }
625
626 int imageScale = settings._scale;
627 if ((settings._scale % info->_prescale) != 0) {
628 int orig_scale = settings._scale;
629 settings._scale = info->_prescale;
630 settings.write();
631 error("image %s is prescaled to an incompatible size: %d\nResetting the scale to %d. Sorry about the inconvenience, please restart.", info->_filename.c_str(), orig_scale, settings._scale);
632 }
633 imageScale /= info->_prescale;
634
635 info->_image = g_screen->screenScale(unscaled, imageScale, info->_tiles, 1);
636
637 delete unscaled;
638 return info;
639 }
640
getSubImage(const Common::String & name)641 SubImage *ImageMgr::getSubImage(const Common::String &name) {
642 Common::String setname;
643
644 ImageSet *set = _baseSet;
645
646 while (set != nullptr) {
647 for (Std::map<Common::String, ImageInfo *>::iterator i = set->_info.begin(); i != set->_info.end(); i++) {
648 ImageInfo *info = (ImageInfo *) i->_value;
649 Std::map<Common::String, SubImage *>::iterator j = info->_subImages.find(name);
650 if (j != info->_subImages.end())
651 return j->_value;
652 }
653
654 set = getSet(set->_extends);
655 }
656
657 return nullptr;
658 }
659
freeIntroBackgrounds()660 void ImageMgr::freeIntroBackgrounds() {
661 for (Std::map<Common::String, ImageSet *>::iterator i = _imageSets.begin(); i != _imageSets.end(); i++) {
662 ImageSet *set = i->_value;
663 for (Std::map<Common::String, ImageInfo *>::iterator j = set->_info.begin(); j != set->_info.end(); j++) {
664 ImageInfo *info = j->_value;
665 if (info->_image != nullptr && info->_introOnly) {
666 delete info->_image;
667 info->_image = nullptr;
668 }
669 }
670 }
671 }
672
getSetNames()673 const Std::vector<Common::String> &ImageMgr::getSetNames() {
674 return _imageSetNames;
675 }
676
update(Settings * newSettings)677 void ImageMgr::update(Settings *newSettings) {
678 Common::String setname;
679
680 setname = newSettings->_videoType;
681
682 _baseSet = getSet(setname);
683 }
684
~ImageSet()685 ImageSet::~ImageSet() {
686 for (Std::map<Common::String, ImageInfo *>::iterator i = _info.begin(); i != _info.end(); i++) {
687 ImageInfo *imageInfo = i->_value;
688 if (imageInfo->_name != "screen")
689 delete imageInfo;
690 }
691 }
692
~ImageInfo()693 ImageInfo::~ImageInfo() {
694 for (Std::map<Common::String, SubImage *>::iterator i = _subImages.begin(); i != _subImages.end(); i++)
695 delete i->_value;
696 if (_image != nullptr)
697 delete _image;
698 }
699
700 } // End of namespace Ultima4
701 } // End of namespace Ultima
702