Ticket #8910: kyra_thumbnail_v1.patch

File kyra_thumbnail_v1.patch, 35.6 KB (added by lordhoto, 16 years ago)

patch against r33849

  • engines/scumm/thumbnail.cpp

     
    2727#include "common/system.h"
    2828#include "common/savefile.h"
    2929#include "graphics/scaler.h"
     30#include "graphics/thumbnail.h"
    3031#include "scumm/scumm.h"
    3132
    3233namespace Scumm {
    3334
    34 #define THMB_VERSION 1
    35 
    36 struct ThumbnailHeader {
    37         uint32 type;
    38         uint32 size;
    39         byte version;
    40         uint16 width, height;
    41         byte bpp;
    42 };
    43 
    44 #define ThumbnailHeaderSize (4+4+1+2+2+1)
    45 
    46 inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) {
    47         r = (((color >> 11) & 0x1F) << 3);
    48         g = (((color >> 5) & 0x3F) << 2);
    49         b = ((color&0x1F) << 3);
    50 }
    51 
    5235Graphics::Surface *ScummEngine::loadThumbnail(Common::SeekableReadStream *file) {
    53         ThumbnailHeader header;
     36        // TODO: Until backwards seeking in compressed save files is not supported
     37        // We can not use this.
    5438
    55         header.type = file->readUint32BE();
    56         // We also accept the bad 'BMHT' header here, for the sake of compatibility
    57         // with some older savegames which were written incorrectly due to a bug in
    58         // ScummVM which wrote the thumb header type incorrectly on LE systems.
    59         if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT'))
    60                 return 0;
     39        //if (!Graphics::checkThumbnailHeader(*file))
     40        //      return 0;
    6141
    62         header.size = file->readUint32BE();
    63         header.version = file->readByte();
    64 
    65         if (header.version > THMB_VERSION) {
    66                 file->skip(header.size - 9);
    67                 warning("Loading a newer thumbnail version");
     42        Graphics::Surface *thumb = new Graphics::Surface();
     43        assert(thumb);
     44        if (!Graphics::loadThumbnail(*file, *thumb)) {
     45                delete thumb;
    6846                return 0;
    6947        }
    7048
    71         header.width = file->readUint16BE();
    72         header.height = file->readUint16BE();
    73         header.bpp = file->readByte();
    74 
    75         // TODO: support other bpp values than 2
    76         if (header.bpp != 2) {
    77                 file->skip(header.size - 14);
    78                 return 0;
    79         }
    80 
    81         Graphics::Surface *thumb = new Graphics::Surface();
    82         thumb->create(header.width, header.height, sizeof(OverlayColor));
    83 
    84         OverlayColor* pixels = (OverlayColor *)thumb->pixels;
    85 
    86         for (int y = 0; y < thumb->h; ++y) {
    87                 for (int x = 0; x < thumb->w; ++x) {
    88                         uint8 r, g, b;
    89                         colorToRGB(file->readUint16BE(), r, g, b);
    90 
    91                         // converting to current OSystem Color
    92                         *pixels++ = _system->RGBToColor(r, g, b);
    93                 }
    94         }
    95 
    9649        return thumb;
    9750}
    9851
    9952void ScummEngine::saveThumbnail(Common::OutSaveFile *file) {
     53        // Until we support no thumbnails in the SCUMM save formats for NDS
     54        // we save a dummy thumbnail.
     55        //
     56        // TODO: Actually all what has to be done about it, is to update
     57        // the code in engines/scumm/saveload.o which skips the saveheader.
     58        // Currently impossible because of lacking backward seek support for
     59        // compressed save files.
     60        // When we change that code to use the new API from graphics/thumbnail.h
     61        // it should be all fine to save no header at all for NDS.
     62
    10063        Graphics::Surface thumb;
    10164
    10265#if !defined(__DS__)
     
    10467#endif
    10568                thumb.create(kThumbnailWidth, kThumbnailHeight2, sizeof(uint16));
    10669
    107         ThumbnailHeader header;
    108         header.type = MKID_BE('THMB');
    109         header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel;
    110         header.version = THMB_VERSION;
    111         header.width = thumb.w;
    112         header.height = thumb.h;
    113         header.bpp = thumb.bytesPerPixel;
    114 
    115         file->writeUint32BE(header.type);
    116         file->writeUint32BE(header.size);
    117         file->writeByte(header.version);
    118         file->writeUint16BE(header.width);
    119         file->writeUint16BE(header.height);
    120         file->writeByte(header.bpp);
    121 
    122         // TODO: for later this shouldn't be casted to uint16...
    123         uint16* pixels = (uint16 *)thumb.pixels;
    124         for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels)
    125                 file->writeUint16BE(*pixels);
    126 
     70        Graphics::saveThumbnail(*file, thumb);
    12771        thumb.free();
    12872}
    12973
  • engines/kyra/kyra_mr.cpp

     
    684684        assert(_invWsa);
    685685        _invWsa->open("MOODOMTR.WSA", 1, 0);
    686686        _invWsaFrame = 6;
    687         saveGame(getSavegameFilename(0), (const char*)getTableEntry(_optionsFile, 33));
     687        saveGame(getSavegameFilename(0), (const char*)getTableEntry(_optionsFile, 33), 0);
    688688        _soundDigital->beginFadeOut(_musicSoundChannel, 60);
    689689        delayWithTicks(60);
    690690        if (_gameToLoad == -1)
  • engines/kyra/kyra_hof.h

     
    907907        int _dbgPass;
    908908
    909909        // save/load specific
    910         void saveGame(const char *fileName, const char *saveName);
     910        void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail);
    911911        void loadGame(const char *fileName);
    912912};
    913913
  • engines/kyra/kyra_v1.h

     
    290290
    291291                bool originalSave;      // savegame from original interpreter
    292292                bool oldHeader;         // old scummvm save header
     293
     294                Graphics::Surface *thumbnail;
    293295        };
    294296
    295297        enum kReadSaveHeaderError {
     
    299301                kRSHEIoError = 3
    300302        };
    301303
    302         static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, SaveHeader &header);
     304        static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, bool loadThumbnail, SaveHeader &header);
    303305
    304306        Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header);
    305         Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName) const;
     307        Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const;
    306308};
    307309
    308310} // End of namespace Kyra
  • engines/kyra/gui_mr.cpp

     
    3333
    3434#include "common/savefile.h"
    3535
     36#include "graphics/scaler.h"
     37
    3638namespace Kyra {
    3739
    3840void KyraEngine_MR::loadButtonShapes() {
     
    11381140GUI_MR::GUI_MR(KyraEngine_MR *vm) : GUI_v2(vm), _vm(vm), _screen(vm->_screen) {
    11391141}
    11401142
     1143void GUI_MR::createScreenThumbnail(Graphics::Surface &dst) {
     1144        ::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(0));
     1145}
     1146
    11411147void GUI_MR::flagButtonEnable(Button *button) {
    11421148        if (!button)
    11431149                return;
     
    14501456
    14511457        if (_vm->_lang != lang) {
    14521458                _reloadTemporarySave = true;
    1453                 _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 3 Savegame");
     1459                _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 3 Savegame", 0);
    14541460                if (!_vm->loadLanguageFile("ITEMS.", _vm->_itemFile))
    14551461                        error("Couldn't load ITEMS");
    14561462                if (!_vm->loadLanguageFile("SCORE.", _vm->_scoreFile))
  • engines/kyra/screen_lok.cpp

     
    147147
    148148void Screen_LoK::loadPageFromDisk(const char *file, int page) {
    149149        debugC(9, kDebugLevelScreen, "Screen_LoK::loadPageFromDisk('%s', %d)", file, page);
     150        if (!_saveLoadPage[page/2]) {
     151                warning("trying to restore page %d, but no backup found", page);
     152                return;
     153        }
     154
    150155        copyBlockToPage(page, 0, 0, SCREEN_W, SCREEN_H, _saveLoadPage[page/2]);
    151156        delete[] _saveLoadPage[page/2];
     157        _saveLoadPage[page/2] = 0;
    152158
    153159        if (_saveLoadPageOvl[page/2]) {
    154160                uint8 *dstPage = getOverlayPtr(page);
     
    160166                memcpy(dstPage, _saveLoadPageOvl[page/2], SCREEN_OVL_SJIS_SIZE);
    161167                delete[] _saveLoadPageOvl[page/2];
    162168                _saveLoadPageOvl[page/2] = 0;
    163         }       _saveLoadPage[page/2] = 0;
     169        }
    164170}
    165171
     172void Screen_LoK::queryPageFromDisk(const char *file, int page, uint8 *buffer) {
     173        debugC(9, kDebugLevelScreen, "Screen_LoK::queryPageFromDisk('%s', %d, %p)", file, page, (const void *)buffer);
     174        if (!_saveLoadPage[page/2]) {
     175                warning("trying to query page %d, but no backup found", page);
     176                return;
     177        }
     178
     179        memcpy(buffer, _saveLoadPage[page/2], SCREEN_W*SCREEN_H);
     180}
     181
    166182void Screen_LoK::deletePageFromDisk(int page) {
    167183        debugC(9, kDebugLevelScreen, "Screen_LoK::deletePageFromDisk(%d)", page);
    168184        delete[] _saveLoadPage[page/2];
  • engines/kyra/gui_lok.h

     
    103103        int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel);
    104104
    105105        int buttonMenuCallback(Button *caller);
     106
     107        void createScreenThumbnail(Graphics::Surface &dst);
    106108private:
    107109        void initStaticResource();
    108110
  • engines/kyra/kyra_mr.h

     
    583583        int albumClose(Button *caller);
    584584
    585585        // save/load
    586         void saveGame(const char *fileName, const char *saveName);
     586        void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail);
    587587        void loadGame(const char *fileName);
    588588
    589589        // opcodes
  • engines/kyra/gui_hof.cpp

     
    3333
    3434#include "common/savefile.h"
    3535
     36#include "graphics/scaler.h"
     37
    3638namespace Kyra {
    3739
    3840void KyraEngine_HoF::loadButtonShapes() {
     
    793795
    794796#pragma mark -
    795797
     798void GUI_HoF::createScreenThumbnail(Graphics::Surface &dst) {
     799        ::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(1));
     800}
     801
    796802void GUI_HoF::setupPalette() {
    797803        memcpy(_screen->getPalette(1), _screen->getPalette(0), 768);
    798804
     
    9961002
    9971003        if (_vm->_lang != lang) {
    9981004                _reloadTemporarySave = true;
    999                 _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 2 Savegame");
     1005                _vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 2 Savegame", 0);
    10001006                _vm->loadCCodeBuffer("C_CODE.XXX");
    10011007                if (_vm->_flags.isTalkie)
    10021008                        _vm->loadOptionsBuffer("OPTIONS.XXX");
  • engines/kyra/gui_mr.h

     
    4747        int redrawButtonCallback(Button *button);
    4848
    4949        int optionsButton(Button *button);
     50
     51        void createScreenThumbnail(Graphics::Surface &dst);
    5052private:
    5153        void getInput();
    5254
  • engines/kyra/gui.h

     
    3232#include "common/array.h"
    3333#include "common/func.h"
    3434
     35#include "graphics/surface.h"
     36
    3537namespace Kyra {
    3638
    3739#define BUTTON_FUNCTOR(type, x, y) Button::Callback(new Common::Functor1Mem<Button*, int, type>(x, y))
     
    153155
    154156        void processHighlights(Menu &menu, int mouseX, int mouseY);
    155157
     158        // utilities for thumbnail creation
     159        virtual void createScreenThumbnail(Graphics::Surface &dst) = 0;
    156160protected:
    157161        KyraEngine_v1 *_vm;
    158162        Screen *_screen;
  • engines/kyra/gui_lok.cpp

     
    3737#include "common/events.h"
    3838#include "common/system.h"
    3939
     40#include "graphics/scaler.h"
     41
    4042namespace Kyra {
    4143
    4244void KyraEngine_LoK::initMainButtonList() {
     
    199201        delete[] _menu;
    200202}
    201203
     204void GUI_LoK::createScreenThumbnail(Graphics::Surface &dst) {
     205        uint8 *screen = new uint8[Screen::SCREEN_W*Screen::SCREEN_H];
     206        if (screen) {
     207                _screen->queryPageFromDisk("SEENPAGE.TMP", 0, screen);
     208                ::createThumbnail(&dst, screen, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(2));
     209        }
     210        delete[] screen;
     211}
     212
    202213int GUI_LoK::processButtonList(Button *list, uint16 inputFlag, int8 mouseWheel) {
    203214        while (list) {
    204215                if (list->flags & 8) {
     
    736747        } else {
    737748                if (_savegameOffset == 0 && _vm->_gameToLoad == 0)
    738749                        _vm->_gameToLoad = getNextSavegameSlot();
    739                 if (_vm->_gameToLoad > 0)
    740                         _vm->saveGame(_vm->getSavegameFilename(_vm->_gameToLoad), _savegameName);
     750                if (_vm->_gameToLoad > 0) {
     751                        Graphics::Surface thumb;
     752                        createScreenThumbnail(thumb);
     753                        _vm->saveGame(_vm->getSavegameFilename(_vm->_gameToLoad), _savegameName, &thumb);
     754                        thumb.free();
     755                }
    741756        }
    742757
    743758        return 0;
  • engines/kyra/screen_lok.h

     
    5050
    5151        void savePageToDisk(const char *file, int page);
    5252        void loadPageFromDisk(const char *file, int page);
     53        void queryPageFromDisk(const char *file, int page, uint8 *buffer);
    5354        void deletePageFromDisk(int page);
    5455
    5556        void copyBackgroundBlock(int x, int page, int flag);
  • engines/kyra/saveload.cpp

     
    2626#include "common/endian.h"
    2727#include "common/savefile.h"
    2828#include "common/system.h"
     29#include "graphics/thumbnail.h"
    2930
    3031#include "kyra/kyra_v1.h"
    3132
    32 #define CURRENT_SAVE_VERSION 13
     33#define CURRENT_SAVE_VERSION 14
    3334
    3435#define GF_FLOPPY  (1 <<  0)
    3536#define GF_TALKIE  (1 <<  1)
     
    3738
    3839namespace Kyra {
    3940
    40 KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header) {
     41KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
    4142        uint32 type = in->readUint32BE();
    4243        header.originalSave = false;
    4344        header.oldHeader = false;
     
    108109        if (header.version >= 2)
    109110                header.flags = in->readUint32BE();
    110111
     112        if (header.version >= 14) {
     113                if (loadThumbnail) {
     114                        header.thumbnail = new Graphics::Surface();
     115                        assert(header.thumbnail);
     116                        Graphics::loadThumbnail(*in, *header.thumbnail);
     117                } else {
     118                        Graphics::skipThumbnailHeader(*in);
     119                }
     120        }
     121
    111122        return (in->ioFailed() ? kRSHEIoError : kRSHENoError);
    112123}
    113124
     
    118129        if (!(in = _saveFileMan->openForLoading(filename)))
    119130                return 0;
    120131
    121         kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, header);
     132        kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, false, header);
    122133        if (errorCode != kRSHENoError) {
    123134                if (errorCode == kRSHEInvalidType)
    124135                        warning("No ScummVM Kyra engine savefile header.");
     
    162173        return in;
    163174}
    164175
    165 Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName) const {
    166         debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s')", filename, saveName);
     176Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const {
     177        debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s', %p)", filename, saveName, (const void *)thumbnail);
    167178        if (_quitFlag)
    168179                return 0;
    169180
     
    191202                return 0;
    192203        }
    193204
     205        if (thumbnail)
     206                Graphics::saveThumbnail(*out, *thumbnail);
     207        else
     208                Graphics::saveThumbnail(*out);
     209
    194210        return out;
    195211}
    196212
  • engines/kyra/timer_mr.cpp

     
    6565void KyraEngine_MR::timerFleaDeath(int arg) {
    6666        debugC(9, kDebugLevelMain | kDebugLevelTimer, "KyraEngine_MR::timerFleaDeath(%d)", arg);
    6767        _timer->setCountdown(4, 5400);
    68         saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME");
     68        saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME", 0);
    6969        _screen->hideMouse();
    7070        _timer->disable(4);
    7171        runAnimationScript("FLEADTH1.EMC", 0, 0, 1, 1);
  • engines/kyra/detection.cpp

     
    10651065                if (slotNum >= 0 && slotNum <= 999) {
    10661066                        Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
    10671067                        if (in) {
    1068                                 if (Kyra::KyraEngine_v1::readSaveHeader(in, header) == Kyra::KyraEngine_v1::kRSHENoError)
     1068                                if (Kyra::KyraEngine_v1::readSaveHeader(in, false, header) == Kyra::KyraEngine_v1::kRSHENoError)
    10691069                                        saveList.push_back(SaveStateDescriptor(slotNum, header.description, *file));
    10701070                                delete in;
    10711071                        }
  • engines/kyra/kyra_lok.h

     
    214214protected:
    215215        int32 _speechPlayTime;
    216216
    217         void saveGame(const char *fileName, const char *saveName);
     217        void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail);
    218218        void loadGame(const char *fileName);
    219219
    220220protected:
  • engines/kyra/kyra_v2.h

     
    419419        int o2_getVocHigh(EMCState *script);
    420420
    421421        // save/load specific
    422         virtual void saveGame(const char *fileName, const char *saveName) = 0;
     422        virtual void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail) = 0;
    423423        virtual void loadGame(const char *fileName) = 0;
    424424};
    425425
  • engines/kyra/gui_hof.h

     
    4141        void initStaticData();
    4242
    4343        int optionsButton(Button *button);
     44
     45        void createScreenThumbnail(Graphics::Surface &dst);
    4446private:
    4547        const char *getMenuTitle(const Menu &menu);
    4648        const char *getMenuItemTitle(const MenuItem &menuItem);
  • engines/kyra/saveload_hof.cpp

     
    3535
    3636namespace Kyra {
    3737
    38 void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName) {
    39         debugC(9, kDebugLevelMain, "KyraEngine_HoF::saveGame('%s', '%s')", fileName, saveName);
     38void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) {
     39        debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb);
    4040
    41         Common::OutSaveFile *out = openSaveForWriting(fileName, saveName);
     41        Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);
    4242        if (!out) {
    4343                warning("Can't open file '%s', game not loadable", fileName);
    4444                return;
  • engines/kyra/script_mr.cpp

     
    293293
    294294int KyraEngine_MR::o3_makeSecondChanceSave(EMCState *script) {
    295295        debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_makeSecondChanceSave(%p) ()", (const void *)script);
    296         saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME");
     296        saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME", 0);
    297297        return 0;
    298298}
    299299
  • engines/kyra/kyra_hof.cpp

     
    434434        if (_gameToLoad == -1) {
    435435                snd_playWanderScoreViaMap(52, 1);
    436436                enterNewScene(_mainCharacter.sceneId, _mainCharacter.facing, 0, 0, 1);
    437                 saveGame(getSavegameFilename(0), "New Game");
     437                saveGame(getSavegameFilename(0), "New Game", 0);
    438438        } else {
    439439                loadGame(getSavegameFilename(_gameToLoad));
    440440        }
  • engines/kyra/saveload_lok.cpp

     
    218218        delete in;
    219219}
    220220
    221 void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName) {
    222         debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s')", fileName, saveName);
     221void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) {
     222        debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb);
    223223       
    224224        if (_quitFlag)
    225225                return;
    226226
    227         Common::OutSaveFile *out = openSaveForWriting(fileName, saveName);
     227        Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);
    228228        if (!out)
    229229                return;
    230230       
  • engines/kyra/kyra_lok.cpp

     
    388388                        _gui->buttonMenuCallback(0);
    389389                        _menuDirectlyToLoad = false;
    390390                } else
    391                         saveGame(getSavegameFilename(0), "New game");
     391                        saveGame(getSavegameFilename(0), "New game", 0);
    392392        } else {
    393393                _screen->setFont(Screen::FID_8_FNT);
    394394                loadGame(getSavegameFilename(_gameToLoad));
     
    470470                                        else {
    471471                                                char savegameName[14];
    472472                                                sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0');
    473                                                 saveGame(saveLoadSlot, savegameName);
     473                                                saveGame(saveLoadSlot, savegameName, 0);
    474474                                        }
    475475                                } else if (event.kbd.flags == Common::KBD_CTRL) {
    476476                                        if (event.kbd.keycode == 'd')
  • engines/kyra/kyra_v2.cpp

     
    186186                                } else {
    187187                                        char savegameName[14];
    188188                                        sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0');
    189                                         saveGame(saveLoadSlot, savegameName);
     189                                        saveGame(saveLoadSlot, savegameName, 0);
    190190                                }
    191191                        } else if (event.kbd.flags == Common::KBD_CTRL) {
    192192                                if (event.kbd.keycode == 'd')
  • engines/kyra/gui_v2.cpp

     
    618618
    619619        restorePage1(_vm->_screenBuffer);
    620620        restorePalette();
    621         _vm->saveGame(_vm->getSavegameFilename(_saveSlot), _saveDescription);
     621
     622        Graphics::Surface thumb;
     623        createScreenThumbnail(thumb);
     624        _vm->saveGame(_vm->getSavegameFilename(_saveSlot), _saveDescription, &thumb);
     625        thumb.free();
     626
    622627        _displayMenu = false;
    623628        _madeSave = true;
    624629
  • engines/kyra/saveload_mr.cpp

     
    3232
    3333namespace Kyra {
    3434
    35 void KyraEngine_MR::saveGame(const char *fileName, const char *saveName) {
    36         debugC(9, kDebugLevelMain, "KyraEngine_MR::saveGame('%s', '%s')", fileName, saveName);
     35void KyraEngine_MR::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) {
     36        debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb);
    3737
    38         Common::OutSaveFile *out = openSaveForWriting(fileName, saveName);
     38        Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);
    3939        if (!out) {
    4040                warning("Can't open file '%s', game not loadable", fileName);
    4141                return;
  • graphics/module.mk

     
    1616        primitives.o \
    1717        scaler.o \
    1818        scaler/thumbnail.o \
    19         surface.o
     19        surface.o \
     20        thumbnail.o
    2021
    2122ifndef DISABLE_SCALERS
    2223MODULE_OBJS += \
  • graphics/scaler.h

     
    8282 * @param surf  a surface (will always have 16 bpp after this for now)
    8383 * @return              false if a error occured
    8484 */
    85 extern bool createThumbnailFromScreen(Graphics::Surface* surf);
     85extern bool createThumbnailFromScreen(Graphics::Surface *surf);
    8686
     87/**
     88 * creates a surface from a buffer
     89 * @param surf      destination surface (will always have 16 bpp after this for now)
     90 * @param pixels    raw pixel data
     91 * @param w         width
     92 * @param h         height
     93 * @param palette   palette in RGB format
     94 */
     95extern bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette);
     96
    8797#endif
  • graphics/thumbnail.cpp

     
     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 * $URL$
     22 * $Id$
     23 */
     24
     25#include "graphics/thumbnail.h"
     26#include "graphics/scaler.h"
     27#include "common/endian.h"
     28#include "common/system.h"
     29
     30namespace Graphics {
     31
     32namespace {
     33#define THMB_VERSION 1
     34
     35struct ThumbnailHeader {
     36        uint32 type;
     37        uint32 size;
     38        byte version;
     39        uint16 width, height;
     40        byte bpp;
     41};
     42
     43#define ThumbnailHeaderSize (4+4+1+2+2+1)
     44
     45inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) {
     46        r = (((color >> 11) & 0x1F) << 3);
     47        g = (((color >> 5) & 0x3F) << 2);
     48        b = ((color&0x1F) << 3);
     49}
     50
     51bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool outputWarnings) {
     52        header.type = in.readUint32BE();
     53        // We also accept the bad 'BMHT' header here, for the sake of compatibility
     54        // with some older savegames which were written incorrectly due to a bug in
     55        // ScummVM which wrote the thumb header type incorrectly on LE systems.
     56        if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT')) {
     57                if (outputWarnings)
     58                        warning("couldn't find thumbnail header type");
     59                return false;
     60        }
     61
     62        header.size = in.readUint32BE();
     63        header.version = in.readByte();
     64
     65        if (header.version > THMB_VERSION) {
     66                if (outputWarnings)
     67                        warning("trying to load a newer thumbnail version: %d instead of %d", header.version, THMB_VERSION);
     68                return false;
     69        }
     70
     71        header.width = in.readUint16BE();
     72        header.height = in.readUint16BE();
     73        header.bpp = in.readByte();
     74
     75        return true;
     76}
     77} // end of anonymous namespace
     78
     79bool checkThumbnailHeader(Common::SeekableReadStream &in) {
     80        uint32 position = in.pos();
     81        ThumbnailHeader header;
     82
     83        bool hasHeader = loadHeader(in, header, false);
     84       
     85        in.seek(position, SEEK_SET);
     86
     87        return hasHeader;
     88}
     89
     90bool skipThumbnailHeader(Common::SeekableReadStream &in) {
     91        uint32 position = in.pos();
     92        ThumbnailHeader header;
     93
     94        if (!loadHeader(in, header, true)) {
     95                in.seek(position, SEEK_SET);
     96                return false;
     97        }
     98
     99        in.seek(header.size - (in.pos() - position), SEEK_CUR);
     100        return true;
     101}
     102
     103bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface &to) {
     104        ThumbnailHeader header;
     105
     106        if (!loadHeader(in, header, true))
     107                return false;
     108
     109        if (header.bpp != 2) {
     110                warning("trying to load thumbnail with unsupported bit depth %d", header.bpp);
     111                return false;
     112        }
     113
     114        to.create(header.width, header.height, sizeof(OverlayColor));
     115
     116        OverlayColor *pixels = (OverlayColor *)to.pixels;
     117        for (int y = 0; y < to.h; ++y) {
     118                for (int x = 0; x < to.w; ++x) {
     119                        uint8 r, g, b;
     120                        colorToRGB(in.readUint16BE(), r, g, b);
     121
     122                        // converting to current OSystem Color
     123                        *pixels++ = g_system->RGBToColor(r, g, b);
     124                }
     125        }
     126
     127        return true;
     128}
     129
     130bool saveThumbnail(Common::WriteStream &out) {
     131        Graphics::Surface thumb;
     132
     133        if (!createThumbnailFromScreen(&thumb)) {
     134                warning("Couldn't create thumbnail from screen, aborting thumbnail save");
     135                return false;
     136        }
     137
     138        bool success = saveThumbnail(out, thumb);
     139        thumb.free();
     140
     141        return success;
     142}
     143
     144bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb) {
     145        if (thumb.bytesPerPixel != 2) {
     146                warning("trying to save thumbnail with bpp different than 2");
     147                return false;
     148        }
     149
     150        ThumbnailHeader header;
     151        header.type = MKID_BE('THMB');
     152        header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel;
     153        header.version = THMB_VERSION;
     154        header.width = thumb.w;
     155        header.height = thumb.h;
     156        header.bpp = thumb.bytesPerPixel;
     157
     158        out.writeUint32BE(header.type);
     159        out.writeUint32BE(header.size);
     160        out.writeByte(header.version);
     161        out.writeUint16BE(header.width);
     162        out.writeUint16BE(header.height);
     163        out.writeByte(header.bpp);
     164
     165        // TODO: for later this shouldn't be casted to uint16...
     166        uint16 *pixels = (uint16 *)thumb.pixels;
     167        for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels)
     168                out.writeUint16BE(*pixels);
     169
     170        return true;
     171}
     172
     173} // end of namespace Graphics
     174
  • graphics/scaler/thumbnail.cpp

    Property changes on: graphics/thumbnail.cpp
    ___________________________________________________________________
    Added: svn:mime-type
       + text/plain
    Added: svn:keywords
       + Date Rev Author URL Id
    Added: svn:eol-style
       + native
    
     
    126126        return true;
    127127}
    128128
    129 bool createThumbnailFromScreen(Graphics::Surface* surf) {
    130         assert(surf);
     129static bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) {
     130        uint16 width = in.w;
     131        uint16 inHeight = in.h;
    131132
    132         int screenWidth = g_system->getWidth();
    133         int screenHeight = g_system->getHeight();
    134 
    135         Graphics::Surface screen;
    136 
    137         if (!grabScreen565(&screen))
    138                 return false;
    139 
    140         uint16 width = screenWidth;
    141 
    142         if (screenWidth < 320) {
     133        if (width < 320) {
    143134                // Special case to handle MM NES (uses a screen width of 256)
    144135                width = 320;
    145136
    146137                // center MM NES screen
    147138                Graphics::Surface newscreen;
    148                 newscreen.create(width, screen.h, screen.bytesPerPixel);
     139                newscreen.create(width, in.h, in.bytesPerPixel);
    149140
    150                 uint8 *dst = (uint8*)newscreen.getBasePtr((320 - screenWidth) / 2, 0);
    151                 uint8 *src = (uint8*)screen.getBasePtr(0, 0);
    152                 uint16 height = screen.h;
     141                uint8 *dst = (uint8*)newscreen.getBasePtr((320 - in.w) / 2, 0);
     142                const uint8 *src = (uint8*)in.getBasePtr(0, 0);
     143                uint16 height = in.h;
    153144
    154145                while (height--) {
    155                         memcpy(dst, src, screen.pitch);
     146                        memcpy(dst, src, in.pitch);
    156147                        dst += newscreen.pitch;
    157                         src += screen.pitch;
     148                        src += in.pitch;
    158149                }
    159150
    160                 screen.free();
    161                 screen = newscreen;
    162         } else if (screenWidth == 720) {
     151                in.free();
     152                in = newscreen;
     153        } else if (width == 720) {
    163154                // Special case to handle Hercules mode
    164155                width = 640;
    165                 screenHeight = 400;
     156                inHeight = 400;
    166157
    167158                // cut off menu and so on..
    168159                Graphics::Surface newscreen;
    169                 newscreen.create(width, 400, screen.bytesPerPixel);
     160                newscreen.create(width, 400, in.bytesPerPixel);
    170161
    171                 uint8 *dst = (uint8*)newscreen.getBasePtr(0, (400 - 240) / 2);
    172                 uint8 *src = (uint8*)screen.getBasePtr(41, 28);
     162                uint8 *dst = (uint8*)in.getBasePtr(0, (400 - 240) / 2);
     163                const uint8 *src = (uint8*)in.getBasePtr(41, 28);
    173164
    174165                for (int y = 0; y < 240; ++y) {
    175                         memcpy(dst, src, 640 * screen.bytesPerPixel);
     166                        memcpy(dst, src, 640 * in.bytesPerPixel);
    176167                        dst += newscreen.pitch;
    177                         src += screen.pitch;
     168                        src += in.pitch;
    178169                }
    179170
    180                 screen.free();
    181                 screen = newscreen;
     171                in.free();
     172                in = newscreen;
    182173        }
    183174
    184         uint16 newHeight = !(screenHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1;
     175        uint16 newHeight = !(inHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1;
    185176
    186177        int gBitFormatBackUp = gBitFormat;
    187178        gBitFormat = 565;
    188         surf->create(kThumbnailWidth, newHeight, sizeof(uint16));
    189         createThumbnail((const uint8*)screen.pixels, width * sizeof(uint16), (uint8*)surf->pixels, surf->pitch, width, screenHeight);
     179        out.create(kThumbnailWidth, newHeight, sizeof(uint16));
     180        createThumbnail((const uint8 *)in.pixels, width * sizeof(uint16), (uint8 *)out.pixels, out.pitch, width, inHeight);
    190181        gBitFormat = gBitFormatBackUp;
    191182
    192         screen.free();
     183        in.free();
    193184
    194185        return true;
    195186}
     187
     188bool createThumbnailFromScreen(Graphics::Surface* surf) {
     189        assert(surf);
     190
     191        Graphics::Surface screen;
     192
     193        if (!grabScreen565(&screen))
     194                return false;
     195
     196        return createThumbnail(*surf, screen);
     197}
     198
     199bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette) {
     200        assert(surf);
     201
     202        Graphics::Surface screen;
     203        screen.create(w, h, 2);
     204
     205        for (uint y = 0; y < screen.h; ++y) {
     206                for (uint x = 0; x < screen.w; ++x) {
     207                        byte r, g, b;
     208                        r = palette[pixels[y * w + x] * 3];
     209                        g = palette[pixels[y * w + x] * 3 + 1];
     210                        b = palette[pixels[y * w + x] * 3 + 2];
     211
     212                        ((uint16 *)screen.pixels)[y * screen.w + x] = RGBToColor<ColorMasks<565> >(r, g, b);
     213                }
     214        }
     215
     216        return createThumbnail(*surf, screen);
     217}
     218
  • graphics/thumbnail.h

     
     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 * $URL$
     22 * $Id$
     23 */
     24
     25#ifndef GRAPHICS_THUMBNAIL_H
     26#define GRAPHICS_THUMBNAIL_H
     27
     28#include "common/stream.h"
     29#include "graphics/surface.h"
     30
     31namespace Graphics {
     32
     33/**
     34 * Checks for presence of the thumbnail save header.
     35 * Seeks automatically back to start position after check.
     36 *
     37 * @param in    stream to check for header
     38 */
     39bool checkThumbnailHeader(Common::SeekableReadStream &in);
     40
     41/**
     42 * Skips a thumbnail header, if present.
     43 *
     44 * @param in    stream to process
     45 */
     46bool skipThumbnailHeader(Common::SeekableReadStream &in);
     47
     48/**
     49 * Lodas a thumbnail from the given input stream.
     50 * The loaded thumbnail will be automatically converted to the
     51 * current overlay pixelformat.
     52 */
     53bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface &to);
     54
     55/**
     56 * Saves a thumbnail to the given write stream.
     57 * Automatically creates a thumbnail from screen contents.
     58 */
     59bool saveThumbnail(Common::WriteStream &out);
     60
     61/**
     62 * Saves a (given) thumbnail to the given write stream.
     63 */
     64bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb);
     65
     66} // end of namespace Graphics
     67
     68#endif
     69