Last part of patch #1163026 (Thumbnails for ScummEngine)

svn-id: r17982
This commit is contained in:
Max Horn 2005-05-09 00:09:01 +00:00
parent 20c8944189
commit c33cc2ce85
7 changed files with 320 additions and 10 deletions

View File

@ -22,6 +22,7 @@
#include "common/config-manager.h"
#include "common/system.h"
#include "common/scaler.h"
#include "gui/chooser.h"
#include "gui/newgui.h"
@ -147,7 +148,6 @@ static ResString string_map_table_v5[] = {
#pragma mark -
const Common::String ScummDialog::queryResString(int stringno) {
byte buf[256];
byte *result;
@ -199,7 +199,7 @@ enum {
kQuitCmd = 'QUIT'
};
class SaveLoadChooser : public GUI::ChooserDialog {
class SaveLoadChooser : public GUI::ChooserDialog, public BaseSaveLoadChooser {
typedef Common::String String;
typedef Common::StringList StringList;
protected:
@ -210,6 +210,8 @@ public:
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
const String &getResultString() const;
void setList(const StringList& list) { GUI::ChooserDialog::setList(list); }
int runModal() { return GUI::ChooserDialog::runModal(); }
};
SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode)
@ -250,6 +252,115 @@ void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 da
}
}
#pragma mark -
enum {
kChooseCmd = 'Chos'
};
// only for use with >= 640x400 resolutions
class SaveLoadChooserEx : public GUI::Dialog, public BaseSaveLoadChooser {
typedef Common::String String;
typedef Common::StringList StringList;
protected:
bool _saveMode;
GUI::ListWidget *_list;
GUI::ButtonWidget *_chooseButton;
GUI::GraphicsWidget *_gfxWidget;
ScummEngine *_scumm;
public:
SaveLoadChooserEx(const String &title, const String &buttonLabel, bool saveMode, ScummEngine *engine);
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
const String &getResultString() const;
void setList(const StringList& list);
int runModal();
bool wantsScaling() const { return false; }
};
SaveLoadChooserEx::SaveLoadChooserEx(const String &title, const String &buttonLabel, bool saveMode, ScummEngine *engine)
: Dialog(8, 8, engine->_system->getOverlayWidth() - 2 * 8, engine->_system->getOverlayHeight() - 16), _saveMode(saveMode), _list(0), _chooseButton(0), _gfxWidget(0), _scumm(engine) {
new StaticTextWidget(this, 10, 6, _w - 2 * 10, kLineHeight, title, kTextAlignCenter);
// Add choice list
_list = new GUI::ListWidget(this, 10, 18, _w - 2 * 10 - 180, _h - 14 - 24 - 10);
_list->setEditable(saveMode);
_list->setNumberingMode(saveMode ? GUI::kListNumberingOne : GUI::kListNumberingZero);
// Add the thumbnail display
_gfxWidget = new GUI::GraphicsWidget(this,
_w - (kThumbnailWidth + 22),
18,
kThumbnailWidth + 8,
((_scumm->_system->getHeight() % 200 && _scumm->_system->getHeight() != 350) ? kThumbnailHeight2 : kThumbnailHeight1) + 8);
_gfxWidget->setFlags(GUI::WIDGET_BORDER);
// Buttons
addButton(_w - 2 * (kButtonWidth + 10), _h - 24, "Cancel", kCloseCmd, 0);
_chooseButton = addButton(_w-(kButtonWidth + 10), _h - 24, buttonLabel, kChooseCmd, 0);
_chooseButton->setEnabled(false);
}
const Common::String &SaveLoadChooserEx::getResultString() const {
return _list->getSelectedString();
}
void SaveLoadChooserEx::setList(const StringList& list) {
_list->setList(list);
}
int SaveLoadChooserEx::runModal() {
_gfxWidget->setGfx(0);
int ret = GUI::Dialog::runModal();
return ret;
}
void SaveLoadChooserEx::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
int selItem = _list->getSelected();
switch (cmd) {
case GUI::kListItemActivatedCmd:
case GUI::kListItemDoubleClickedCmd:
if (selItem >= 0) {
if (_saveMode || !getResultString().isEmpty()) {
_list->endEditMode();
setResult(selItem);
close();
}
}
break;
case kChooseCmd:
_list->endEditMode();
setResult(selItem);
close();
break;
case GUI::kListSelectionChangedCmd: {
const Graphics::Surface *thumb;
thumb = _scumm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem);
_gfxWidget->setGfx(thumb);
delete thumb;
_gfxWidget->draw();
if (_saveMode) {
_list->startEditMode();
}
// Disable button if nothing is selected, or (in load mode) if an empty
// list item is selected. We allow choosing an empty item in save mode
// because we then just assign a default name.
_chooseButton->setEnabled(selItem >= 0 && (_saveMode || !getResultString().isEmpty()));
_chooseButton->draw();
} break;
case kCloseCmd:
setResult(-1);
default:
GUI::Dialog::handleCommand(sender, cmd, data);
}
}
#pragma mark -
Common::StringList generateSavegameList(ScummEngine *scumm, bool saveMode) {
// Get savegame names
Common::StringList l;
@ -308,8 +419,13 @@ MainMenuDialog::MainMenuDialog(ScummEngine *scumm)
#ifndef DISABLE_HELP
_helpDialog = new HelpDialog(scumm);
#endif
_saveDialog = new SaveLoadChooser("Save game:", "Save", true);
_loadDialog = new SaveLoadChooser("Load game:", "Load", false);
if (scumm->_system->getOverlayWidth() <= 320) {
_saveDialog = new SaveLoadChooser("Save game:", "Save", true);
_loadDialog = new SaveLoadChooser("Load game:", "Load", false);
} else {
_saveDialog = new SaveLoadChooserEx("Save game:", "Save", true, scumm);
_loadDialog = new SaveLoadChooserEx("Load game:", "Load", false, scumm);
}
}
MainMenuDialog::~MainMenuDialog() {

View File

@ -54,7 +54,18 @@ protected:
const String queryResString(int stringno);
};
class SaveLoadChooser;
// to have a base for all different Save/Load Choosers
// currently only for SaveLoadChooser (320x200)
// and for SaveLoadChooserEx (640x400/640x480)
class BaseSaveLoadChooser
{
public:
virtual ~BaseSaveLoadChooser() {};
virtual const Common::String &getResultString() const = 0;
virtual void setList(const Common::StringList& list) = 0;
virtual int runModal() = 0;
};
class MainMenuDialog : public ScummDialog {
public:
@ -68,8 +79,8 @@ protected:
#ifndef DISABLE_HELP
GUI::Dialog *_helpDialog;
#endif
SaveLoadChooser *_saveDialog;
SaveLoadChooser *_loadDialog;
BaseSaveLoadChooser *_saveDialog;
BaseSaveLoadChooser *_loadDialog;
void save();
void load();

View File

@ -79,7 +79,8 @@ MODULE_OBJS := \
scumm/smush/smush_player.o \
scumm/smush/saud_channel.o \
scumm/smush/smush_mixer.o \
scumm/smush/smush_font.o
scumm/smush/smush_font.o \
scumm/thumbnail.o
MODULE_DIRS += \
scumm \

View File

@ -83,6 +83,7 @@ bool ScummEngine::saveState(int slot, bool compat) {
hdr.ver = TO_LE_32(CURRENT_VER);
out->write(&hdr, sizeof(hdr));
saveThumbnail(out);
Serializer ser(0, out, CURRENT_VER);
saveOrLoad(&ser, CURRENT_VER);
@ -126,6 +127,18 @@ bool ScummEngine::loadState(int slot, bool compat) {
delete in;
return false;
}
// Sine version 52 a thumbnail is saved directly after the header
if (hdr.ver >= VER(52)) {
uint32 type = in->readUint32BE();
if (type != MKID('THMB')) {
warning("Can not load thumbnail");
delete in;
return false;
}
uint32 size = in->readUint32BE();
in->skip(size - 8);
}
// Due to a bug in scummvm up to and including 0.3.0, save games could be saved
// in the V8/V9 format but were tagged with a V7 mark. Ouch. So we just pretend V7 == V8 here
@ -387,6 +400,36 @@ bool ScummEngine::getSavegameName(int slot, char *desc) {
return true;
}
Graphics::Surface *ScummEngine::loadThumbnailFromSlot(int slot) {
char filename[256];
InSaveFile *in;
SaveGameHeader hdr;
int len;
makeSavegameName(filename, slot, false);
if (!(in = _saveFileMan->openForLoading(filename))) {
return 0;
}
len = in->read(&hdr, sizeof(hdr));
if (len != sizeof(hdr) || hdr.type != MKID('SCVM')) {
delete in;
return 0;
}
if (hdr.ver > CURRENT_VER)
hdr.ver = TO_LE_32(hdr.ver);
if (hdr.ver < VER(52)) {
delete in;
return 0;
}
Graphics::Surface *thumb = loadThumbnail(in);
delete in;
return thumb;
}
void ScummEngine::saveOrLoad(Serializer *s, uint32 savegameVersion) {
const SaveLoadEntry objectEntries[] = {
MKLINE(ObjectData, OBIMoffset, sleUint32, VER(8)),

View File

@ -43,7 +43,7 @@ namespace Scumm {
* only saves/loads those which are valid for the version of the savegame
* which is being loaded/saved currently.
*/
#define CURRENT_VER 51
#define CURRENT_VER 52
/**
* An auxillary macro, used to specify savegame versions. We use this instead

View File

@ -27,6 +27,7 @@
#include "common/file.h"
#include "common/rect.h"
#include "common/str.h"
#include "graphics/surface.h"
#include "scumm/gfx.h"
#include "scumm/script.h"
@ -36,7 +37,8 @@ namespace GUI {
}
using GUI::Dialog;
class GameDetector;
class InSaveFile;
class OutSaveFile;
namespace Scumm {
@ -579,6 +581,14 @@ public:
void requestSave(int slot, const char *name, bool temporary = false);
void requestLoad(int slot);
// thumbnail stuff
public:
Graphics::Surface *loadThumbnailFromSlot(int slot);
protected:
Graphics::Surface *loadThumbnail(InSaveFile *file);
void saveThumbnail(OutSaveFile *file);
protected:
/* Script VM - should be in Script class */
uint32 _localScriptOffsets[1024];

129
scumm/thumbnail.cpp Normal file
View File

@ -0,0 +1,129 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2001 Ludvig Strigeus
* Copyright (C) 2001-2005 The ScummVM project
*
* 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 file 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include "common/stdafx.h"
#include "common/scummsys.h"
#include "common/system.h"
#include "common/savefile.h"
#include "common/scaler.h"
#include "scumm.h"
namespace Scumm {
#define THMB_VERSION 1
#if !defined(__GNUC__)
#pragma START_PACK_STRUCTS
#endif
struct ThumbnailHeader {
uint32 type;
uint32 size;
byte version;
uint16 width, height;
byte bpp;
} GCC_PACK;
#if !defined(__GNUC__)
#pragma END_PACK_STRUCTS
#endif
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(InSaveFile *file) {
ThumbnailHeader header;
header.type = file->readUint32BE();
if (header.type != MKID('THMB'))
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();
thumb->create(header.width, header.height, sizeof(uint16));
uint16* pixels = (uint16 *)thumb->pixels;
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;
}
void ScummEngine::saveThumbnail(OutSaveFile *file) {
Graphics::Surface thumb;
if (!createThumbnailFromScreen(&thumb))
thumb.create(kThumbnailWidth, kThumbnailHeight2, sizeof(uint16));
ThumbnailHeader header;
header.type = MKID('THMB');
header.size = sizeof(header) + 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();
}
} // end of namespace Scumm