Committed patch #2050337 "KYRA/SCUMM: Thumbnail support/improvement". (Without Max' compressed backward seeking support for now)
svn-id: r34053
This commit is contained in:
parent
a79e9385a1
commit
f4fc8c3e4c
32 changed files with 464 additions and 164 deletions
|
@ -1117,7 +1117,7 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const {
|
||||||
if (slotNum >= 0 && slotNum <= 999) {
|
if (slotNum >= 0 && slotNum <= 999) {
|
||||||
Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
|
Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
|
||||||
if (in) {
|
if (in) {
|
||||||
if (Kyra::KyraEngine_v1::readSaveHeader(in, header) == Kyra::KyraEngine_v1::kRSHENoError)
|
if (Kyra::KyraEngine_v1::readSaveHeader(in, false, header) == Kyra::KyraEngine_v1::kRSHENoError)
|
||||||
saveList.push_back(SaveStateDescriptor(slotNum, header.description, *file));
|
saveList.push_back(SaveStateDescriptor(slotNum, header.description, *file));
|
||||||
delete in;
|
delete in;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include "common/array.h"
|
#include "common/array.h"
|
||||||
#include "common/func.h"
|
#include "common/func.h"
|
||||||
|
|
||||||
|
#include "graphics/surface.h"
|
||||||
|
|
||||||
namespace Kyra {
|
namespace Kyra {
|
||||||
|
|
||||||
#define BUTTON_FUNCTOR(type, x, y) Button::Callback(new Common::Functor1Mem<Button*, int, type>(x, y))
|
#define BUTTON_FUNCTOR(type, x, y) Button::Callback(new Common::Functor1Mem<Button*, int, type>(x, y))
|
||||||
|
@ -153,6 +155,8 @@ public:
|
||||||
|
|
||||||
void processHighlights(Menu &menu, int mouseX, int mouseY);
|
void processHighlights(Menu &menu, int mouseX, int mouseY);
|
||||||
|
|
||||||
|
// utilities for thumbnail creation
|
||||||
|
virtual void createScreenThumbnail(Graphics::Surface &dst) = 0;
|
||||||
protected:
|
protected:
|
||||||
KyraEngine_v1 *_vm;
|
KyraEngine_v1 *_vm;
|
||||||
Screen *_screen;
|
Screen *_screen;
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
|
|
||||||
#include "common/savefile.h"
|
#include "common/savefile.h"
|
||||||
|
|
||||||
|
#include "graphics/scaler.h"
|
||||||
|
|
||||||
namespace Kyra {
|
namespace Kyra {
|
||||||
|
|
||||||
void KyraEngine_HoF::loadButtonShapes() {
|
void KyraEngine_HoF::loadButtonShapes() {
|
||||||
|
@ -793,6 +795,10 @@ int GUI_HoF::optionsButton(Button *button) {
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
|
void GUI_HoF::createScreenThumbnail(Graphics::Surface &dst) {
|
||||||
|
::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(1));
|
||||||
|
}
|
||||||
|
|
||||||
void GUI_HoF::setupPalette() {
|
void GUI_HoF::setupPalette() {
|
||||||
memcpy(_screen->getPalette(1), _screen->getPalette(0), 768);
|
memcpy(_screen->getPalette(1), _screen->getPalette(0), 768);
|
||||||
|
|
||||||
|
@ -996,7 +1002,7 @@ int GUI_HoF::gameOptionsTalkie(Button *caller) {
|
||||||
|
|
||||||
if (_vm->_lang != lang) {
|
if (_vm->_lang != lang) {
|
||||||
_reloadTemporarySave = true;
|
_reloadTemporarySave = true;
|
||||||
_vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 2 Savegame");
|
_vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 2 Savegame", 0);
|
||||||
_vm->loadCCodeBuffer("C_CODE.XXX");
|
_vm->loadCCodeBuffer("C_CODE.XXX");
|
||||||
if (_vm->_flags.isTalkie)
|
if (_vm->_flags.isTalkie)
|
||||||
_vm->loadOptionsBuffer("OPTIONS.XXX");
|
_vm->loadOptionsBuffer("OPTIONS.XXX");
|
||||||
|
|
|
@ -41,6 +41,8 @@ public:
|
||||||
void initStaticData();
|
void initStaticData();
|
||||||
|
|
||||||
int optionsButton(Button *button);
|
int optionsButton(Button *button);
|
||||||
|
|
||||||
|
void createScreenThumbnail(Graphics::Surface &dst);
|
||||||
private:
|
private:
|
||||||
const char *getMenuTitle(const Menu &menu);
|
const char *getMenuTitle(const Menu &menu);
|
||||||
const char *getMenuItemTitle(const MenuItem &menuItem);
|
const char *getMenuItemTitle(const MenuItem &menuItem);
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
#include "common/events.h"
|
#include "common/events.h"
|
||||||
#include "common/system.h"
|
#include "common/system.h"
|
||||||
|
|
||||||
|
#include "graphics/scaler.h"
|
||||||
|
|
||||||
namespace Kyra {
|
namespace Kyra {
|
||||||
|
|
||||||
void KyraEngine_LoK::initMainButtonList() {
|
void KyraEngine_LoK::initMainButtonList() {
|
||||||
|
@ -199,6 +201,15 @@ GUI_LoK::~GUI_LoK() {
|
||||||
delete[] _menu;
|
delete[] _menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUI_LoK::createScreenThumbnail(Graphics::Surface &dst) {
|
||||||
|
uint8 *screen = new uint8[Screen::SCREEN_W*Screen::SCREEN_H];
|
||||||
|
if (screen) {
|
||||||
|
_screen->queryPageFromDisk("SEENPAGE.TMP", 0, screen);
|
||||||
|
::createThumbnail(&dst, screen, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(2));
|
||||||
|
}
|
||||||
|
delete[] screen;
|
||||||
|
}
|
||||||
|
|
||||||
int GUI_LoK::processButtonList(Button *list, uint16 inputFlag, int8 mouseWheel) {
|
int GUI_LoK::processButtonList(Button *list, uint16 inputFlag, int8 mouseWheel) {
|
||||||
while (list) {
|
while (list) {
|
||||||
if (list->flags & 8) {
|
if (list->flags & 8) {
|
||||||
|
@ -736,8 +747,12 @@ int GUI_LoK::saveGame(Button *button) {
|
||||||
} else {
|
} else {
|
||||||
if (_savegameOffset == 0 && _vm->_gameToLoad == 0)
|
if (_savegameOffset == 0 && _vm->_gameToLoad == 0)
|
||||||
_vm->_gameToLoad = getNextSavegameSlot();
|
_vm->_gameToLoad = getNextSavegameSlot();
|
||||||
if (_vm->_gameToLoad > 0)
|
if (_vm->_gameToLoad > 0) {
|
||||||
_vm->saveGame(_vm->getSavegameFilename(_vm->_gameToLoad), _savegameName);
|
Graphics::Surface thumb;
|
||||||
|
createScreenThumbnail(thumb);
|
||||||
|
_vm->saveGame(_vm->getSavegameFilename(_vm->_gameToLoad), _savegameName, &thumb);
|
||||||
|
thumb.free();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -103,6 +103,8 @@ public:
|
||||||
int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel);
|
int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel);
|
||||||
|
|
||||||
int buttonMenuCallback(Button *caller);
|
int buttonMenuCallback(Button *caller);
|
||||||
|
|
||||||
|
void createScreenThumbnail(Graphics::Surface &dst);
|
||||||
private:
|
private:
|
||||||
void initStaticResource();
|
void initStaticResource();
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
|
|
||||||
#include "common/savefile.h"
|
#include "common/savefile.h"
|
||||||
|
|
||||||
|
#include "graphics/scaler.h"
|
||||||
|
|
||||||
namespace Kyra {
|
namespace Kyra {
|
||||||
|
|
||||||
void KyraEngine_MR::loadButtonShapes() {
|
void KyraEngine_MR::loadButtonShapes() {
|
||||||
|
@ -1138,6 +1140,10 @@ int KyraEngine_MR::albumClose(Button *caller) {
|
||||||
GUI_MR::GUI_MR(KyraEngine_MR *vm) : GUI_v2(vm), _vm(vm), _screen(vm->_screen) {
|
GUI_MR::GUI_MR(KyraEngine_MR *vm) : GUI_v2(vm), _vm(vm), _screen(vm->_screen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUI_MR::createScreenThumbnail(Graphics::Surface &dst) {
|
||||||
|
::createThumbnail(&dst, _vm->_screenBuffer, Screen::SCREEN_W, Screen::SCREEN_H, _screen->getPalette(0));
|
||||||
|
}
|
||||||
|
|
||||||
void GUI_MR::flagButtonEnable(Button *button) {
|
void GUI_MR::flagButtonEnable(Button *button) {
|
||||||
if (!button)
|
if (!button)
|
||||||
return;
|
return;
|
||||||
|
@ -1450,7 +1456,7 @@ int GUI_MR::gameOptions(Button *caller) {
|
||||||
|
|
||||||
if (_vm->_lang != lang) {
|
if (_vm->_lang != lang) {
|
||||||
_reloadTemporarySave = true;
|
_reloadTemporarySave = true;
|
||||||
_vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 3 Savegame");
|
_vm->saveGame(_vm->getSavegameFilename(999), "Temporary Kyrandia 3 Savegame", 0);
|
||||||
if (!_vm->loadLanguageFile("ITEMS.", _vm->_itemFile))
|
if (!_vm->loadLanguageFile("ITEMS.", _vm->_itemFile))
|
||||||
error("Couldn't load ITEMS");
|
error("Couldn't load ITEMS");
|
||||||
if (!_vm->loadLanguageFile("SCORE.", _vm->_scoreFile))
|
if (!_vm->loadLanguageFile("SCORE.", _vm->_scoreFile))
|
||||||
|
|
|
@ -47,6 +47,8 @@ public:
|
||||||
int redrawButtonCallback(Button *button);
|
int redrawButtonCallback(Button *button);
|
||||||
|
|
||||||
int optionsButton(Button *button);
|
int optionsButton(Button *button);
|
||||||
|
|
||||||
|
void createScreenThumbnail(Graphics::Surface &dst);
|
||||||
private:
|
private:
|
||||||
void getInput();
|
void getInput();
|
||||||
|
|
||||||
|
|
|
@ -618,7 +618,12 @@ int GUI_v2::saveMenu(Button *caller) {
|
||||||
|
|
||||||
restorePage1(_vm->_screenBuffer);
|
restorePage1(_vm->_screenBuffer);
|
||||||
restorePalette();
|
restorePalette();
|
||||||
_vm->saveGame(_vm->getSavegameFilename(_saveSlot), _saveDescription);
|
|
||||||
|
Graphics::Surface thumb;
|
||||||
|
createScreenThumbnail(thumb);
|
||||||
|
_vm->saveGame(_vm->getSavegameFilename(_saveSlot), _saveDescription, &thumb);
|
||||||
|
thumb.free();
|
||||||
|
|
||||||
_displayMenu = false;
|
_displayMenu = false;
|
||||||
_madeSave = true;
|
_madeSave = true;
|
||||||
|
|
||||||
|
|
|
@ -436,7 +436,7 @@ void KyraEngine_HoF::startup() {
|
||||||
if (_gameToLoad == -1) {
|
if (_gameToLoad == -1) {
|
||||||
snd_playWanderScoreViaMap(52, 1);
|
snd_playWanderScoreViaMap(52, 1);
|
||||||
enterNewScene(_mainCharacter.sceneId, _mainCharacter.facing, 0, 0, 1);
|
enterNewScene(_mainCharacter.sceneId, _mainCharacter.facing, 0, 0, 1);
|
||||||
saveGame(getSavegameFilename(0), "New Game");
|
saveGame(getSavegameFilename(0), "New Game", 0);
|
||||||
} else {
|
} else {
|
||||||
loadGame(getSavegameFilename(_gameToLoad));
|
loadGame(getSavegameFilename(_gameToLoad));
|
||||||
}
|
}
|
||||||
|
|
|
@ -907,7 +907,7 @@ protected:
|
||||||
int _dbgPass;
|
int _dbgPass;
|
||||||
|
|
||||||
// save/load specific
|
// save/load specific
|
||||||
void saveGame(const char *fileName, const char *saveName);
|
void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail);
|
||||||
void loadGame(const char *fileName);
|
void loadGame(const char *fileName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -388,7 +388,7 @@ void KyraEngine_LoK::startup() {
|
||||||
_gui->buttonMenuCallback(0);
|
_gui->buttonMenuCallback(0);
|
||||||
_menuDirectlyToLoad = false;
|
_menuDirectlyToLoad = false;
|
||||||
} else
|
} else
|
||||||
saveGame(getSavegameFilename(0), "New game");
|
saveGame(getSavegameFilename(0), "New game", 0);
|
||||||
} else {
|
} else {
|
||||||
_screen->setFont(Screen::FID_8_FNT);
|
_screen->setFont(Screen::FID_8_FNT);
|
||||||
loadGame(getSavegameFilename(_gameToLoad));
|
loadGame(getSavegameFilename(_gameToLoad));
|
||||||
|
@ -470,7 +470,7 @@ void KyraEngine_LoK::delay(uint32 amount, bool update, bool isMainLoop) {
|
||||||
else {
|
else {
|
||||||
char savegameName[14];
|
char savegameName[14];
|
||||||
sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0');
|
sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0');
|
||||||
saveGame(saveLoadSlot, savegameName);
|
saveGame(saveLoadSlot, savegameName, 0);
|
||||||
}
|
}
|
||||||
} else if (event.kbd.flags == Common::KBD_CTRL) {
|
} else if (event.kbd.flags == Common::KBD_CTRL) {
|
||||||
if (event.kbd.keycode == 'd')
|
if (event.kbd.keycode == 'd')
|
||||||
|
|
|
@ -214,7 +214,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
int32 _speechPlayTime;
|
int32 _speechPlayTime;
|
||||||
|
|
||||||
void saveGame(const char *fileName, const char *saveName);
|
void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail);
|
||||||
void loadGame(const char *fileName);
|
void loadGame(const char *fileName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -684,7 +684,7 @@ void KyraEngine_MR::startup() {
|
||||||
assert(_invWsa);
|
assert(_invWsa);
|
||||||
_invWsa->open("MOODOMTR.WSA", 1, 0);
|
_invWsa->open("MOODOMTR.WSA", 1, 0);
|
||||||
_invWsaFrame = 6;
|
_invWsaFrame = 6;
|
||||||
saveGame(getSavegameFilename(0), (const char*)getTableEntry(_optionsFile, 33));
|
saveGame(getSavegameFilename(0), (const char*)getTableEntry(_optionsFile, 33), 0);
|
||||||
_soundDigital->beginFadeOut(_musicSoundChannel, 60);
|
_soundDigital->beginFadeOut(_musicSoundChannel, 60);
|
||||||
delayWithTicks(60);
|
delayWithTicks(60);
|
||||||
if (_gameToLoad == -1)
|
if (_gameToLoad == -1)
|
||||||
|
|
|
@ -583,7 +583,7 @@ private:
|
||||||
int albumClose(Button *caller);
|
int albumClose(Button *caller);
|
||||||
|
|
||||||
// save/load
|
// save/load
|
||||||
void saveGame(const char *fileName, const char *saveName);
|
void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail);
|
||||||
void loadGame(const char *fileName);
|
void loadGame(const char *fileName);
|
||||||
|
|
||||||
// opcodes
|
// opcodes
|
||||||
|
|
|
@ -290,6 +290,8 @@ protected:
|
||||||
|
|
||||||
bool originalSave; // savegame from original interpreter
|
bool originalSave; // savegame from original interpreter
|
||||||
bool oldHeader; // old scummvm save header
|
bool oldHeader; // old scummvm save header
|
||||||
|
|
||||||
|
Graphics::Surface *thumbnail;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum kReadSaveHeaderError {
|
enum kReadSaveHeaderError {
|
||||||
|
@ -299,10 +301,10 @@ protected:
|
||||||
kRSHEIoError = 3
|
kRSHEIoError = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, SaveHeader &header);
|
static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, bool loadThumbnail, SaveHeader &header);
|
||||||
|
|
||||||
Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header);
|
Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header);
|
||||||
Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName) const;
|
Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Kyra
|
} // End of namespace Kyra
|
||||||
|
|
|
@ -186,7 +186,7 @@ int KyraEngine_v2::checkInput(Button *buttonList, bool mainLoop) {
|
||||||
} else {
|
} else {
|
||||||
char savegameName[14];
|
char savegameName[14];
|
||||||
sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0');
|
sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0');
|
||||||
saveGame(saveLoadSlot, savegameName);
|
saveGame(saveLoadSlot, savegameName, 0);
|
||||||
}
|
}
|
||||||
} else if (event.kbd.flags == Common::KBD_CTRL) {
|
} else if (event.kbd.flags == Common::KBD_CTRL) {
|
||||||
if (event.kbd.keycode == 'd')
|
if (event.kbd.keycode == 'd')
|
||||||
|
|
|
@ -419,7 +419,7 @@ protected:
|
||||||
int o2_getVocHigh(EMCState *script);
|
int o2_getVocHigh(EMCState *script);
|
||||||
|
|
||||||
// save/load specific
|
// save/load specific
|
||||||
virtual void saveGame(const char *fileName, const char *saveName) = 0;
|
virtual void saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumbnail) = 0;
|
||||||
virtual void loadGame(const char *fileName) = 0;
|
virtual void loadGame(const char *fileName) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,11 @@
|
||||||
#include "common/endian.h"
|
#include "common/endian.h"
|
||||||
#include "common/savefile.h"
|
#include "common/savefile.h"
|
||||||
#include "common/system.h"
|
#include "common/system.h"
|
||||||
|
#include "graphics/thumbnail.h"
|
||||||
|
|
||||||
#include "kyra/kyra_v1.h"
|
#include "kyra/kyra_v1.h"
|
||||||
|
|
||||||
#define CURRENT_SAVE_VERSION 13
|
#define CURRENT_SAVE_VERSION 14
|
||||||
|
|
||||||
#define GF_FLOPPY (1 << 0)
|
#define GF_FLOPPY (1 << 0)
|
||||||
#define GF_TALKIE (1 << 1)
|
#define GF_TALKIE (1 << 1)
|
||||||
|
@ -37,7 +38,7 @@
|
||||||
|
|
||||||
namespace Kyra {
|
namespace Kyra {
|
||||||
|
|
||||||
KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header) {
|
KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
|
||||||
uint32 type = in->readUint32BE();
|
uint32 type = in->readUint32BE();
|
||||||
header.originalSave = false;
|
header.originalSave = false;
|
||||||
header.oldHeader = false;
|
header.oldHeader = false;
|
||||||
|
@ -108,6 +109,16 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab
|
||||||
if (header.version >= 2)
|
if (header.version >= 2)
|
||||||
header.flags = in->readUint32BE();
|
header.flags = in->readUint32BE();
|
||||||
|
|
||||||
|
if (header.version >= 14) {
|
||||||
|
if (loadThumbnail) {
|
||||||
|
header.thumbnail = new Graphics::Surface();
|
||||||
|
assert(header.thumbnail);
|
||||||
|
Graphics::loadThumbnail(*in, *header.thumbnail);
|
||||||
|
} else {
|
||||||
|
Graphics::skipThumbnailHeader(*in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (in->ioFailed() ? kRSHEIoError : kRSHENoError);
|
return (in->ioFailed() ? kRSHEIoError : kRSHENoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +129,7 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena
|
||||||
if (!(in = _saveFileMan->openForLoading(filename)))
|
if (!(in = _saveFileMan->openForLoading(filename)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, header);
|
kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, false, header);
|
||||||
if (errorCode != kRSHENoError) {
|
if (errorCode != kRSHENoError) {
|
||||||
if (errorCode == kRSHEInvalidType)
|
if (errorCode == kRSHEInvalidType)
|
||||||
warning("No ScummVM Kyra engine savefile header.");
|
warning("No ScummVM Kyra engine savefile header.");
|
||||||
|
@ -162,8 +173,8 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName) const {
|
Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const {
|
||||||
debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s')", filename, saveName);
|
debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s', %p)", filename, saveName, (const void *)thumbnail);
|
||||||
if (_quitFlag)
|
if (_quitFlag)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -191,6 +202,11 @@ Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, con
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thumbnail)
|
||||||
|
Graphics::saveThumbnail(*out, *thumbnail);
|
||||||
|
else
|
||||||
|
Graphics::saveThumbnail(*out);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,10 +35,10 @@
|
||||||
|
|
||||||
namespace Kyra {
|
namespace Kyra {
|
||||||
|
|
||||||
void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName) {
|
void KyraEngine_HoF::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) {
|
||||||
debugC(9, kDebugLevelMain, "KyraEngine_HoF::saveGame('%s', '%s')", fileName, saveName);
|
debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb);
|
||||||
|
|
||||||
Common::OutSaveFile *out = openSaveForWriting(fileName, saveName);
|
Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
warning("Can't open file '%s', game not loadable", fileName);
|
warning("Can't open file '%s', game not loadable", fileName);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -218,13 +218,13 @@ void KyraEngine_LoK::loadGame(const char *fileName) {
|
||||||
delete in;
|
delete in;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName) {
|
void KyraEngine_LoK::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) {
|
||||||
debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s')", fileName, saveName);
|
debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb);
|
||||||
|
|
||||||
if (_quitFlag)
|
if (_quitFlag)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Common::OutSaveFile *out = openSaveForWriting(fileName, saveName);
|
Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);
|
||||||
if (!out)
|
if (!out)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -32,10 +32,10 @@
|
||||||
|
|
||||||
namespace Kyra {
|
namespace Kyra {
|
||||||
|
|
||||||
void KyraEngine_MR::saveGame(const char *fileName, const char *saveName) {
|
void KyraEngine_MR::saveGame(const char *fileName, const char *saveName, const Graphics::Surface *thumb) {
|
||||||
debugC(9, kDebugLevelMain, "KyraEngine_MR::saveGame('%s', '%s')", fileName, saveName);
|
debugC(9, kDebugLevelMain, "KyraEngine_LoK::saveGame('%s', '%s', %p)", fileName, saveName, (const void *)thumb);
|
||||||
|
|
||||||
Common::OutSaveFile *out = openSaveForWriting(fileName, saveName);
|
Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
warning("Can't open file '%s', game not loadable", fileName);
|
warning("Can't open file '%s', game not loadable", fileName);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -147,8 +147,14 @@ void Screen_LoK::savePageToDisk(const char *file, int page) {
|
||||||
|
|
||||||
void Screen_LoK::loadPageFromDisk(const char *file, int page) {
|
void Screen_LoK::loadPageFromDisk(const char *file, int page) {
|
||||||
debugC(9, kDebugLevelScreen, "Screen_LoK::loadPageFromDisk('%s', %d)", file, page);
|
debugC(9, kDebugLevelScreen, "Screen_LoK::loadPageFromDisk('%s', %d)", file, page);
|
||||||
|
if (!_saveLoadPage[page/2]) {
|
||||||
|
warning("trying to restore page %d, but no backup found", page);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
copyBlockToPage(page, 0, 0, SCREEN_W, SCREEN_H, _saveLoadPage[page/2]);
|
copyBlockToPage(page, 0, 0, SCREEN_W, SCREEN_H, _saveLoadPage[page/2]);
|
||||||
delete[] _saveLoadPage[page/2];
|
delete[] _saveLoadPage[page/2];
|
||||||
|
_saveLoadPage[page/2] = 0;
|
||||||
|
|
||||||
if (_saveLoadPageOvl[page/2]) {
|
if (_saveLoadPageOvl[page/2]) {
|
||||||
uint8 *dstPage = getOverlayPtr(page);
|
uint8 *dstPage = getOverlayPtr(page);
|
||||||
|
@ -160,7 +166,17 @@ void Screen_LoK::loadPageFromDisk(const char *file, int page) {
|
||||||
memcpy(dstPage, _saveLoadPageOvl[page/2], SCREEN_OVL_SJIS_SIZE);
|
memcpy(dstPage, _saveLoadPageOvl[page/2], SCREEN_OVL_SJIS_SIZE);
|
||||||
delete[] _saveLoadPageOvl[page/2];
|
delete[] _saveLoadPageOvl[page/2];
|
||||||
_saveLoadPageOvl[page/2] = 0;
|
_saveLoadPageOvl[page/2] = 0;
|
||||||
} _saveLoadPage[page/2] = 0;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen_LoK::queryPageFromDisk(const char *file, int page, uint8 *buffer) {
|
||||||
|
debugC(9, kDebugLevelScreen, "Screen_LoK::queryPageFromDisk('%s', %d, %p)", file, page, (const void *)buffer);
|
||||||
|
if (!_saveLoadPage[page/2]) {
|
||||||
|
warning("trying to query page %d, but no backup found", page);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer, _saveLoadPage[page/2], SCREEN_W*SCREEN_H);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen_LoK::deletePageFromDisk(int page) {
|
void Screen_LoK::deletePageFromDisk(int page) {
|
||||||
|
|
|
@ -50,6 +50,7 @@ public:
|
||||||
|
|
||||||
void savePageToDisk(const char *file, int page);
|
void savePageToDisk(const char *file, int page);
|
||||||
void loadPageFromDisk(const char *file, int page);
|
void loadPageFromDisk(const char *file, int page);
|
||||||
|
void queryPageFromDisk(const char *file, int page, uint8 *buffer);
|
||||||
void deletePageFromDisk(int page);
|
void deletePageFromDisk(int page);
|
||||||
|
|
||||||
void copyBackgroundBlock(int x, int page, int flag);
|
void copyBackgroundBlock(int x, int page, int flag);
|
||||||
|
|
|
@ -293,7 +293,7 @@ int KyraEngine_MR::o3_updateScore(EMCState *script) {
|
||||||
|
|
||||||
int KyraEngine_MR::o3_makeSecondChanceSave(EMCState *script) {
|
int KyraEngine_MR::o3_makeSecondChanceSave(EMCState *script) {
|
||||||
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_makeSecondChanceSave(%p) ()", (const void *)script);
|
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_MR::o3_makeSecondChanceSave(%p) ()", (const void *)script);
|
||||||
saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME");
|
saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME", 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ void KyraEngine_MR::timerRunSceneScript7(int arg) {
|
||||||
void KyraEngine_MR::timerFleaDeath(int arg) {
|
void KyraEngine_MR::timerFleaDeath(int arg) {
|
||||||
debugC(9, kDebugLevelMain | kDebugLevelTimer, "KyraEngine_MR::timerFleaDeath(%d)", arg);
|
debugC(9, kDebugLevelMain | kDebugLevelTimer, "KyraEngine_MR::timerFleaDeath(%d)", arg);
|
||||||
_timer->setCountdown(4, 5400);
|
_timer->setCountdown(4, 5400);
|
||||||
saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME");
|
saveGame(getSavegameFilename(999), "SECOND CHANCE SAVE GAME", 0);
|
||||||
_screen->hideMouse();
|
_screen->hideMouse();
|
||||||
_timer->disable(4);
|
_timer->disable(4);
|
||||||
runAnimationScript("FLEADTH1.EMC", 0, 0, 1, 1);
|
runAnimationScript("FLEADTH1.EMC", 0, 0, 1, 1);
|
||||||
|
|
|
@ -27,76 +27,39 @@
|
||||||
#include "common/system.h"
|
#include "common/system.h"
|
||||||
#include "common/savefile.h"
|
#include "common/savefile.h"
|
||||||
#include "graphics/scaler.h"
|
#include "graphics/scaler.h"
|
||||||
|
#include "graphics/thumbnail.h"
|
||||||
#include "scumm/scumm.h"
|
#include "scumm/scumm.h"
|
||||||
|
|
||||||
namespace Scumm {
|
namespace Scumm {
|
||||||
|
|
||||||
#define THMB_VERSION 1
|
|
||||||
|
|
||||||
struct ThumbnailHeader {
|
|
||||||
uint32 type;
|
|
||||||
uint32 size;
|
|
||||||
byte version;
|
|
||||||
uint16 width, height;
|
|
||||||
byte bpp;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ThumbnailHeaderSize (4+4+1+2+2+1)
|
|
||||||
|
|
||||||
inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) {
|
|
||||||
r = (((color >> 11) & 0x1F) << 3);
|
|
||||||
g = (((color >> 5) & 0x3F) << 2);
|
|
||||||
b = ((color&0x1F) << 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
Graphics::Surface *ScummEngine::loadThumbnail(Common::SeekableReadStream *file) {
|
Graphics::Surface *ScummEngine::loadThumbnail(Common::SeekableReadStream *file) {
|
||||||
ThumbnailHeader header;
|
// TODO: Until backwards seeking in compressed save files is not supported
|
||||||
|
// We can not use this.
|
||||||
|
|
||||||
header.type = file->readUint32BE();
|
//if (!Graphics::checkThumbnailHeader(*file))
|
||||||
// We also accept the bad 'BMHT' header here, for the sake of compatibility
|
// return 0;
|
||||||
// with some older savegames which were written incorrectly due to a bug in
|
|
||||||
// ScummVM which wrote the thumb header type incorrectly on LE systems.
|
|
||||||
if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT'))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
header.size = file->readUint32BE();
|
|
||||||
header.version = file->readByte();
|
|
||||||
|
|
||||||
if (header.version > THMB_VERSION) {
|
|
||||||
file->skip(header.size - 9);
|
|
||||||
warning("Loading a newer thumbnail version");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
header.width = file->readUint16BE();
|
|
||||||
header.height = file->readUint16BE();
|
|
||||||
header.bpp = file->readByte();
|
|
||||||
|
|
||||||
// TODO: support other bpp values than 2
|
|
||||||
if (header.bpp != 2) {
|
|
||||||
file->skip(header.size - 14);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Graphics::Surface *thumb = new Graphics::Surface();
|
Graphics::Surface *thumb = new Graphics::Surface();
|
||||||
thumb->create(header.width, header.height, sizeof(OverlayColor));
|
assert(thumb);
|
||||||
|
if (!Graphics::loadThumbnail(*file, *thumb)) {
|
||||||
OverlayColor* pixels = (OverlayColor *)thumb->pixels;
|
delete thumb;
|
||||||
|
return 0;
|
||||||
for (int y = 0; y < thumb->h; ++y) {
|
|
||||||
for (int x = 0; x < thumb->w; ++x) {
|
|
||||||
uint8 r, g, b;
|
|
||||||
colorToRGB(file->readUint16BE(), r, g, b);
|
|
||||||
|
|
||||||
// converting to current OSystem Color
|
|
||||||
*pixels++ = _system->RGBToColor(r, g, b);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return thumb;
|
return thumb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScummEngine::saveThumbnail(Common::OutSaveFile *file) {
|
void ScummEngine::saveThumbnail(Common::OutSaveFile *file) {
|
||||||
|
// Until we support no thumbnails in the SCUMM save formats for NDS
|
||||||
|
// we save a dummy thumbnail.
|
||||||
|
//
|
||||||
|
// TODO: Actually all what has to be done about it, is to update
|
||||||
|
// the code in engines/scumm/saveload.o which skips the saveheader.
|
||||||
|
// Currently impossible because of lacking backward seek support for
|
||||||
|
// compressed save files.
|
||||||
|
// When we change that code to use the new API from graphics/thumbnail.h
|
||||||
|
// it should be all fine to save no header at all for NDS.
|
||||||
|
|
||||||
Graphics::Surface thumb;
|
Graphics::Surface thumb;
|
||||||
|
|
||||||
#if !defined(__DS__)
|
#if !defined(__DS__)
|
||||||
|
@ -104,26 +67,7 @@ void ScummEngine::saveThumbnail(Common::OutSaveFile *file) {
|
||||||
#endif
|
#endif
|
||||||
thumb.create(kThumbnailWidth, kThumbnailHeight2, sizeof(uint16));
|
thumb.create(kThumbnailWidth, kThumbnailHeight2, sizeof(uint16));
|
||||||
|
|
||||||
ThumbnailHeader header;
|
Graphics::saveThumbnail(*file, thumb);
|
||||||
header.type = MKID_BE('THMB');
|
|
||||||
header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel;
|
|
||||||
header.version = THMB_VERSION;
|
|
||||||
header.width = thumb.w;
|
|
||||||
header.height = thumb.h;
|
|
||||||
header.bpp = thumb.bytesPerPixel;
|
|
||||||
|
|
||||||
file->writeUint32BE(header.type);
|
|
||||||
file->writeUint32BE(header.size);
|
|
||||||
file->writeByte(header.version);
|
|
||||||
file->writeUint16BE(header.width);
|
|
||||||
file->writeUint16BE(header.height);
|
|
||||||
file->writeByte(header.bpp);
|
|
||||||
|
|
||||||
// TODO: for later this shouldn't be casted to uint16...
|
|
||||||
uint16* pixels = (uint16 *)thumb.pixels;
|
|
||||||
for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels)
|
|
||||||
file->writeUint16BE(*pixels);
|
|
||||||
|
|
||||||
thumb.free();
|
thumb.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@ MODULE_OBJS := \
|
||||||
primitives.o \
|
primitives.o \
|
||||||
scaler.o \
|
scaler.o \
|
||||||
scaler/thumbnail.o \
|
scaler/thumbnail.o \
|
||||||
surface.o
|
surface.o \
|
||||||
|
thumbnail.o
|
||||||
|
|
||||||
ifndef DISABLE_SCALERS
|
ifndef DISABLE_SCALERS
|
||||||
MODULE_OBJS += \
|
MODULE_OBJS += \
|
||||||
|
|
|
@ -78,10 +78,22 @@ enum {
|
||||||
extern void createThumbnail(const uint8* src, uint32 srcPitch, uint8* dstPtr, uint32 dstPitch, int width, int height);
|
extern void createThumbnail(const uint8* src, uint32 srcPitch, uint8* dstPtr, uint32 dstPitch, int width, int height);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates a thumbnail from the current screen (without overlay)
|
* Creates a thumbnail from the current screen (without overlay).
|
||||||
|
*
|
||||||
* @param surf a surface (will always have 16 bpp after this for now)
|
* @param surf a surface (will always have 16 bpp after this for now)
|
||||||
* @return false if a error occured
|
* @return false if a error occured
|
||||||
*/
|
*/
|
||||||
extern bool createThumbnailFromScreen(Graphics::Surface* surf);
|
extern bool createThumbnailFromScreen(Graphics::Surface *surf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a thumbnail from a buffer.
|
||||||
|
*
|
||||||
|
* @param surf destination surface (will always have 16 bpp after this for now)
|
||||||
|
* @param pixels raw pixel data
|
||||||
|
* @param w width
|
||||||
|
* @param h height
|
||||||
|
* @param palette palette in RGB format
|
||||||
|
*/
|
||||||
|
extern bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -126,70 +126,93 @@ static bool grabScreen565(Graphics::Surface *surf) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool createThumbnail(Graphics::Surface &out, Graphics::Surface &in) {
|
||||||
|
uint16 width = in.w;
|
||||||
|
uint16 inHeight = in.h;
|
||||||
|
|
||||||
|
if (width < 320) {
|
||||||
|
// Special case to handle MM NES (uses a screen width of 256)
|
||||||
|
width = 320;
|
||||||
|
|
||||||
|
// center MM NES screen
|
||||||
|
Graphics::Surface newscreen;
|
||||||
|
newscreen.create(width, in.h, in.bytesPerPixel);
|
||||||
|
|
||||||
|
uint8 *dst = (uint8*)newscreen.getBasePtr((320 - in.w) / 2, 0);
|
||||||
|
const uint8 *src = (uint8*)in.getBasePtr(0, 0);
|
||||||
|
uint16 height = in.h;
|
||||||
|
|
||||||
|
while (height--) {
|
||||||
|
memcpy(dst, src, in.pitch);
|
||||||
|
dst += newscreen.pitch;
|
||||||
|
src += in.pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
in.free();
|
||||||
|
in = newscreen;
|
||||||
|
} else if (width == 720) {
|
||||||
|
// Special case to handle Hercules mode
|
||||||
|
width = 640;
|
||||||
|
inHeight = 400;
|
||||||
|
|
||||||
|
// cut off menu and so on..
|
||||||
|
Graphics::Surface newscreen;
|
||||||
|
newscreen.create(width, 400, in.bytesPerPixel);
|
||||||
|
|
||||||
|
uint8 *dst = (uint8*)in.getBasePtr(0, (400 - 240) / 2);
|
||||||
|
const uint8 *src = (uint8*)in.getBasePtr(41, 28);
|
||||||
|
|
||||||
|
for (int y = 0; y < 240; ++y) {
|
||||||
|
memcpy(dst, src, 640 * in.bytesPerPixel);
|
||||||
|
dst += newscreen.pitch;
|
||||||
|
src += in.pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
in.free();
|
||||||
|
in = newscreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 newHeight = !(inHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1;
|
||||||
|
|
||||||
|
int gBitFormatBackUp = gBitFormat;
|
||||||
|
gBitFormat = 565;
|
||||||
|
out.create(kThumbnailWidth, newHeight, sizeof(uint16));
|
||||||
|
createThumbnail((const uint8 *)in.pixels, width * sizeof(uint16), (uint8 *)out.pixels, out.pitch, width, inHeight);
|
||||||
|
gBitFormat = gBitFormatBackUp;
|
||||||
|
|
||||||
|
in.free();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool createThumbnailFromScreen(Graphics::Surface* surf) {
|
bool createThumbnailFromScreen(Graphics::Surface* surf) {
|
||||||
assert(surf);
|
assert(surf);
|
||||||
|
|
||||||
int screenWidth = g_system->getWidth();
|
|
||||||
int screenHeight = g_system->getHeight();
|
|
||||||
|
|
||||||
Graphics::Surface screen;
|
Graphics::Surface screen;
|
||||||
|
|
||||||
if (!grabScreen565(&screen))
|
if (!grabScreen565(&screen))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint16 width = screenWidth;
|
return createThumbnail(*surf, screen);
|
||||||
|
}
|
||||||
|
|
||||||
if (screenWidth < 320) {
|
bool createThumbnail(Graphics::Surface *surf, const uint8 *pixels, int w, int h, const uint8 *palette) {
|
||||||
// Special case to handle MM NES (uses a screen width of 256)
|
assert(surf);
|
||||||
width = 320;
|
|
||||||
|
|
||||||
// center MM NES screen
|
Graphics::Surface screen;
|
||||||
Graphics::Surface newscreen;
|
screen.create(w, h, 2);
|
||||||
newscreen.create(width, screen.h, screen.bytesPerPixel);
|
|
||||||
|
|
||||||
uint8 *dst = (uint8*)newscreen.getBasePtr((320 - screenWidth) / 2, 0);
|
for (uint y = 0; y < screen.h; ++y) {
|
||||||
uint8 *src = (uint8*)screen.getBasePtr(0, 0);
|
for (uint x = 0; x < screen.w; ++x) {
|
||||||
uint16 height = screen.h;
|
byte r, g, b;
|
||||||
|
r = palette[pixels[y * w + x] * 3];
|
||||||
|
g = palette[pixels[y * w + x] * 3 + 1];
|
||||||
|
b = palette[pixels[y * w + x] * 3 + 2];
|
||||||
|
|
||||||
while (height--) {
|
((uint16 *)screen.pixels)[y * screen.w + x] = RGBToColor<ColorMasks<565> >(r, g, b);
|
||||||
memcpy(dst, src, screen.pitch);
|
|
||||||
dst += newscreen.pitch;
|
|
||||||
src += screen.pitch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
screen.free();
|
|
||||||
screen = newscreen;
|
|
||||||
} else if (screenWidth == 720) {
|
|
||||||
// Special case to handle Hercules mode
|
|
||||||
width = 640;
|
|
||||||
screenHeight = 400;
|
|
||||||
|
|
||||||
// cut off menu and so on..
|
|
||||||
Graphics::Surface newscreen;
|
|
||||||
newscreen.create(width, 400, screen.bytesPerPixel);
|
|
||||||
|
|
||||||
uint8 *dst = (uint8*)newscreen.getBasePtr(0, (400 - 240) / 2);
|
|
||||||
uint8 *src = (uint8*)screen.getBasePtr(41, 28);
|
|
||||||
|
|
||||||
for (int y = 0; y < 240; ++y) {
|
|
||||||
memcpy(dst, src, 640 * screen.bytesPerPixel);
|
|
||||||
dst += newscreen.pitch;
|
|
||||||
src += screen.pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
screen.free();
|
|
||||||
screen = newscreen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 newHeight = !(screenHeight % 240) ? kThumbnailHeight2 : kThumbnailHeight1;
|
return createThumbnail(*surf, screen);
|
||||||
|
|
||||||
int gBitFormatBackUp = gBitFormat;
|
|
||||||
gBitFormat = 565;
|
|
||||||
surf->create(kThumbnailWidth, newHeight, sizeof(uint16));
|
|
||||||
createThumbnail((const uint8*)screen.pixels, width * sizeof(uint16), (uint8*)surf->pixels, surf->pitch, width, screenHeight);
|
|
||||||
gBitFormat = gBitFormatBackUp;
|
|
||||||
|
|
||||||
screen.free();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
174
graphics/thumbnail.cpp
Normal file
174
graphics/thumbnail.cpp
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "graphics/thumbnail.h"
|
||||||
|
#include "graphics/scaler.h"
|
||||||
|
#include "common/endian.h"
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
namespace Graphics {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
#define THMB_VERSION 1
|
||||||
|
|
||||||
|
struct ThumbnailHeader {
|
||||||
|
uint32 type;
|
||||||
|
uint32 size;
|
||||||
|
byte version;
|
||||||
|
uint16 width, height;
|
||||||
|
byte bpp;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ThumbnailHeaderSize (4+4+1+2+2+1)
|
||||||
|
|
||||||
|
inline void colorToRGB(uint16 color, uint8 &r, uint8 &g, uint8 &b) {
|
||||||
|
r = (((color >> 11) & 0x1F) << 3);
|
||||||
|
g = (((color >> 5) & 0x3F) << 2);
|
||||||
|
b = ((color&0x1F) << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool outputWarnings) {
|
||||||
|
header.type = in.readUint32BE();
|
||||||
|
// We also accept the bad 'BMHT' header here, for the sake of compatibility
|
||||||
|
// with some older savegames which were written incorrectly due to a bug in
|
||||||
|
// ScummVM which wrote the thumb header type incorrectly on LE systems.
|
||||||
|
if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT')) {
|
||||||
|
if (outputWarnings)
|
||||||
|
warning("couldn't find thumbnail header type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.size = in.readUint32BE();
|
||||||
|
header.version = in.readByte();
|
||||||
|
|
||||||
|
if (header.version > THMB_VERSION) {
|
||||||
|
if (outputWarnings)
|
||||||
|
warning("trying to load a newer thumbnail version: %d instead of %d", header.version, THMB_VERSION);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.width = in.readUint16BE();
|
||||||
|
header.height = in.readUint16BE();
|
||||||
|
header.bpp = in.readByte();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // end of anonymous namespace
|
||||||
|
|
||||||
|
bool checkThumbnailHeader(Common::SeekableReadStream &in) {
|
||||||
|
uint32 position = in.pos();
|
||||||
|
ThumbnailHeader header;
|
||||||
|
|
||||||
|
bool hasHeader = loadHeader(in, header, false);
|
||||||
|
|
||||||
|
in.seek(position, SEEK_SET);
|
||||||
|
|
||||||
|
return hasHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool skipThumbnailHeader(Common::SeekableReadStream &in) {
|
||||||
|
uint32 position = in.pos();
|
||||||
|
ThumbnailHeader header;
|
||||||
|
|
||||||
|
if (!loadHeader(in, header, true)) {
|
||||||
|
in.seek(position, SEEK_SET);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
in.seek(header.size - (in.pos() - position), SEEK_CUR);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface &to) {
|
||||||
|
ThumbnailHeader header;
|
||||||
|
|
||||||
|
if (!loadHeader(in, header, true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (header.bpp != 2) {
|
||||||
|
warning("trying to load thumbnail with unsupported bit depth %d", header.bpp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
to.create(header.width, header.height, sizeof(OverlayColor));
|
||||||
|
|
||||||
|
OverlayColor *pixels = (OverlayColor *)to.pixels;
|
||||||
|
for (int y = 0; y < to.h; ++y) {
|
||||||
|
for (int x = 0; x < to.w; ++x) {
|
||||||
|
uint8 r, g, b;
|
||||||
|
colorToRGB(in.readUint16BE(), r, g, b);
|
||||||
|
|
||||||
|
// converting to current OSystem Color
|
||||||
|
*pixels++ = g_system->RGBToColor(r, g, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool saveThumbnail(Common::WriteStream &out) {
|
||||||
|
Graphics::Surface thumb;
|
||||||
|
|
||||||
|
if (!createThumbnailFromScreen(&thumb)) {
|
||||||
|
warning("Couldn't create thumbnail from screen, aborting thumbnail save");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = saveThumbnail(out, thumb);
|
||||||
|
thumb.free();
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb) {
|
||||||
|
if (thumb.bytesPerPixel != 2) {
|
||||||
|
warning("trying to save thumbnail with bpp different than 2");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThumbnailHeader header;
|
||||||
|
header.type = MKID_BE('THMB');
|
||||||
|
header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel;
|
||||||
|
header.version = THMB_VERSION;
|
||||||
|
header.width = thumb.w;
|
||||||
|
header.height = thumb.h;
|
||||||
|
header.bpp = thumb.bytesPerPixel;
|
||||||
|
|
||||||
|
out.writeUint32BE(header.type);
|
||||||
|
out.writeUint32BE(header.size);
|
||||||
|
out.writeByte(header.version);
|
||||||
|
out.writeUint16BE(header.width);
|
||||||
|
out.writeUint16BE(header.height);
|
||||||
|
out.writeByte(header.bpp);
|
||||||
|
|
||||||
|
// TODO: for later this shouldn't be casted to uint16...
|
||||||
|
uint16 *pixels = (uint16 *)thumb.pixels;
|
||||||
|
for (uint16 p = 0; p < thumb.w*thumb.h; ++p, ++pixels)
|
||||||
|
out.writeUint16BE(*pixels);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Graphics
|
||||||
|
|
69
graphics/thumbnail.h
Normal file
69
graphics/thumbnail.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GRAPHICS_THUMBNAIL_H
|
||||||
|
#define GRAPHICS_THUMBNAIL_H
|
||||||
|
|
||||||
|
#include "common/stream.h"
|
||||||
|
#include "graphics/surface.h"
|
||||||
|
|
||||||
|
namespace Graphics {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for presence of the thumbnail save header.
|
||||||
|
* Seeks automatically back to start position after check.
|
||||||
|
*
|
||||||
|
* @param in stream to check for header
|
||||||
|
*/
|
||||||
|
bool checkThumbnailHeader(Common::SeekableReadStream &in);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skips a thumbnail header, if present.
|
||||||
|
*
|
||||||
|
* @param in stream to process
|
||||||
|
*/
|
||||||
|
bool skipThumbnailHeader(Common::SeekableReadStream &in);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lodas a thumbnail from the given input stream.
|
||||||
|
* The loaded thumbnail will be automatically converted to the
|
||||||
|
* current overlay pixelformat.
|
||||||
|
*/
|
||||||
|
bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface &to);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a thumbnail to the given write stream.
|
||||||
|
* Automatically creates a thumbnail from screen contents.
|
||||||
|
*/
|
||||||
|
bool saveThumbnail(Common::WriteStream &out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a (given) thumbnail to the given write stream.
|
||||||
|
*/
|
||||||
|
bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb);
|
||||||
|
|
||||||
|
} // end of namespace Graphics
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue