diff options
author | Willem Jan Palenstijn | 2013-04-18 23:35:23 +0200 |
---|---|---|
committer | Willem Jan Palenstijn | 2013-05-08 20:40:58 +0200 |
commit | 9c2341678ef4984bf92b3878295250faf980b066 (patch) | |
tree | 2fb4805e05e16b9924e80c9947e6bad723b28c4b /engines/mohawk | |
parent | 8172d679df5148a4a32f46074b20cb6caf91844f (diff) | |
parent | a5f4ff36ffc386d48f2da49387a9655ce9295a4d (diff) | |
download | scummvm-rg350-9c2341678ef4984bf92b3878295250faf980b066.tar.gz scummvm-rg350-9c2341678ef4984bf92b3878295250faf980b066.tar.bz2 scummvm-rg350-9c2341678ef4984bf92b3878295250faf980b066.zip |
Merge branch 'master'
Diffstat (limited to 'engines/mohawk')
45 files changed, 2714 insertions, 1493 deletions
diff --git a/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp index f61516c91d..4edde31236 100644 --- a/engines/mohawk/bitmap.cpp +++ b/engines/mohawk/bitmap.cpp @@ -887,7 +887,7 @@ void DOSBitmap::expandEGAPlanes(Graphics::Surface *surface, Common::SeekableRead assert(surface->format.bytesPerPixel == 1); // Note that the image is in EGA planar form and not just standard 4bpp - // This seems to contradict the PoP specs which seem to do + // This seems to contradict the PoP specs which seem to do something else byte *dst = (byte *)surface->pixels; diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp index 0234c86c7e..a7a650d8ed 100644 --- a/engines/mohawk/console.cpp +++ b/engines/mohawk/console.cpp @@ -21,7 +21,6 @@ */ #include "mohawk/console.h" -#include "mohawk/graphics.h" #include "mohawk/livingbooks.h" #include "mohawk/sound.h" #include "mohawk/video.h" @@ -36,6 +35,7 @@ #ifdef ENABLE_MYST #include "mohawk/myst.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_scripts.h" #endif diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h index 0bc236f930..db06b9791e 100644 --- a/engines/mohawk/cstime.h +++ b/engines/mohawk/cstime.h @@ -25,7 +25,7 @@ #include "mohawk/mohawk.h" #include "mohawk/console.h" -#include "mohawk/graphics.h" +#include "mohawk/cstime_graphics.h" #include "common/random.h" #include "common/list.h" diff --git a/engines/mohawk/cstime_graphics.cpp b/engines/mohawk/cstime_graphics.cpp new file mode 100644 index 0000000000..3a1452e67c --- /dev/null +++ b/engines/mohawk/cstime_graphics.cpp @@ -0,0 +1,64 @@ +/* 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. + * + */ + +#include "mohawk/cstime.h" +#include "mohawk/cstime_graphics.h" +#include "mohawk/resource.h" + +#include "common/system.h" +#include "engines/util.h" + +namespace Mohawk { + +CSTimeGraphics::CSTimeGraphics(MohawkEngine_CSTime *vm) : GraphicsManager(), _vm(vm) { + _bmpDecoder = new MohawkBitmap(); + + initGraphics(640, 480, true); +} + +CSTimeGraphics::~CSTimeGraphics() { + delete _bmpDecoder; +} + +void CSTimeGraphics::drawRect(Common::Rect rect, byte color) { + rect.clip(Common::Rect(640, 480)); + + // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active. + if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0) + return; + + Graphics::Surface *screen = _vm->_system->lockScreen(); + + screen->frameRect(rect, color); + + _vm->_system->unlockScreen(); +} + +MohawkSurface *CSTimeGraphics::decodeImage(uint16 id) { + return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id)); +} + +Common::Array<MohawkSurface *> CSTimeGraphics::decodeImages(uint16 id) { + return _bmpDecoder->decodeImages(_vm->getResource(ID_TBMH, id)); +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/cstime_graphics.h b/engines/mohawk/cstime_graphics.h new file mode 100644 index 0000000000..5f034f47f4 --- /dev/null +++ b/engines/mohawk/cstime_graphics.h @@ -0,0 +1,51 @@ +/* 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. + * + */ + +#ifndef MOHAWK_CSTIME_GRAPHICS_H +#define MOHAWK_CSTIME_GRAPHICS_H + +#include "mohawk/graphics.h" + +namespace Mohawk { + +class MohawkEngine_CSTime; + +class CSTimeGraphics : public GraphicsManager { +public: + CSTimeGraphics(MohawkEngine_CSTime *vm); + ~CSTimeGraphics(); + + void drawRect(Common::Rect rect, byte color); + +protected: + MohawkSurface *decodeImage(uint16 id); + Common::Array<MohawkSurface *> decodeImages(uint16 id); + MohawkEngine *getVM() { return (MohawkEngine *)_vm; } + +private: + MohawkBitmap *_bmpDecoder; + MohawkEngine_CSTime *_vm; +}; + +} // End of namespace Mohawk + +#endif diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h index 94f18e134b..08df0a2cbe 100644 --- a/engines/mohawk/detection_tables.h +++ b/engines/mohawk/detection_tables.h @@ -34,7 +34,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, 0, @@ -52,7 +52,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, GF_DEMO, @@ -70,7 +70,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, 0, @@ -88,7 +88,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, 0, @@ -106,7 +106,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, 0, @@ -124,7 +124,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::JA_JPN, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, 0, @@ -142,7 +142,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, 0, @@ -160,7 +160,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MAKINGOF, 0, @@ -178,7 +178,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::JA_JPN, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MAKINGOF, 0, @@ -196,7 +196,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, GF_ME, @@ -214,7 +214,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, GF_ME, @@ -232,7 +232,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, GF_ME, @@ -250,7 +250,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, GF_ME, @@ -268,7 +268,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_RIVEN, 0, @@ -286,7 +286,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_RIVEN, 0, @@ -304,7 +304,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_RIVEN, 0, @@ -322,7 +322,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_RIVEN, GF_DVD, @@ -340,7 +340,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_RIVEN, GF_DVD, @@ -358,7 +358,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_RIVEN, GF_DVD, @@ -376,7 +376,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_RIVEN, GF_DEMO, @@ -391,7 +391,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_CSTIME, 0, @@ -406,7 +406,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_CSTIME, GF_DEMO, @@ -422,7 +422,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_ZOOMBINI, GF_HASMIDI, @@ -437,7 +437,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_ZOOMBINI, GF_HASMIDI, @@ -452,7 +452,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_ZOOMBINI, GF_HASMIDI, @@ -467,7 +467,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_ZOOMBINI, GF_HASMIDI, @@ -482,7 +482,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_ZOOMBINI, GF_HASMIDI, @@ -497,7 +497,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_CSWORLD, 0, @@ -512,7 +512,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_CSWORLD, 0, @@ -527,7 +527,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_CSAMTRAK, 0, @@ -545,7 +545,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_GRB, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -563,7 +563,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -581,7 +581,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -597,7 +597,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_GRB, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -613,7 +613,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -629,7 +629,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -646,7 +646,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -663,7 +663,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -678,7 +678,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV5, 0, @@ -693,7 +693,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV5, 0, @@ -709,7 +709,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -724,7 +724,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -739,7 +739,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -754,7 +754,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_JAMESMATH, GF_HASMIDI, @@ -770,7 +770,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_JAMESMATH, GF_HASMIDI, @@ -785,7 +785,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_TREEHOUSE, GF_HASMIDI, @@ -800,7 +800,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -816,7 +816,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -831,7 +831,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -846,7 +846,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -862,7 +862,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -877,7 +877,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -892,7 +892,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, GF_DEMO, @@ -907,7 +907,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_1STDEGREE, GF_HASMIDI, @@ -925,7 +925,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_1STDEGREE, GF_HASMIDI, @@ -940,7 +940,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_CSUSA, 0, @@ -955,7 +955,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -972,7 +972,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -988,7 +988,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_GRB, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1004,7 +1004,23 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_GRB, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV2, + 0, + 0, + }, + + // Tortoise and the Hare Hebrew variant - From georgeqgreg on bug #3441928 + { + { + "tortoise", + "", + AD_ENTRY1("TORTB.LB", "23135777370cf1ff00aa7247e93642d3"), + Common::HE_ISR, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1020,7 +1036,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1036,7 +1052,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1052,7 +1068,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1068,7 +1084,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1083,7 +1099,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1098,7 +1114,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1114,7 +1130,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1129,7 +1145,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1144,7 +1160,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_LB_10, @@ -1161,7 +1177,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_LB_10, @@ -1177,7 +1193,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_LB_10, @@ -1193,7 +1209,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_LB_10, @@ -1208,7 +1224,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO | GF_LB_10, @@ -1223,7 +1239,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1239,7 +1255,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1254,7 +1270,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO | GF_LB_10, @@ -1269,7 +1285,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1286,7 +1302,24 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + + // Just Grandma and Me 2.0 Macintosh + // From aluff in bug #3461368 + { + { + "grandma", + "v2.0", + AD_ENTRY1("BookOutline", "99fe5c8ace79f0542e6390bc3b58f25a"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_UNSTABLE, + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -1303,7 +1336,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_LB_10, @@ -1319,7 +1352,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_LB_10, @@ -1335,7 +1368,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_GRB, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1351,7 +1384,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1367,7 +1400,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1382,7 +1415,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO | GF_LB_10, @@ -1397,7 +1430,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1413,7 +1446,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1428,7 +1461,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO | GF_LB_10, @@ -1443,7 +1476,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1460,7 +1493,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -1476,7 +1509,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -1491,7 +1524,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1507,7 +1540,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1522,7 +1555,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1538,7 +1571,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -1555,7 +1588,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -1571,7 +1604,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -1586,7 +1619,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1601,7 +1634,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1617,7 +1650,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1632,7 +1665,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1647,7 +1680,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -1663,7 +1696,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -1678,7 +1711,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -1694,7 +1727,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -1710,7 +1743,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -1726,7 +1759,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_GRB, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1742,7 +1775,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1758,7 +1791,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1775,7 +1808,24 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + + // Arthur Birthday (English) Version 2.0 Macintosh + // From aluff in bug #3461368 + { + { + "arthurbday", + "", + AD_ENTRY1("BookOutline", "8e4fddb5b761c8cf2a3b448dd38422be"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_UNSTABLE, + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -1790,7 +1840,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1806,7 +1856,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1821,7 +1871,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1836,7 +1886,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -1851,7 +1901,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -1867,7 +1917,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_GRB, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1883,7 +1933,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1899,7 +1949,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1915,7 +1965,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_GRB, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1931,7 +1981,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1947,7 +1997,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -1963,7 +2013,23 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + "MONSTER.EXE" + }, + + // From GeorgeQGreg + { + { + "lilmonster", + "Demo", + AD_ENTRY1("MONSTER.512", "f603f04c1824d1034ec0366416a059c9"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, GF_DEMO, @@ -1978,7 +2044,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -1993,7 +2059,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -2008,7 +2074,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV4, 0, @@ -2023,7 +2089,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV4, 0, @@ -2041,7 +2107,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV4, 0, @@ -2056,7 +2122,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -2071,7 +2137,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -2086,7 +2152,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2102,7 +2168,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -2117,7 +2183,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -2132,7 +2198,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -2147,7 +2213,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -2164,7 +2230,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -2179,7 +2245,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV1, 0, @@ -2195,7 +2261,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -2212,7 +2278,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -2228,7 +2294,23 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + + // From aluff in bug #3461368 + { + { + "beardark", + "", + AD_ENTRY1("BookOutline", "b56746b3b2c062c8588bfb6b28e137c1"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV3, 0, @@ -2243,7 +2325,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV4, 0, @@ -2258,7 +2340,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV4, 0, @@ -2275,7 +2357,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2291,7 +2373,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2307,7 +2389,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2324,7 +2406,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2340,7 +2422,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2356,7 +2438,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_GRB, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2372,7 +2454,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2388,7 +2470,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2404,7 +2486,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_GRB, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2420,7 +2502,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2436,7 +2518,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_LIVINGBOOKSV2, 0, @@ -2459,7 +2541,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, 0, @@ -2474,7 +2556,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MAKINGOF, 0, @@ -2489,7 +2571,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_MYST, GF_ME, @@ -2504,7 +2586,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_RIVEN, 0, @@ -2519,7 +2601,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NONE) + GUIO1(GUIO_NOASPECT) }, GType_RIVEN, GF_DVD, diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp index c4326d175f..a08d034ef7 100644 --- a/engines/mohawk/graphics.cpp +++ b/engines/mohawk/graphics.cpp @@ -20,30 +20,13 @@ * */ +#include "mohawk/mohawk.h" #include "mohawk/resource.h" #include "mohawk/graphics.h" -#include "mohawk/livingbooks.h" -#include "common/substream.h" #include "common/system.h" -#include "common/textconsole.h" #include "engines/util.h" #include "graphics/palette.h" -#include "graphics/primitives.h" -#include "gui/message.h" - -#ifdef ENABLE_CSTIME -#include "mohawk/cstime.h" -#endif - -#ifdef ENABLE_MYST -#include "mohawk/myst.h" -#include "graphics/jpeg.h" -#endif - -#ifdef ENABLE_RIVEN -#include "mohawk/riven.h" -#endif namespace Mohawk { @@ -108,9 +91,9 @@ GraphicsManager::~GraphicsManager() { } void GraphicsManager::clearCache() { - for (Common::HashMap<uint16, MohawkSurface*>::iterator it = _cache.begin(); it != _cache.end(); it++) + for (Common::HashMap<uint16, MohawkSurface *>::iterator it = _cache.begin(); it != _cache.end(); it++) delete it->_value; - for (Common::HashMap<uint16, Common::Array<MohawkSurface*> >::iterator it = _subImageCache.begin(); it != _subImageCache.end(); it++) { + for (Common::HashMap<uint16, Common::Array<MohawkSurface *> >::iterator it = _subImageCache.begin(); it != _subImageCache.end(); it++) { Common::Array<MohawkSurface *> &array = it->_value; for (uint i = 0; i < array.size(); i++) delete array[i]; @@ -262,983 +245,4 @@ void GraphicsManager::addImageToCache(uint16 id, MohawkSurface *surface) { _cache[id] = surface; } -#ifdef ENABLE_MYST - -MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { - _bmpDecoder = new MystBitmap(); - - _viewport = Common::Rect(544, 332); - - // The original version of Myst could run in 8bpp color too. - // However, it dithered videos to 8bpp and they looked considerably - // worse (than they already did :P). So we're not even going to - // support 8bpp mode in Myst (Myst ME required >8bpp anyway). - initGraphics(_viewport.width(), _viewport.height(), true, NULL); // What an odd screen size! - - _pixelFormat = _vm->_system->getScreenFormat(); - - if (_pixelFormat.bytesPerPixel == 1) - error("Myst requires greater than 256 colors to run"); - - if (_vm->getFeatures() & GF_ME) { - _jpegDecoder = new Graphics::JPEG(); - _pictDecoder = new Graphics::PictDecoder(_pixelFormat); - } else { - _jpegDecoder = NULL; - _pictDecoder = NULL; - } - - _pictureFile.entries = NULL; - - // Initialize our buffer - _backBuffer = new Graphics::Surface(); - _backBuffer->create(_vm->_system->getWidth(), _vm->_system->getHeight(), _pixelFormat); - - _nextAllowedDrawTime = _vm->_system->getMillis(); - _enableDrawingTimeSimulation = 0; -} - -MystGraphics::~MystGraphics() { - delete _bmpDecoder; - delete _jpegDecoder; - delete _pictDecoder; - delete[] _pictureFile.entries; - - _backBuffer->free(); - delete _backBuffer; -} - -static const char* picFileNames[] = { - "CHpics", - "", - "DUpics", - "INpics", - "MEpics", - "MYpics", - "SEpics", - "STpics", - "" -}; - -void MystGraphics::loadExternalPictureFile(uint16 stack) { - if (_vm->getPlatform() != Common::kPlatformMacintosh) - return; - - if (_pictureFile.picFile.isOpen()) - _pictureFile.picFile.close(); - delete[] _pictureFile.entries; - - if (!scumm_stricmp(picFileNames[stack], "")) - return; - - if (!_pictureFile.picFile.open(picFileNames[stack])) - error ("Could not open external picture file \'%s\'", picFileNames[stack]); - - _pictureFile.pictureCount = _pictureFile.picFile.readUint32BE(); - _pictureFile.entries = new PictureFile::PictureEntry[_pictureFile.pictureCount]; - - for (uint32 i = 0; i < _pictureFile.pictureCount; i++) { - _pictureFile.entries[i].offset = _pictureFile.picFile.readUint32BE(); - _pictureFile.entries[i].size = _pictureFile.picFile.readUint32BE(); - _pictureFile.entries[i].id = _pictureFile.picFile.readUint16BE(); - _pictureFile.entries[i].type = _pictureFile.picFile.readUint16BE(); - _pictureFile.entries[i].width = _pictureFile.picFile.readUint16BE(); - _pictureFile.entries[i].height = _pictureFile.picFile.readUint16BE(); - } -} - -MohawkSurface *MystGraphics::decodeImage(uint16 id) { - MohawkSurface *mhkSurface = 0; - - // Myst ME uses JPEG/PICT images instead of compressed Windows Bitmaps for room images, - // though there are a few weird ones that use that format. For further nonsense with images, - // the Macintosh version stores images in external "picture files." We check them before - // going to check for a PICT resource. - if (_vm->getFeatures() & GF_ME && _vm->getPlatform() == Common::kPlatformMacintosh && _pictureFile.picFile.isOpen()) { - for (uint32 i = 0; i < _pictureFile.pictureCount; i++) - if (_pictureFile.entries[i].id == id) { - if (_pictureFile.entries[i].type == 0) { - Common::SeekableReadStream *stream = new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size); - - if (!_jpegDecoder->read(stream)) - error("Could not decode Myst ME Mac JPEG"); - - mhkSurface = new MohawkSurface(_jpegDecoder->getSurface(_pixelFormat)); - delete stream; - } else if (_pictureFile.entries[i].type == 1) { - mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size))); - } else - error ("Unknown Picture File type %d", _pictureFile.entries[i].type); - break; - } - } - - // We're not using the external Mac files, so it's time to delve into the main Mohawk - // archives. However, we still don't know if it's a PICT or WDIB resource. If it's Myst - // ME it's most likely a PICT, and if it's original it's definitely a WDIB. However, - // Myst ME throws us another curve ball in that PICT resources can contain WDIB's instead - // of PICT's. - if (!mhkSurface) { - bool isPict = false; - Common::SeekableReadStream *dataStream = NULL; - - if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) { - // The PICT resource exists. However, it could still contain a MystBitmap - // instead of a PICT image... - dataStream = _vm->getResource(ID_PICT, id); - } else // No PICT, so the WDIB must exist. Let's go grab it. - dataStream = _vm->getResource(ID_WDIB, id); - - if (_vm->getFeatures() & GF_ME) { - // Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap - // would be compressed, there's no way to detect for the BM without a hack. - // So, we search for the PICT version opcode for detection. - dataStream->seek(512 + 10); // 512 byte pict header - isPict = (dataStream->readUint32BE() == 0x001102FF); - dataStream->seek(0); - } - - if (isPict) - mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(dataStream)); - else { - mhkSurface = _bmpDecoder->decodeImage(dataStream); - mhkSurface->convertToTrueColor(); - } - } - - assert(mhkSurface); - return mhkSurface; -} - -void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest) { - Graphics::Surface *surface = findImage(image)->getSurface(); - - // Make sure the image is bottom aligned in the dest rect - dest.top = dest.bottom - MIN<int>(surface->h, dest.height()); - - // Convert from bitmap coordinates to surface coordinates - uint16 top = surface->h - (src.top + MIN<int>(surface->h, dest.height())); - - // Do not draw the top pixels if the image is too tall - if (dest.height() > _viewport.height()) - top += dest.height() - _viewport.height(); - - // Clip the destination rect to the screen - if (dest.right > _vm->_system->getWidth() || dest.bottom > _vm->_system->getHeight()) - dest.debugPrint(4, "Clipping destination rect to the screen"); - dest.right = CLIP<int>(dest.right, 0, _vm->_system->getWidth()); - dest.bottom = CLIP<int>(dest.bottom, 0, _vm->_system->getHeight()); - - uint16 width = MIN<int>(surface->w, dest.width()); - uint16 height = MIN<int>(surface->h, dest.height()); - - // Clamp Width and Height to within src surface dimensions - if (src.left + width > surface->w) - width = surface->w - src.left; - if (src.top + height > surface->h) - height = surface->h - src.top; - - debug(3, "MystGraphics::copyImageSectionToScreen()"); - debug(3, "\tImage: %d", image); - debug(3, "\tsrc.left: %d", src.left); - debug(3, "\tsrc.top: %d", src.top); - debug(3, "\tdest.left: %d", dest.left); - debug(3, "\tdest.top: %d", dest.top); - debug(3, "\twidth: %d", width); - debug(3, "\theight: %d", height); - - simulatePreviousDrawDelay(dest); - - _vm->_system->copyRectToScreen((byte *)surface->getBasePtr(src.left, top), surface->pitch, dest.left, dest.top, width, height); -} - -void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest) { - Graphics::Surface *surface = findImage(image)->getSurface(); - - // Make sure the image is bottom aligned in the dest rect - dest.top = dest.bottom - MIN<int>(surface->h, dest.height()); - - // Convert from bitmap coordinates to surface coordinates - uint16 top = surface->h - (src.top + MIN<int>(surface->h, dest.height())); - - // Do not draw the top pixels if the image is too tall - if (dest.height() > _viewport.height()) { - top += dest.height() - _viewport.height(); - } - - // Clip the destination rect to the screen - if (dest.right > _vm->_system->getWidth() || dest.bottom > _vm->_system->getHeight()) - dest.debugPrint(4, "Clipping destination rect to the screen"); - dest.right = CLIP<int>(dest.right, 0, _vm->_system->getWidth()); - dest.bottom = CLIP<int>(dest.bottom, 0, _vm->_system->getHeight()); - - uint16 width = MIN<int>(surface->w, dest.width()); - uint16 height = MIN<int>(surface->h, dest.height()); - - // Clamp Width and Height to within src surface dimensions - if (src.left + width > surface->w) - width = surface->w - src.left; - if (src.top + height > surface->h) - height = surface->h - src.top; - - debug(3, "MystGraphics::copyImageSectionToBackBuffer()"); - debug(3, "\tImage: %d", image); - debug(3, "\tsrc.left: %d", src.left); - debug(3, "\tsrc.top: %d", src.top); - debug(3, "\tdest.left: %d", dest.left); - debug(3, "\tdest.top: %d", dest.top); - debug(3, "\twidth: %d", width); - debug(3, "\theight: %d", height); - - for (uint16 i = 0; i < height; i++) - memcpy(_backBuffer->getBasePtr(dest.left, i + dest.top), surface->getBasePtr(src.left, top + i), width * surface->format.bytesPerPixel); -} - -void MystGraphics::copyImageToScreen(uint16 image, Common::Rect dest) { - copyImageSectionToScreen(image, Common::Rect(544, 333), dest); -} - -void MystGraphics::copyImageToBackBuffer(uint16 image, Common::Rect dest) { - copyImageSectionToBackBuffer(image, Common::Rect(544, 333), dest); -} - -void MystGraphics::copyBackBufferToScreen(Common::Rect r) { - r.clip(_viewport); - - simulatePreviousDrawDelay(r); - - _vm->_system->copyRectToScreen((byte *)_backBuffer->getBasePtr(r.left, r.top), _backBuffer->pitch, r.left, r.top, r.width(), r.height()); -} - -void MystGraphics::runTransition(uint16 type, Common::Rect rect, uint16 steps, uint16 delay) { - - // Do not artificially delay during transitions - int oldEnableDrawingTimeSimulation = _enableDrawingTimeSimulation; - _enableDrawingTimeSimulation = 0; - - switch (type) { - case 0: { - debugC(kDebugScript, "Left to Right"); - - uint16 step = (rect.right - rect.left) / steps; - Common::Rect area = rect; - for (uint i = 0; i < steps; i++) { - area.left = rect.left + step * i; - area.right = area.left + step; - - _vm->_system->delayMillis(delay); - - copyBackBufferToScreen(area); - _vm->_system->updateScreen(); - } - if (area.right < rect.right) { - area.left = area.right; - area.right = rect.right; - - copyBackBufferToScreen(area); - _vm->_system->updateScreen(); - } - } - break; - case 1: { - debugC(kDebugScript, "Right to Left"); - - uint16 step = (rect.right - rect.left) / steps; - Common::Rect area = rect; - for (uint i = 0; i < steps; i++) { - area.right = rect.right - step * i; - area.left = area.right - step; - - _vm->_system->delayMillis(delay); - - copyBackBufferToScreen(area); - _vm->_system->updateScreen(); - } - if (area.left > rect.left) { - area.right = area.left; - area.left = rect.left; - - copyBackBufferToScreen(area); - _vm->_system->updateScreen(); - } - } - break; - case 5: { - debugC(kDebugScript, "Top to Bottom"); - - uint16 step = (rect.bottom - rect.top) / steps; - Common::Rect area = rect; - for (uint i = 0; i < steps; i++) { - area.top = rect.top + step * i; - area.bottom = area.top + step; - - _vm->_system->delayMillis(delay); - - copyBackBufferToScreen(area); - _vm->_system->updateScreen(); - } - if (area.bottom < rect.bottom) { - area.top = area.bottom; - area.bottom = rect.bottom; - - copyBackBufferToScreen(area); - _vm->_system->updateScreen(); - } - } - break; - case 6: { - debugC(kDebugScript, "Bottom to Top"); - - uint16 step = (rect.bottom - rect.top) / steps; - Common::Rect area = rect; - for (uint i = 0; i < steps; i++) { - area.bottom = rect.bottom - step * i; - area.top = area.bottom - step; - - _vm->_system->delayMillis(delay); - - copyBackBufferToScreen(area); - _vm->_system->updateScreen(); - } - if (area.top > rect.top) { - area.bottom = area.top; - area.top = rect.top; - - copyBackBufferToScreen(area); - _vm->_system->updateScreen(); - } - } - break; - default: - warning("Unknown Update Direction"); - - //TODO: Replace minimal implementation - copyBackBufferToScreen(rect); - _vm->_system->updateScreen(); - break; - } - - _enableDrawingTimeSimulation = oldEnableDrawingTimeSimulation; -} - -void MystGraphics::drawRect(Common::Rect rect, RectState state) { - rect.clip(_viewport); - - // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active. - if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0) - return; - - Graphics::Surface *screen = _vm->_system->lockScreen(); - - if (state == kRectEnabled) - screen->frameRect(rect, _pixelFormat.RGBToColor(0, 255, 0)); - else if (state == kRectUnreachable) - screen->frameRect(rect, _pixelFormat.RGBToColor(0, 0, 255)); - else - screen->frameRect(rect, _pixelFormat.RGBToColor(255, 0, 0)); - - _vm->_system->unlockScreen(); -} - -void MystGraphics::drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color) { - _backBuffer->drawLine(p1.x, p1.y, p2.x, p2.y, color); -} - -void MystGraphics::enableDrawingTimeSimulation(bool enable) { - if (enable) - _enableDrawingTimeSimulation++; - else - _enableDrawingTimeSimulation--; - - if (_enableDrawingTimeSimulation < 0) - _enableDrawingTimeSimulation = 0; -} - -void MystGraphics::simulatePreviousDrawDelay(const Common::Rect &dest) { - uint32 time = 0; - - if (_enableDrawingTimeSimulation) { - time = _vm->_system->getMillis(); - - // Do not draw anything new too quickly after the previous draw call - // so that images stay at least a little while on screen - // This is enabled only for scripted draw calls - if (time < _nextAllowedDrawTime) - _vm->_system->delayMillis(_nextAllowedDrawTime - time); - } - - // Next draw call allowed at DELAY + AERA * COEFF milliseconds from now - time = _vm->_system->getMillis(); - _nextAllowedDrawTime = time + _constantDrawDelay + dest.height() * dest.width() / _proportionalDrawDelay; -} - -void MystGraphics::copyBackBufferToScreenWithSaturation(int16 saturation) { - Graphics::Surface *screen = _vm->_system->lockScreen(); - - for (uint16 y = 0; y < _viewport.height(); y++) - for (uint16 x = 0; x < _viewport.width(); x++) { - uint32 color; - uint8 r, g, b; - - if (_pixelFormat.bytesPerPixel == 2) - color = *(const uint16 *)_backBuffer->getBasePtr(x, y); - else - color = *(const uint32 *)_backBuffer->getBasePtr(x, y); - - _pixelFormat.colorToRGB(color, r, g, b); - - r = CLIP<int16>((int16)r - saturation, 0, 255); - g = CLIP<int16>((int16)g - saturation, 0, 255); - b = CLIP<int16>((int16)b - saturation, 0, 255); - - color = _pixelFormat.RGBToColor(r, g, b); - - if (_pixelFormat.bytesPerPixel == 2) { - uint16 *dst = (uint16 *)screen->getBasePtr(x, y); - *dst = color; - } else { - uint32 *dst = (uint32 *)screen->getBasePtr(x, y); - *dst = color; - } - } - - _vm->_system->unlockScreen(); - _vm->_system->updateScreen(); -} - -void MystGraphics::fadeToBlack() { - for (int16 i = 0; i < 256; i += 32) { - copyBackBufferToScreenWithSaturation(i); - } -} - -void MystGraphics::fadeFromBlack() { - for (int16 i = 256; i >= 0; i -= 32) { - copyBackBufferToScreenWithSaturation(i); - } -} - -#endif // ENABLE_MYST - -#ifdef ENABLE_RIVEN - -RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm) { - _bitmapDecoder = new MohawkBitmap(); - - // Give me the best you've got! - initGraphics(608, 436, true, NULL); - _pixelFormat = _vm->_system->getScreenFormat(); - - if (_pixelFormat.bytesPerPixel == 1) - error("Riven requires greater than 256 colors to run"); - - // The actual game graphics only take up the first 392 rows. The inventory - // occupies the rest of the screen and we don't use the buffer to hold that. - _mainScreen = new Graphics::Surface(); - _mainScreen->create(608, 392, _pixelFormat); - - _updatesEnabled = true; - _scheduledTransition = -1; // no transition - _dirtyScreen = false; - _inventoryDrawn = false; - - _creditsImage = 302; - _creditsPos = 0; -} - -RivenGraphics::~RivenGraphics() { - _mainScreen->free(); - delete _mainScreen; - delete _bitmapDecoder; -} - -MohawkSurface *RivenGraphics::decodeImage(uint16 id) { - MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getResource(ID_TBMP, id)); - surface->convertToTrueColor(); - return surface; -} - -void RivenGraphics::copyImageToScreen(uint16 image, uint32 left, uint32 top, uint32 right, uint32 bottom) { - Graphics::Surface *surface = findImage(image)->getSurface(); - - // Clip the width to fit on the screen. Fixes some images. - if (left + surface->w > 608) - surface->w = 608 - left; - - for (uint16 i = 0; i < surface->h; i++) - memcpy(_mainScreen->getBasePtr(left, i + top), surface->getBasePtr(0, i), surface->w * surface->format.bytesPerPixel); - - _dirtyScreen = true; -} - -void RivenGraphics::drawPLST(uint16 x) { - Common::SeekableReadStream* plst = _vm->getResource(ID_PLST, _vm->getCurCard()); - uint16 recordCount = plst->readUint16BE(); - - for (uint16 i = 0; i < recordCount; i++) { - uint16 index = plst->readUint16BE(); - uint16 id = plst->readUint16BE(); - uint16 left = plst->readUint16BE(); - uint16 top = plst->readUint16BE(); - uint16 right = plst->readUint16BE(); - uint16 bottom = plst->readUint16BE(); - - // We are also checking here to make sure we haven't drawn the image yet on screen. - // This fixes problems with drawing PLST 1 twice and some other images twice. PLST - // 1 is sometimes not called by the scripts, so some cards don't appear if we don't - // draw PLST 1 each time. This "hack" is here to catch any PLST attempting to draw - // twice. There should never be a problem with doing it this way. - if (index == x && !(Common::find(_activatedPLSTs.begin(), _activatedPLSTs.end(), x) != _activatedPLSTs.end())) { - debug(0, "Drawing image %d", id); - copyImageToScreen(id, left, top, right, bottom); - _activatedPLSTs.push_back(x); - break; - } - } - - delete plst; -} - -void RivenGraphics::updateScreen(Common::Rect updateRect) { - if (_updatesEnabled) { - _vm->runUpdateScreenScript(); - - if (_dirtyScreen) { - _activatedPLSTs.clear(); - - // Copy to screen if there's no transition. Otherwise transition. ;) - if (_scheduledTransition < 0) - _vm->_system->copyRectToScreen((byte *)_mainScreen->getBasePtr(updateRect.left, updateRect.top), _mainScreen->pitch, updateRect.left, updateRect.top, updateRect.width(), updateRect.height()); - else - runScheduledTransition(); - - // Finally, update the screen. - _vm->_system->updateScreen(); - _dirtyScreen = false; - } - } -} - -void RivenGraphics::scheduleWaterEffect(uint16 sfxeID) { - Common::SeekableReadStream *sfxeStream = _vm->getResource(ID_SFXE, sfxeID); - - if (sfxeStream->readUint16BE() != 'SL') - error ("Unknown sfxe tag"); - - // Read in header info - SFXERecord sfxeRecord; - sfxeRecord.frameCount = sfxeStream->readUint16BE(); - uint32 offsetTablePosition = sfxeStream->readUint32BE(); - sfxeRecord.rect.left = sfxeStream->readUint16BE(); - sfxeRecord.rect.top = sfxeStream->readUint16BE(); - sfxeRecord.rect.right = sfxeStream->readUint16BE(); - sfxeRecord.rect.bottom = sfxeStream->readUint16BE(); - sfxeRecord.speed = sfxeStream->readUint16BE(); - // Skip the rest of the fields... - - // Read in offsets - sfxeStream->seek(offsetTablePosition); - uint32 *frameOffsets = new uint32[sfxeRecord.frameCount]; - for (uint16 i = 0; i < sfxeRecord.frameCount; i++) - frameOffsets[i] = sfxeStream->readUint32BE(); - sfxeStream->seek(frameOffsets[0]); - - // Read in the scripts - for (uint16 i = 0; i < sfxeRecord.frameCount; i++) - sfxeRecord.frameScripts.push_back(sfxeStream->readStream((i == sfxeRecord.frameCount - 1) ? sfxeStream->size() - frameOffsets[i] : frameOffsets[i + 1] - frameOffsets[i])); - - // Set it to the first frame - sfxeRecord.curFrame = 0; - sfxeRecord.lastFrameTime = 0; - - delete[] frameOffsets; - delete sfxeStream; - _waterEffects.push_back(sfxeRecord); -} - -void RivenGraphics::clearWaterEffects() { - _waterEffects.clear(); -} - -bool RivenGraphics::runScheduledWaterEffects() { - // Don't run the effect if it's disabled - if (_vm->_vars["waterenabled"] == 0) - return false; - - Graphics::Surface *screen = NULL; - - for (uint16 i = 0; i < _waterEffects.size(); i++) { - if (_vm->_system->getMillis() > _waterEffects[i].lastFrameTime + 1000 / _waterEffects[i].speed) { - // Lock the screen! - if (!screen) - screen = _vm->_system->lockScreen(); - - // Make sure the script is at the starting point - Common::SeekableReadStream *script = _waterEffects[i].frameScripts[_waterEffects[i].curFrame]; - if (script->pos() != 0) - script->seek(0); - - // Run script - uint16 curRow = 0; - for (uint16 op = script->readUint16BE(); op != 4; op = script->readUint16BE()) { - if (op == 1) { // Increment Row - curRow++; - } else if (op == 3) { // Copy Pixels - uint16 dstLeft = script->readUint16BE(); - uint16 srcLeft = script->readUint16BE(); - uint16 srcTop = script->readUint16BE(); - uint16 rowWidth = script->readUint16BE(); - memcpy ((byte *)screen->getBasePtr(dstLeft, curRow + _waterEffects[i].rect.top), (byte *)_mainScreen->getBasePtr(srcLeft, srcTop), rowWidth * _pixelFormat.bytesPerPixel); - } else if (op != 4) { // End of Script - error ("Unknown SFXE opcode %d", op); - } - } - - // Increment frame - _waterEffects[i].curFrame++; - if (_waterEffects[i].curFrame == _waterEffects[i].frameCount) - _waterEffects[i].curFrame = 0; - - // Set the new time - _waterEffects[i].lastFrameTime = _vm->_system->getMillis(); - } - } - - // Unlock the screen if it has been locked and return true to update the screen - if (screen) { - _vm->_system->unlockScreen(); - return true; - } - - return false; -} - -void RivenGraphics::scheduleTransition(uint16 id, Common::Rect rect) { - _scheduledTransition = id; - _transitionRect = rect; -} - -void RivenGraphics::runScheduledTransition() { - if (_scheduledTransition < 0) // No transition is scheduled - return; - - // TODO: There's a lot to be done here... - - // Note: Transitions 0-11 are actual transitions, but none are used in-game. - // There's no point in implementing them if they're not used. These extra - // transitions were found by hacking scripts. - - switch (_scheduledTransition) { - case 0: // Swipe Left - case 1: // Swipe Right - case 2: // Swipe Up - case 3: // Swipe Down - case 12: // Pan Left - case 13: // Pan Right - case 14: // Pan Up - case 15: // Pan Down - case 16: // Dissolve - case 17: // Dissolve (tspit CARD 155) - break; - default: - if (_scheduledTransition >= 4 && _scheduledTransition <= 11) - error("Found unused transition %d", _scheduledTransition); - else - error("Found unknown transition %d", _scheduledTransition); - } - - // For now, just copy the image to screen without doing any transition. - _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); - _vm->_system->updateScreen(); - - _scheduledTransition = -1; // Clear scheduled transition -} - -void RivenGraphics::clearMainScreen() { - _mainScreen->fillRect(Common::Rect(0, 0, 608, 392), _pixelFormat.RGBToColor(0, 0, 0)); -} - -void RivenGraphics::fadeToBlack() { - // The transition speed is forced to best here - setTransitionSpeed(kRivenTransitionSpeedBest); - scheduleTransition(16); - clearMainScreen(); - runScheduledTransition(); -} - -void RivenGraphics::showInventory() { - // Don't redraw the inventory - if (_inventoryDrawn) - return; - - // Clear the inventory area - clearInventoryArea(); - - // Draw the demo's exit button - if (_vm->getFeatures() & GF_DEMO) { - // extras.mhk tBMP 101 contains "EXIT" instead of Atrus' journal in the demo! - // The demo's extras.mhk contains all the other inventory/marble/credits image - // but has hacked tBMP 101 with "EXIT". *sigh* - drawInventoryImage(101, g_demoExitRect); - } else { - // We don't want to show the inventory on setup screens or in other journals. - if (_vm->getCurStack() == aspit) - return; - - // There are three books and three vars. We have three different - // combinations. At the start you have just Atrus' journal. Later, - // you get Catherine's journal and the trap book. Near the end, - // you lose the trap book and have just the two journals. - - bool hasCathBook = _vm->_vars["acathbook"] != 0; - bool hasTrapBook = _vm->_vars["atrapbook"] != 0; - - if (!hasCathBook) { - drawInventoryImage(101, g_atrusJournalRect1); - } else if (!hasTrapBook) { - drawInventoryImage(101, g_atrusJournalRect2); - drawInventoryImage(102, g_cathJournalRect2); - } else { - drawInventoryImage(101, g_atrusJournalRect3); - drawInventoryImage(102, g_cathJournalRect3); - drawInventoryImage(100, g_trapBookRect3); - } - } - - _vm->_system->updateScreen(); - _inventoryDrawn = true; -} - -void RivenGraphics::hideInventory() { - // Don't hide the inventory twice - if (!_inventoryDrawn) - return; - - // Clear the area - clearInventoryArea(); - - _inventoryDrawn = false; -} - -void RivenGraphics::clearInventoryArea() { - // Clear the inventory area - static const Common::Rect inventoryRect = Common::Rect(0, 392, 608, 436); - - // Lock the screen - Graphics::Surface *screen = _vm->_system->lockScreen(); - - // Fill the inventory area with black - screen->fillRect(inventoryRect, _pixelFormat.RGBToColor(0, 0, 0)); - - _vm->_system->unlockScreen(); -} - -void RivenGraphics::drawInventoryImage(uint16 id, const Common::Rect *rect) { - MohawkSurface *mhkSurface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id)); - mhkSurface->convertToTrueColor(); - Graphics::Surface *surface = mhkSurface->getSurface(); - - _vm->_system->copyRectToScreen((byte *)surface->pixels, surface->pitch, rect->left, rect->top, surface->w, surface->h); - - delete mhkSurface; -} - -void RivenGraphics::drawRect(Common::Rect rect, bool active) { - // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active. - Graphics::Surface *screen = _vm->_system->lockScreen(); - - if (active) - screen->frameRect(rect, _pixelFormat.RGBToColor(0, 255, 0)); - else - screen->frameRect(rect, _pixelFormat.RGBToColor(255, 0, 0)); - - _vm->_system->unlockScreen(); -} - -void RivenGraphics::drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect) { - // Draw tBMP id from srcRect to dstRect - Graphics::Surface *surface = findImage(id)->getSurface(); - - assert(srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height()); - - for (uint16 i = 0; i < srcRect.height(); i++) - memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(srcRect.left, i + srcRect.top), srcRect.width() * surface->format.bytesPerPixel); - - _dirtyScreen = true; -} - -void RivenGraphics::drawExtrasImage(uint16 id, Common::Rect dstRect) { - MohawkSurface *mhkSurface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id)); - mhkSurface->convertToTrueColor(); - Graphics::Surface *surface = mhkSurface->getSurface(); - - assert(dstRect.width() == surface->w); - - for (uint16 i = 0; i < surface->h; i++) - memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(0, i), surface->pitch); - - delete mhkSurface; - _dirtyScreen = true; -} - -void RivenGraphics::beginCredits() { - // Clear the old cache - clearCache(); - - // Now cache all the credits images - for (uint16 i = 302; i <= 320; i++) { - MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, i)); - surface->convertToTrueColor(); - addImageToCache(i, surface); - } - - // And clear our screen too - clearMainScreen(); -} - -void RivenGraphics::updateCredits() { - if ((_creditsImage == 303 || _creditsImage == 304) && _creditsPos == 0) - fadeToBlack(); - - if (_creditsImage < 304) { - // For the first two credit images, they are faded from black to the image and then out again - scheduleTransition(16); - - Graphics::Surface *frame = findImage(_creditsImage++)->getSurface(); - - for (int y = 0; y < frame->h; y++) - memcpy(_mainScreen->getBasePtr(124, y), frame->getBasePtr(0, y), frame->pitch); - - runScheduledTransition(); - } else { - // Otheriwse, we're scrolling - // Move the screen up one row - memmove(_mainScreen->pixels, _mainScreen->getBasePtr(0, 1), _mainScreen->pitch * (_mainScreen->h - 1)); - - // Only update as long as we're not before the last frame - // Otherwise, we're just moving up a row (which we already did) - if (_creditsImage <= 320) { - // Copy the next row to the bottom of the screen - Graphics::Surface *frame = findImage(_creditsImage)->getSurface(); - memcpy(_mainScreen->getBasePtr(124, _mainScreen->h - 1), frame->getBasePtr(0, _creditsPos), frame->pitch); - _creditsPos++; - - if (_creditsPos == _mainScreen->h) { - _creditsImage++; - _creditsPos = 0; - } - } - - // Now flush the new screen - _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); - _vm->_system->updateScreen(); - } -} - -#endif // ENABLE_RIVEN - -LBGraphics::LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height) : GraphicsManager(), _vm(vm) { - _bmpDecoder = _vm->isPreMohawk() ? new LivingBooksBitmap_v1() : new MohawkBitmap(); - - initGraphics(width, height, true); -} - -LBGraphics::~LBGraphics() { - delete _bmpDecoder; -} - -MohawkSurface *LBGraphics::decodeImage(uint16 id) { - if (_vm->isPreMohawk()) - return _bmpDecoder->decodeImage(_vm->wrapStreamEndian(ID_BMAP, id)); - - return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id)); -} - -void LBGraphics::copyOffsetAnimImageToScreen(uint16 image, int left, int top) { - MohawkSurface *mhkSurface = findImage(image); - - left -= mhkSurface->getOffsetX(); - top -= mhkSurface->getOffsetY(); - - GraphicsManager::copyAnimImageToScreen(image, left, top); -} - -bool LBGraphics::imageIsTransparentAt(uint16 image, bool useOffsets, int x, int y) { - MohawkSurface *mhkSurface = findImage(image); - - if (useOffsets) { - x += mhkSurface->getOffsetX(); - y += mhkSurface->getOffsetY(); - } - - if (x < 0 || y < 0) - return true; - - Graphics::Surface *surface = mhkSurface->getSurface(); - if (x >= surface->w || y >= surface->h) - return true; - - return *(byte *)surface->getBasePtr(x, y) == 0; -} - -void LBGraphics::setPalette(uint16 id) { - // Old Living Books games use the old CTBL-style palette format while newer - // games use the better tPAL format which can store partial palettes. - if (_vm->isPreMohawk()) { - Common::SeekableSubReadStreamEndian *ctblStream = _vm->wrapStreamEndian(ID_CTBL, id); - uint16 colorCount = ctblStream->readUint16(); - byte *palette = new byte[colorCount * 3]; - - for (uint16 i = 0; i < colorCount; i++) { - palette[i * 3 + 0] = ctblStream->readByte(); - palette[i * 3 + 1] = ctblStream->readByte(); - palette[i * 3 + 2] = ctblStream->readByte(); - ctblStream->readByte(); - } - - delete ctblStream; - - _vm->_system->getPaletteManager()->setPalette(palette, 0, colorCount); - delete[] palette; - } else { - GraphicsManager::setPalette(id); - } -} - -#ifdef ENABLE_CSTIME - -CSTimeGraphics::CSTimeGraphics(MohawkEngine_CSTime *vm) : GraphicsManager(), _vm(vm) { - _bmpDecoder = new MohawkBitmap(); - - initGraphics(640, 480, true); -} - -CSTimeGraphics::~CSTimeGraphics() { - delete _bmpDecoder; -} - -void CSTimeGraphics::drawRect(Common::Rect rect, byte color) { - rect.clip(Common::Rect(640, 480)); - - // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active. - if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0) - return; - - Graphics::Surface *screen = _vm->_system->lockScreen(); - - screen->frameRect(rect, color); - - _vm->_system->unlockScreen(); -} - -MohawkSurface *CSTimeGraphics::decodeImage(uint16 id) { - return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id)); -} - -Common::Array<MohawkSurface *> CSTimeGraphics::decodeImages(uint16 id) { - return _bmpDecoder->decodeImages(_vm->getResource(ID_TBMH, id)); -} - -#endif - } // End of namespace Mohawk diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h index 463608a2aa..51d25db5d9 100644 --- a/engines/mohawk/graphics.h +++ b/engines/mohawk/graphics.h @@ -25,12 +25,11 @@ #include "mohawk/bitmap.h" -#include "common/file.h" #include "common/hashmap.h" -#include "graphics/pict.h" +#include "common/rect.h" namespace Graphics { -class JPEG; +struct Surface; } namespace Mohawk { @@ -99,200 +98,10 @@ protected: private: // An image cache that stores images until clearCache() is called - Common::HashMap<uint16, MohawkSurface*> _cache; - Common::HashMap<uint16, Common::Array<MohawkSurface*> > _subImageCache; + Common::HashMap<uint16, MohawkSurface *> _cache; + Common::HashMap<uint16, Common::Array<MohawkSurface *> > _subImageCache; }; -#ifdef ENABLE_MYST - -class MystBitmap; -class MohawkEngine_Myst; - -enum RectState { - kRectEnabled, - kRectDisabled, - kRectUnreachable -}; - -class MystGraphics : public GraphicsManager { -public: - MystGraphics(MohawkEngine_Myst*); - ~MystGraphics(); - - void loadExternalPictureFile(uint16 stack); - void copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest); - void copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest); - void copyImageToScreen(uint16 image, Common::Rect dest); - void copyImageToBackBuffer(uint16 image, Common::Rect dest); - void copyBackBufferToScreen(Common::Rect r); - void runTransition(uint16 type, Common::Rect rect, uint16 steps, uint16 delay); - void drawRect(Common::Rect rect, RectState state); - void drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color); - void enableDrawingTimeSimulation(bool enable); - void fadeToBlack(); - void fadeFromBlack(); - -protected: - MohawkSurface *decodeImage(uint16 id); - MohawkEngine *getVM() { return (MohawkEngine *)_vm; } - void simulatePreviousDrawDelay(const Common::Rect &dest); - void copyBackBufferToScreenWithSaturation(int16 saturation); - -private: - MohawkEngine_Myst *_vm; - MystBitmap *_bmpDecoder; - Graphics::PictDecoder *_pictDecoder; - Graphics::JPEG *_jpegDecoder; - - struct PictureFile { - uint32 pictureCount; - struct PictureEntry { - uint32 offset; - uint32 size; - uint16 id; - uint16 type; - uint16 width; - uint16 height; - } *entries; - - Common::File picFile; - } _pictureFile; - - Graphics::Surface *_backBuffer; - Graphics::PixelFormat _pixelFormat; - Common::Rect _viewport; - - int _enableDrawingTimeSimulation; - uint32 _nextAllowedDrawTime; - static const uint _constantDrawDelay = 10; // ms - static const uint _proportionalDrawDelay = 500; // pixels per ms -}; - -#endif // ENABLE_MYST - -#ifdef ENABLE_RIVEN - -class MohawkEngine_Riven; - -class RivenGraphics : public GraphicsManager { -public: - RivenGraphics(MohawkEngine_Riven *vm); - ~RivenGraphics(); - - void copyImageToScreen(uint16, uint32, uint32, uint32, uint32); - void updateScreen(Common::Rect updateRect = Common::Rect(0, 0, 608, 392)); - bool _updatesEnabled; - Common::Array<uint16> _activatedPLSTs; - void drawPLST(uint16 x); - void drawRect(Common::Rect rect, bool active); - void drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect); - void drawExtrasImage(uint16 id, Common::Rect dstRect); - - // Water Effect - void scheduleWaterEffect(uint16); - void clearWaterEffects(); - bool runScheduledWaterEffects(); - - // Transitions - void scheduleTransition(uint16 id, Common::Rect rect = Common::Rect(0, 0, 608, 392)); - void runScheduledTransition(); - void fadeToBlack(); - void setTransitionSpeed(uint32 speed) { _transitionSpeed = speed; } - - // Inventory - void showInventory(); - void hideInventory(); - - // Credits - void beginCredits(); - void updateCredits(); - uint getCurCreditsImage() { return _creditsImage; } - -protected: - MohawkSurface *decodeImage(uint16 id); - MohawkEngine *getVM() { return (MohawkEngine *)_vm; } - -private: - MohawkEngine_Riven *_vm; - MohawkBitmap *_bitmapDecoder; - - // Water Effects - struct SFXERecord { - // Record values - uint16 frameCount; - Common::Rect rect; - uint16 speed; - Common::Array<Common::SeekableReadStream*> frameScripts; - - // Cur frame - uint16 curFrame; - uint32 lastFrameTime; - }; - Common::Array<SFXERecord> _waterEffects; - - // Transitions - int16 _scheduledTransition; - Common::Rect _transitionRect; - uint32 _transitionSpeed; - - // Inventory - void clearInventoryArea(); - void drawInventoryImage(uint16 id, const Common::Rect *rect); - bool _inventoryDrawn; - - // Screen Related - Graphics::Surface *_mainScreen; - bool _dirtyScreen; - Graphics::PixelFormat _pixelFormat; - void clearMainScreen(); - - // Credits - uint _creditsImage, _creditsPos; -}; - -#endif // ENABLE_RIVEN - -class LBGraphics : public GraphicsManager { -public: - LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height); - ~LBGraphics(); - - void setPalette(uint16 id); - void copyOffsetAnimImageToScreen(uint16 image, int left = 0, int top = 0); - bool imageIsTransparentAt(uint16 image, bool useOffsets, int x, int y); - -protected: - MohawkSurface *decodeImage(uint16 id); - MohawkEngine *getVM() { return (MohawkEngine *)_vm; } - -private: - MohawkBitmap *_bmpDecoder; - MohawkEngine_LivingBooks *_vm; -}; - -#ifdef ENABLE_CSTIME - -class MohawkEngine_CSTime; - -class CSTimeGraphics : public GraphicsManager { -public: - CSTimeGraphics(MohawkEngine_CSTime *vm); - ~CSTimeGraphics(); - - void drawRect(Common::Rect rect, byte color); - -protected: - MohawkSurface *decodeImage(uint16 id); - Common::Array<MohawkSurface *> decodeImages(uint16 id); - MohawkEngine *getVM() { return (MohawkEngine *)_vm; } - -private: - MohawkBitmap *_bmpDecoder; - MohawkEngine_CSTime *_vm; -}; - -#endif - } // End of namespace Mohawk #endif diff --git a/engines/mohawk/installer_archive.cpp b/engines/mohawk/installer_archive.cpp index 83796158a6..636b7ae476 100644 --- a/engines/mohawk/installer_archive.cpp +++ b/engines/mohawk/installer_archive.cpp @@ -107,18 +107,18 @@ void InstallerArchive::close() { _map.clear(); } -bool InstallerArchive::hasFile(const Common::String &name) { +bool InstallerArchive::hasFile(const Common::String &name) const { return _map.contains(name); } -int InstallerArchive::listMembers(Common::ArchiveMemberList &list) { +int InstallerArchive::listMembers(Common::ArchiveMemberList &list) const { for (FileMap::const_iterator it = _map.begin(); it != _map.end(); it++) list.push_back(getMember(it->_key)); return _map.size(); } -Common::ArchiveMemberPtr InstallerArchive::getMember(const Common::String &name) { +const Common::ArchiveMemberPtr InstallerArchive::getMember(const Common::String &name) const { return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this)); } diff --git a/engines/mohawk/installer_archive.h b/engines/mohawk/installer_archive.h index 27877d69f9..89d2d85f8d 100644 --- a/engines/mohawk/installer_archive.h +++ b/engines/mohawk/installer_archive.h @@ -43,9 +43,9 @@ public: bool isOpen() const { return _stream != 0; } // Common::Archive API implementation - bool hasFile(const Common::String &name); - int listMembers(Common::ArchiveMemberList &list); - Common::ArchiveMemberPtr getMember(const Common::String &name); + bool hasFile(const Common::String &name) const; + int listMembers(Common::ArchiveMemberList &list) const; + const Common::ArchiveMemberPtr getMember(const Common::String &name) const; Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; private: diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp index 65073bd970..708478a6d8 100644 --- a/engines/mohawk/livingbooks.cpp +++ b/engines/mohawk/livingbooks.cpp @@ -102,6 +102,14 @@ void LBPage::open(Archive *mhk, uint16 baseId) { for (uint32 i = 0; i < _items.size(); i++) _items[i]->init(); + + for (uint32 i = 0; i < _items.size(); i++) + _items[i]->startPhase(kLBPhaseLoad); +} + +void LBPage::addClonedItem(LBItem *item) { + _vm->addItem(item); + _items.push_back(item); } void LBPage::itemDestroyed(LBItem *item) { @@ -138,8 +146,12 @@ MohawkEngine_LivingBooks::MohawkEngine_LivingBooks(OSystem *syst, const MohawkGa const Common::FSNode gameDataDir(ConfMan.get("path")); // Rugrats - SearchMan.addSubDirectoryMatching(gameDataDir, "program"); - SearchMan.addSubDirectoryMatching(gameDataDir, "Rugrats Adventure Game"); + const Common::FSNode ProgPath = gameDataDir.getChild("program"); + if (ProgPath.exists()) + SearchMan.addDirectory(ProgPath.getPath(), ProgPath, 0, 2); + const Common::FSNode RugPath = gameDataDir.getChild("Rugrats Adventure Game"); + if (RugPath.exists()) + SearchMan.addDirectory(RugPath.getPath(), RugPath, 0, 2); // CarmenTQ const Common::FSNode CTQPath = gameDataDir.getChild("95instal"); if (CTQPath.exists()) @@ -304,8 +316,9 @@ void MohawkEngine_LivingBooks::loadBookInfo(const Common::String &filename) { const Common::ConfigFile::SectionKeyList globals = _bookInfoFile.getKeys("Globals"); for (Common::ConfigFile::SectionKeyList::const_iterator i = globals.begin(); i != globals.end(); i++) { Common::String command = Common::String::format("%s = %s", i->key.c_str(), i->value.c_str()); - debug("global: %s", command.c_str()); - // TODO: run command + LBCode tempCode(this, 0); + uint offset = tempCode.parseCode(command); + tempCode.runCode(NULL, offset); } } } @@ -375,10 +388,13 @@ bool MohawkEngine_LivingBooks::loadPage(LBMode mode, uint page, uint subpage) { } // TODO: fading between pages +#if 0 bool fade = false; if (leftover.contains("fade")) { fade = true; } +#endif + if (leftover.contains("read")) { _readOnly = true; } @@ -436,12 +452,9 @@ bool MohawkEngine_LivingBooks::loadPage(LBMode mode, uint page, uint subpage) { void MohawkEngine_LivingBooks::updatePage() { switch (_phase) { - case 0: - for (uint32 i = 0; i < _items.size(); i++) - _items[i]->startPhase(0xFFFE); - + case kLBPhaseInit: for (uint32 i = 0; i < _items.size(); i++) - _items[i]->startPhase(0xFFFF); + _items[i]->startPhase(kLBPhaseCreate); for (uint32 i = 0; i < _items.size(); i++) _items[i]->startPhase(_phase); @@ -537,7 +550,7 @@ void MohawkEngine_LivingBooks::updatePage() { _phase++; break; - case 1: + case kLBPhaseIntro: for (uint32 i = 0; i < _items.size(); i++) _items[i]->startPhase(_phase); @@ -550,7 +563,7 @@ void MohawkEngine_LivingBooks::updatePage() { _phase++; break; - case 2: + case kLBPhaseMain: if (!_introDone) break; @@ -593,8 +606,8 @@ void MohawkEngine_LivingBooks::updatePage() { _items[i]->update(); if (_needsRedraw) { - for (uint16 i = 0; i < _items.size(); i++) - _items[i]->draw(); + for (Common::List<LBItem *>::const_iterator i = _orderedItems.reverse_begin(); i != _orderedItems.end(); --i) + (*i)->draw(); _needsRedraw = false; _needsUpdate = true; @@ -1854,6 +1867,35 @@ void LBAnimation::seek(uint16 pos) { } } +void LBAnimation::seekToTime(uint32 time) { + _lastTime = 0; + _currentFrame = 0; + + if (_currentSound != 0xffff) { + _vm->_sound->stopSound(_currentSound); + _currentSound = 0xffff; + } + + for (uint32 i = 0; i < _nodes.size(); i++) + _nodes[i]->reset(); + + uint32 elapsed = 0; + while (elapsed <= time) { + bool ranSomething = false; + // nodes don't wait while seeking + for (uint32 i = 0; i < _nodes.size(); i++) + ranSomething |= (_nodes[i]->update(true) != kLBNodeDone); + + elapsed += _tempo; + _currentFrame++; + + if (!ranSomething) { + _running = false; + break; + } + } +} + void LBAnimation::stop() { _running = false; if (_currentSound != 0xffff) { @@ -1920,7 +1962,10 @@ LBScriptEntry::~LBScriptEntry() { } LBItem::LBItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : _vm(vm), _page(page), _rect(rect) { - _phase = 0; + if (_vm->getGameType() == GType_LIVINGBOOKSV1 || _vm->getGameType() == GType_LIVINGBOOKSV2) + _phase = kLBPhaseInit; + else + _phase = kLBPhaseLoad; _loopMode = 0; _delayMin = 0; @@ -1931,7 +1976,7 @@ LBItem::LBItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : _controlMode = kLBControlNone; _soundMode = 0; - _neverEnabled = true; + _loaded = false; _enabled = false; _visible = true; _playing = false; @@ -2338,6 +2383,22 @@ void LBItem::readData(uint16 type, uint16 size, Common::MemoryReadStreamEndian * } break; + case kLBSetRolloverData: + { + assert(size == 2); + uint16 flag = stream->readUint16(); + warning("ignoring kLBSetRolloverData: item %s, flag %d", _desc.c_str(), flag); + } + break; + + case kLBSetParent: + { + assert(size == 2); + uint16 parent = stream->readUint16(); + warning("ignoring kLBSetParent: item %s, parent id %d", _desc.c_str(), parent); + } + break; + case kLBUnknown194: { assert(size == 4); @@ -2365,25 +2426,27 @@ void LBItem::destroySelf() { } void LBItem::setEnabled(bool enabled) { - if (enabled && _neverEnabled && !_playing) { + if (enabled && !_loaded && !_playing) { if (_timingMode == kLBAutoUserIdle) { setNextTime(_periodMin, _periodMax); debug(2, "Enable time startup"); } } - _neverEnabled = false; _enabled = enabled; } void LBItem::setGlobalEnabled(bool enabled) { - bool wasEnabled = !_neverEnabled && _enabled && _globalEnabled; + bool wasEnabled = _loaded && _enabled && _globalEnabled; _globalEnabled = enabled; - if (wasEnabled != (!_neverEnabled && _enabled && _globalEnabled)) + if (wasEnabled != (_loaded && _enabled && _globalEnabled)) setEnabled(enabled); } bool LBItem::contains(Common::Point point) { + if (!_loaded) + return false; + if (_playing && _loopMode == 0xFFFF) stop(); @@ -2394,7 +2457,7 @@ bool LBItem::contains(Common::Point point) { } void LBItem::update() { - if (_phase != 0x7FFF && (_neverEnabled || !_enabled || !_globalEnabled)) + if (_phase != kLBPhaseNone && (!_loaded || !_enabled || !_globalEnabled)) return; if (_nextTime == 0 || _nextTime > (uint32)(_vm->_system->getMillis() / 16)) @@ -2409,7 +2472,7 @@ void LBItem::update() { } void LBItem::handleMouseDown(Common::Point pos) { - if (_neverEnabled || !_enabled || !_globalEnabled) + if (!_loaded || !_enabled || !_globalEnabled) return; _vm->setFocus(this); @@ -2432,7 +2495,7 @@ bool LBItem::togglePlaying(bool playing, bool restart) { _vm->queueDelayedEvent(DelayedEvent(this, kLBDelayedEventDone)); return true; } - if (((!_neverEnabled && _enabled && _globalEnabled) || _phase == 0x7FFF) && !_playing) { + if (((_loaded && _enabled && _globalEnabled) || _phase == kLBPhaseNone) && !_playing) { _playing = togglePlaying(true, restart); if (_playing) { _nextTime = 0; @@ -2501,6 +2564,10 @@ void LBItem::done(bool onlyNotify) { notify(0xFFFF, _itemId); } +void LBItem::init() { + runScript(kLBEventInit); +} + void LBItem::setVisible(bool visible) { if (visible == _visible) return; @@ -2517,38 +2584,40 @@ void LBItem::setGlobalVisible(bool visible) { } void LBItem::startPhase(uint phase) { - if (_phase == phase) - setEnabled(true); + if (_phase == phase) { + if (_phase != kLBPhaseNone) { + setEnabled(true); + } + + load(); + } switch (phase) { - case 0xFFFE: - if (_timingMode == kLBAutoLoad) { - debug(2, "Phase load: time startup"); - setNextTime(_periodMin, _periodMax); - } + case kLBPhaseLoad: + runScript(kLBEventListLoad); break; - case 0xFFFF: + case kLBPhaseCreate: runScript(kLBEventPhaseCreate); if (_timingMode == kLBAutoCreate) { debug(2, "Phase create: time startup"); setNextTime(_periodMin, _periodMax); } break; - case 0: + case kLBPhaseInit: runScript(kLBEventPhaseInit); if (_timingMode == kLBAutoInit) { debug(2, "Phase init: time startup"); setNextTime(_periodMin, _periodMax); } break; - case 1: + case kLBPhaseIntro: runScript(kLBEventPhaseIntro); if (_timingMode == kLBAutoIntro || _timingMode == kLBAutoUserIdle) { debug(2, "Phase intro: time startup"); setNextTime(_periodMin, _periodMax); } break; - case 2: + case kLBPhaseMain: runScript(kLBEventPhaseMain); if (_timingMode == kLBAutoUserIdle || _timingMode == kLBAutoMain) { debug(2, "Phase main: time startup"); @@ -2579,6 +2648,54 @@ void LBItem::notify(uint16 data, uint16 from) { runScript(kLBEventNotified, data, from); } +void LBItem::load() { + if (_loaded) + return; + + _loaded = true; + + // FIXME: events etc + if (_timingMode == kLBAutoLoad) { + debug(2, "Load: time startup"); + setNextTime(_periodMin, _periodMax); + } +} + +void LBItem::unload() { + if (!_loaded) + return; + + _loaded = false; + + // FIXME: stuff +} + +void LBItem::moveBy(const Common::Point &pos) { + _rect.translate(pos.x, pos.y); +} + +void LBItem::moveTo(const Common::Point &pos) { + _rect.moveTo(pos); +} + +LBItem *LBItem::clone(uint16 newId, const Common::String &newName) { + LBItem *item = createClone(); + + item->_itemId = newId; + item->_desc = newName; + + item->_resourceId = _resourceId; + // FIXME: the rest + + _page->addClonedItem(item); + // FIXME: zorder? + return item; +} + +LBItem *LBItem::createClone() { + return new LBItem(_vm, _page, _rect); +} + void LBItem::runScript(uint event, uint16 data, uint16 from) { for (uint i = 0; i < _scriptEntries.size(); i++) { LBScriptEntry *entry = _scriptEntries[i]; @@ -2819,9 +2936,7 @@ int LBItem::runScriptEntry(LBScriptEntry *entry) { break; case kLBOpLoad: - // FIXME - warning("ignoring kLBOpLoad (event 0x%04x, param 0x%04x, target '%s')", - entry->event, entry->param, target->_desc.c_str()); + target->load(); break; case kLBOpPreload: @@ -2831,9 +2946,7 @@ int LBItem::runScriptEntry(LBScriptEntry *entry) { break; case kLBOpUnload: - // FIXME - warning("ignoring kLBOpUnload (event 0x%04x, param 0x%04x, target '%s')", - entry->event, entry->param, target->_desc.c_str()); + target->unload(); break; case kLBOpSeekToPrev: @@ -2882,6 +2995,7 @@ int LBItem::runScriptEntry(LBScriptEntry *entry) { case kLBOpBreakExpression: debug(2, "BreakExpression"); i = entry->subentries.size(); + break; case kLBOpJumpToExpression: debug(2, "JumpToExpression got %d (on %d, of %d)", e, i, entry->subentries.size()); i = e - 1; @@ -2969,7 +3083,7 @@ bool LBSoundItem::togglePlaying(bool playing, bool restart) { _vm->_sound->stopSound(_resourceId); } - if (_neverEnabled || !_enabled || !_globalEnabled) + if (!_loaded || !_enabled || !_globalEnabled) return false; _running = true; @@ -2987,6 +3101,10 @@ void LBSoundItem::stop() { LBItem::stop(); } +LBItem *LBSoundItem::createClone() { + return new LBSoundItem(_vm, _page, _rect); +} + LBGroupItem::LBGroupItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : LBItem(vm, page, rect) { debug(3, "new LBGroupItem"); _starting = false; @@ -3102,6 +3220,44 @@ void LBGroupItem::stop() { } } +void LBGroupItem::load() { + for (uint i = 0; i < _groupEntries.size(); i++) { + LBItem *item = _vm->getItemById(_groupEntries[i].entryId); + if (item) + item->load(); + } +} + +void LBGroupItem::unload() { + for (uint i = 0; i < _groupEntries.size(); i++) { + LBItem *item = _vm->getItemById(_groupEntries[i].entryId); + if (item) + item->unload(); + } +} + +void LBGroupItem::moveBy(const Common::Point &pos) { + for (uint i = 0; i < _groupEntries.size(); i++) { + LBItem *item = _vm->getItemById(_groupEntries[i].entryId); + if (item) + item->moveBy(pos); + } +} + +void LBGroupItem::moveTo(const Common::Point &pos) { + for (uint i = 0; i < _groupEntries.size(); i++) { + LBItem *item = _vm->getItemById(_groupEntries[i].entryId); + if (item) + item->moveTo(pos); + } +} + +LBItem *LBGroupItem::createClone() { + // TODO: needed? + error("LBGroupItem::createClone unimplemented"); + return new LBGroupItem(_vm, _page, _rect); +} + LBPaletteItem::LBPaletteItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : LBItem(vm, page, rect) { debug(3, "new LBPaletteItem"); @@ -3187,6 +3343,10 @@ void LBPaletteItem::update() { LBItem::update(); } +LBItem *LBPaletteItem::createClone() { + error("can't clone LBPaletteItem"); +} + LBLiveTextItem::LBLiveTextItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : LBItem(vm, page, rect) { _currentPhrase = 0xFFFF; _currentWord = 0xFFFF; @@ -3350,7 +3510,7 @@ void LBLiveTextItem::drawWord(uint word, uint yPos) { } void LBLiveTextItem::handleMouseDown(Common::Point pos) { - if (_neverEnabled || !_enabled || !_globalEnabled || _playing) + if (!_loaded || !_enabled || !_globalEnabled || _playing) return LBItem::handleMouseDown(pos); pos.x -= _rect.left; @@ -3381,7 +3541,7 @@ void LBLiveTextItem::handleMouseDown(Common::Point pos) { bool LBLiveTextItem::togglePlaying(bool playing, bool restart) { if (!playing) return LBItem::togglePlaying(playing, restart); - if (_neverEnabled || !_enabled || !_globalEnabled) + if (!_loaded || !_enabled || !_globalEnabled) return _playing; // TODO: handle this properly @@ -3400,7 +3560,7 @@ void LBLiveTextItem::stop() { } void LBLiveTextItem::notify(uint16 data, uint16 from) { - if (_neverEnabled || !_enabled || !_globalEnabled || !_playing) + if (!_loaded || !_enabled || !_globalEnabled || !_playing) return LBItem::notify(data, from); if (_currentWord != 0xFFFF) { @@ -3434,6 +3594,10 @@ void LBLiveTextItem::notify(uint16 data, uint16 from) { LBItem::notify(data, from); } +LBItem *LBLiveTextItem::createClone() { + error("can't clone LBLiveTextItem"); +} + LBPictureItem::LBPictureItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : LBItem(vm, page, rect) { debug(3, "new LBPictureItem"); } @@ -3468,15 +3632,21 @@ bool LBPictureItem::contains(Common::Point point) { void LBPictureItem::init() { _vm->_gfx->preloadImage(_resourceId); + + LBItem::init(); } void LBPictureItem::draw() { - if (!_visible || !_globalVisible) + if (!_loaded || !_visible || !_globalVisible) return; _vm->_gfx->copyAnimImageToScreen(_resourceId, _rect.left, _rect.top); } +LBItem *LBPictureItem::createClone() { + return new LBPictureItem(_vm, _page, _rect); +} + LBAnimationItem::LBAnimationItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : LBItem(vm, page, rect) { _anim = NULL; _running = false; @@ -3489,9 +3659,9 @@ LBAnimationItem::~LBAnimationItem() { void LBAnimationItem::setEnabled(bool enabled) { if (_running) { - if (enabled && _globalEnabled && _neverEnabled) + if (enabled && _globalEnabled && !_loaded) _anim->start(); - else if (!_neverEnabled && !enabled && _enabled && _globalEnabled) + else if (_loaded && !enabled && _enabled && _globalEnabled) _anim->stop(); } @@ -3509,7 +3679,7 @@ bool LBAnimationItem::contains(Common::Point point) { } void LBAnimationItem::update() { - if (!_neverEnabled && _enabled && _globalEnabled && _running) { + if (_loaded && _enabled && _globalEnabled && _running) { bool wasDone = _anim->update(); if (wasDone) { _running = false; @@ -3522,7 +3692,7 @@ void LBAnimationItem::update() { bool LBAnimationItem::togglePlaying(bool playing, bool restart) { if (playing) { - if (!_neverEnabled && _enabled && _globalEnabled) { + if (_loaded && _enabled && _globalEnabled) { if (restart) seek(1); _running = true; @@ -3545,6 +3715,8 @@ void LBAnimationItem::done(bool onlyNotify) { void LBAnimationItem::init() { _anim = new LBAnimation(_vm, this, _resourceId); + + LBItem::init(); } void LBAnimationItem::stop() { @@ -3562,6 +3734,10 @@ void LBAnimationItem::seek(uint16 pos) { _anim->seek(pos); } +void LBAnimationItem::seekToTime(uint32 time) { + _anim->seekToTime(time); +} + void LBAnimationItem::startPhase(uint phase) { if (phase == _phase) seek(1); @@ -3576,6 +3752,12 @@ void LBAnimationItem::draw() { _anim->draw(); } +LBItem *LBAnimationItem::createClone() { + LBAnimationItem *item = new LBAnimationItem(_vm, _page, _rect); + item->_anim = new LBAnimation(_vm, item, _resourceId); + return item; +} + LBMovieItem::LBMovieItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : LBItem(vm, page, rect) { debug(3, "new LBMovieItem"); } @@ -3595,7 +3777,7 @@ void LBMovieItem::update() { bool LBMovieItem::togglePlaying(bool playing, bool restart) { if (playing) { - if ((!_neverEnabled && _enabled && _globalEnabled) || _phase == 0x7FFF) { + if ((_loaded && _enabled && _globalEnabled) || _phase == kLBPhaseNone) { _vm->_video->playMovie(_resourceId, _rect.left, _rect.top); return true; @@ -3605,6 +3787,10 @@ bool LBMovieItem::togglePlaying(bool playing, bool restart) { return LBItem::togglePlaying(playing, restart); } +LBItem *LBMovieItem::createClone() { + return new LBMovieItem(_vm, _page, _rect); +} + LBMiniGameItem::LBMiniGameItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : LBItem(vm, page, rect) { debug(3, "new LBMiniGameItem"); } @@ -3640,6 +3826,10 @@ bool LBMiniGameItem::togglePlaying(bool playing, bool restart) { return false; } +LBItem *LBMiniGameItem::createClone() { + error("can't clone LBMiniGameItem"); +} + LBProxyItem::LBProxyItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : LBItem(vm, page, rect) { debug(3, "new LBProxyItem"); @@ -3650,7 +3840,10 @@ LBProxyItem::~LBProxyItem() { delete _page; } -void LBProxyItem::init() { +void LBProxyItem::load() { + if (_loaded) + return; + Common::String leftover; Common::String filename = _vm->getFileNameFromConfig("Proxies", _desc.c_str(), leftover); if (!leftover.empty()) @@ -3669,6 +3862,19 @@ void LBProxyItem::init() { error("failed to open archive '%s' (for proxy '%s')", filename.c_str(), _desc.c_str()); _page = new LBPage(_vm); _page->open(pageArchive, baseId); + + LBItem::load(); +} + +void LBProxyItem::unload() { + delete _page; + _page = NULL; + + LBItem::unload(); +} + +LBItem *LBProxyItem::createClone() { + return new LBProxyItem(_vm, _page, _rect); } } // End of namespace Mohawk diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h index 008a7dbf23..91d6a8cd30 100644 --- a/engines/mohawk/livingbooks.h +++ b/engines/mohawk/livingbooks.h @@ -25,7 +25,7 @@ #include "mohawk/mohawk.h" #include "mohawk/console.h" -#include "mohawk/graphics.h" +#include "mohawk/livingbooks_graphics.h" #include "mohawk/sound.h" #include "common/config-file.h" @@ -68,6 +68,15 @@ enum LBMode { kLBPlayMode = 6 }; +enum { + kLBPhaseInit = 0x0, + kLBPhaseIntro = 0x1, + kLBPhaseMain = 0x2, + kLBPhaseNone = 0x7fff, + kLBPhaseLoad = 0xfffe, + kLBPhaseCreate = 0xffff +}; + // automatic modes used in _timingMode enum { kLBAutoNone = 0, @@ -178,10 +187,10 @@ enum { kLBGlobalSetNotVisible = 0x79, kLBGlobalSetVisible = 0x7a, // unused? kLBSetAmbient = 0x7b, - kLBUnknown7C = 0x7c, // unused? + kLBSetDragParams = 0x7c, kLBSetKeyEvent = 0x7d, - kLBUnknown7E = 0x7e, // unused? (rect flag) - kLBSetParent = 0x7f, // unused? + kLBSetRolloverData = 0x7e, + kLBSetParent = 0x7f, kLBSetHitTest = 0x80, // from here, rugrats kLBUnknown194 = 0x194 @@ -331,6 +340,7 @@ public: void start(); void seek(uint16 pos); + void seekToTime(uint32 time); void stop(); void playSound(uint16 resourceId); @@ -391,23 +401,34 @@ public: virtual void handleMouseUp(Common::Point pos); // 0xD virtual bool togglePlaying(bool playing, bool restart = false); // 0xF virtual void done(bool onlyNotify); // 0x10 - virtual void init() { } // 0x11 + virtual void init(); // 0x11 virtual void seek(uint16 pos) { } // 0x13 + virtual void seekToTime(uint32 time) { } virtual void setFocused(bool focused) { } // 0x14 virtual void setVisible(bool visible); // 0x17 virtual void setGlobalVisible(bool enabled); virtual void startPhase(uint phase); // 0x18 virtual void stop(); // 0x19 virtual void notify(uint16 data, uint16 from); // 0x1A + virtual void load(); + virtual void unload(); + virtual void moveBy(const Common::Point &pos); + virtual void moveTo(const Common::Point &pos); + + LBItem *clone(uint16 newId, const Common::String &newName); uint16 getId() { return _itemId; } const Common::String &getName() { return _desc; } const Common::Rect &getRect() { return _rect; } uint16 getSoundPriority() { return _soundMode; } + bool isLoaded() { return _loaded; } bool isAmbient() { return _isAmbient; } Common::List<LBItem *>::iterator _iterator; + // TODO: make private + Common::HashMap<Common::String, LBValue, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _variables; + protected: MohawkEngine_LivingBooks *_vm; LBPage *_page; @@ -420,7 +441,7 @@ protected: uint16 _resourceId; uint16 _itemId; - bool _visible, _globalVisible, _playing, _enabled, _neverEnabled, _globalEnabled; + bool _loaded, _visible, _globalVisible, _playing, _enabled, _globalEnabled; uint32 _nextTime, _startTime; uint16 _loops; @@ -433,6 +454,8 @@ protected: bool _isAmbient; bool _doHitTest; + virtual LBItem *createClone(); + Common::Array<LBScriptEntry *> _scriptEntries; void runScript(uint event, uint16 data = 0, uint16 from = 0); int runScriptEntry(LBScriptEntry *entry); @@ -453,6 +476,8 @@ public: void stop(); protected: + LBItem *createClone(); + bool _running; }; @@ -478,8 +503,14 @@ public: void setGlobalVisible(bool visible); void startPhase(uint phase); void stop(); + void load(); + void unload(); + void moveBy(const Common::Point &pos); + void moveTo(const Common::Point &pos); protected: + LBItem *createClone(); + bool _starting; Common::Array<GroupEntry> _groupEntries; @@ -496,6 +527,8 @@ public: void update(); protected: + LBItem *createClone(); + uint16 _fadeInPeriod, _fadeInStep, _drawStart, _drawCount; uint32 _fadeInStart, _fadeInCurrent; byte *_palette; @@ -527,6 +560,8 @@ public: void notify(uint16 data, uint16 from); protected: + LBItem *createClone(); + void paletteUpdate(uint16 word, bool on); void drawWord(uint word, uint yPos); @@ -550,6 +585,9 @@ public: bool contains(Common::Point point); void draw(); void init(); + +protected: + LBItem *createClone(); }; class LBAnimationItem : public LBItem { @@ -565,10 +603,13 @@ public: void done(bool onlyNotify); void init(); void seek(uint16 pos); + void seekToTime(uint32 time); void startPhase(uint phase); void stop(); protected: + LBItem *createClone(); + LBAnimation *_anim; bool _running; }; @@ -580,6 +621,9 @@ public: void update(); bool togglePlaying(bool playing, bool restart); + +protected: + LBItem *createClone(); }; class LBMiniGameItem : public LBItem { @@ -588,6 +632,9 @@ public: ~LBMiniGameItem(); bool togglePlaying(bool playing, bool restart); + +protected: + LBItem *createClone(); }; class LBProxyItem : public LBItem { @@ -595,9 +642,12 @@ public: LBProxyItem(MohawkEngine_LivingBooks *_vm, LBPage *page, Common::Rect rect); ~LBProxyItem(); - void init(); + void load(); + void unload(); protected: + LBItem *createClone(); + class LBPage *_page; }; @@ -634,6 +684,7 @@ public: void open(Archive *mhk, uint16 baseId); uint16 getResourceVersion(); + void addClonedItem(LBItem *item); void itemDestroyed(LBItem *item); LBCode *_code; @@ -697,7 +748,7 @@ public: void nextPage(); // TODO: make private - Common::HashMap<Common::String, LBValue> _variables; + Common::HashMap<Common::String, LBValue, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _variables; // helper functions, also used by LBProxyItem Common::String getFileNameFromConfig(const Common::String §ion, const Common::String &key, Common::String &leftover); diff --git a/engines/mohawk/livingbooks_code.cpp b/engines/mohawk/livingbooks_code.cpp index 80b5fe9660..bb8f7a0d05 100644 --- a/engines/mohawk/livingbooks_code.cpp +++ b/engines/mohawk/livingbooks_code.cpp @@ -21,8 +21,10 @@ */ #include "mohawk/livingbooks.h" +#include "mohawk/livingbooks_lbx.h" #include "mohawk/resource.h" +#include "common/events.h" #include "common/system.h" #include "common/textconsole.h" @@ -99,12 +101,17 @@ double LBValue::toDouble() const { Common::Point LBValue::toPoint() const { switch (type) { case kLBValueString: - // FIXME - return Common::Point(); + { + Common::Point ret; + sscanf(string.c_str(), "%hd , %hd", &ret.x, &ret.y); + return ret; + } case kLBValueInteger: return Common::Point(integer, integer); case kLBValuePoint: return point; + case kLBValueRect: + return Common::Point(rect.left, rect.top); default: error("failed to convert to point"); } @@ -113,10 +120,15 @@ Common::Point LBValue::toPoint() const { Common::Rect LBValue::toRect() const { switch (type) { case kLBValueString: - // FIXME - return Common::Rect(); + { + Common::Rect ret; + sscanf(string.c_str(), "%hd , %hd , %hd , %hd", &ret.left, &ret.top, &ret.right, &ret.bottom); + return ret; + } case kLBValueInteger: return Common::Rect(integer, integer, integer, integer); + case kLBValuePoint: + return Common::Rect(point.x, point.y, point.x, point.y); case kLBValueRect: return rect; case kLBValueItemPtr: @@ -476,26 +488,84 @@ void LBCode::parseMain() { if (_currToken == kTokenAssign) error("attempted assignment to self"); break; - } else if (_currToken == kTokenAssign) { + } + bool indexing = false; + Common::Array<LBValue> index; + while (_currToken == kTokenListStart) { + debugN("["); + nextToken(); + parseStatement(); + if (_currToken != kTokenListEnd) + error("expected list end"); + debugN("]"); + nextToken(); + if (!_stack.size()) + error("index failed"); + indexing = true; + index.push_back(_stack.pop()); + } + if (_currToken == kTokenAssign) { debugN(" = "); nextToken(); parseStatement(); if (!_stack.size()) error("assignment failed"); - LBValue *val = &_vm->_variables[varname]; - *val = _stack.pop(); - _stack.push(*val); + LBValue *val; + if (indexing) + val = getIndexedVar(varname, index); + else + val = &_vm->_variables[varname]; + if (val) { + *val = _stack.pop(); + _stack.push(*val); + } else + _stack.push(LBValue()); + } else if (_currToken == kTokenAndEquals) { + debugN(" &= "); + nextToken(); + parseStatement(); + if (!_stack.size()) + error("assignment failed"); + LBValue *val; + if (indexing) + val = getIndexedVar(varname, index); + else + val = &_vm->_variables[varname]; + if (val) { + if (val->type != kLBValueString) + error("operator &= used on non-string"); + val->string = val->string + _stack.pop().toString(); + _stack.push(*val); + } else + _stack.push(LBValue()); } else { - _stack.push(_vm->_variables[varname]); + if (indexing) { + LBValue *val = getIndexedVar(varname, index); + if (val) + _stack.push(*val); + else + _stack.push(LBValue()); + } else + _stack.push(_vm->_variables[varname]); } // FIXME: pre/postincrement for non-integers if (_currToken == kTokenPlusPlus) { debugN("++"); - _vm->_variables[varname].integer++; + if (indexing) { + LBValue *val = getIndexedVar(varname, index); + if (val) + val->integer++; + } else + _vm->_variables[varname].integer++; nextToken(); } else if (_currToken == kTokenMinusMinus) { debugN("--"); - _vm->_variables[varname].integer--; + if (indexing) { + LBValue *val = getIndexedVar(varname, index); + if (val) + val->integer--; + } else + _vm->_variables[varname].integer--; nextToken(); } } @@ -567,6 +637,28 @@ void LBCode::parseMain() { nextToken(); break; + case kTokenListStart: + debugN("["); + nextToken(); + { + Common::SharedPtr<LBList> list = Common::SharedPtr<LBList>(new LBList); + while (_currToken != kTokenListEnd) { + parseStatement(); + if (!_stack.size()) + error("unexpected empty stack during literal list evaluation"); + list->array.push_back(_stack.pop()); + if (_currToken == kTokenComma) { + debugN(", "); + nextToken(); + } else if (_currToken != kTokenListEnd) + error("encountered unexpected token %02x during literal list", _currToken); + } + debugN("]"); + nextToken(); + _stack.push(list); + } + break; + case kTokenNot: debugN("!"); nextToken(); @@ -607,6 +699,20 @@ void LBCode::parseMain() { } } +LBValue *LBCode::getIndexedVar(Common::String varname, const Common::Array<LBValue> &index) { + LBValue *var = &_vm->_variables[varname]; + for (uint i = 0; i < index.size(); i++) { + if (var->type != kLBValueList) + error("variable '%s' was indexed, but isn't a list after %d indexes", varname.c_str(), i); + if (index[i].type != kLBValueInteger) + error("index %d wasn't an integer", i); + if (index[i].integer < 1 || index[i].integer > (int)var->list->array.size()) + return NULL; + var = &var->list->array[index[i].integer - 1]; + } + return var; +} + LBItem *LBCode::resolveItem(const LBValue &value) { if (value.type == kLBValueItemPtr) return value.item; @@ -626,7 +732,7 @@ Common::Array<LBValue> LBCode::readParams() { byte numParams = _data[_currOffset++]; if (!numParams) { - debugN("()\n"); + debugN("()"); nextToken(); return params; } @@ -688,14 +794,14 @@ CodeCommandInfo generalCommandInfo[NUM_GENERAL_COMMANDS] = { { "random", &LBCode::cmdRandom }, { "stringLen", &LBCode::cmdStringLen }, { "substring", &LBCode::cmdSubstring }, - { "max", 0 }, - { "min", 0 }, - { "abs", 0 }, + { "max", &LBCode::cmdMax }, + { "min", &LBCode::cmdMin }, + { "abs", &LBCode::cmdAbs }, { "getRect", &LBCode::cmdGetRect }, // also "makeRect" - { "makePt", 0 }, // also "makePair" + { "makePt", &LBCode::cmdMakePoint }, // also "makePair" { "topLeft", &LBCode::cmdTopLeft }, { "bottomRight", &LBCode::cmdBottomRight }, - { "mousePos", 0 }, + { "mousePos", &LBCode::cmdMousePos }, { "top", &LBCode::cmdTop }, { "left", &LBCode::cmdLeft }, { "bottom", &LBCode::cmdBottom }, @@ -704,7 +810,7 @@ CodeCommandInfo generalCommandInfo[NUM_GENERAL_COMMANDS] = { { "xpos", 0 }, { "ypos", 0 }, { "playFrom", 0 }, - { "move", 0 }, + { "move", &LBCode::cmdMove }, { 0, 0 }, { 0, 0 }, { "setDragParams", &LBCode::cmdSetDragParams }, @@ -727,26 +833,26 @@ CodeCommandInfo generalCommandInfo[NUM_GENERAL_COMMANDS] = { { "getPage", 0 }, { "getWorldRect", 0 }, { "isWorldWrap", 0 }, - { "newList", 0 }, + { "newList", &LBCode::cmdNewList }, { "deleteList", 0 }, - { "add", 0 }, + { "add", &LBCode::cmdAdd }, { 0, 0 }, - { "addAt", 0 }, + { "addAt", &LBCode::cmdAddAt }, { "getAt", 0 }, // 0x30 { 0, 0 }, { "getIndex", 0 }, - { "setAt", 0 }, - { "listLen", 0 }, - { "deleteAt", 0 }, - { "clearList", 0 }, + { "setAt", &LBCode::cmdSetAt }, + { "listLen", &LBCode::cmdListLen }, + { "deleteAt", &LBCode::cmdDeleteAt }, + { "clearList", &LBCode::cmdUnimplemented }, { "setWorld", 0 }, - { "setProperty", 0 }, - { "getProperty", 0 }, + { "setProperty", &LBCode::cmdSetProperty }, + { "getProperty", &LBCode::cmdGetProperty }, { "copyList", 0 }, { "invoke", 0 }, - { "exec", 0 }, - { "return", 0 }, + { "exec", &LBCode::cmdExec }, + { "return", &LBCode::cmdReturn }, { "sendSync", 0 }, { "moveViewOrigin", 0 }, { "addToGroup", 0 }, @@ -775,8 +881,8 @@ CodeCommandInfo generalCommandInfo[NUM_GENERAL_COMMANDS] = { { "setDisplay", &LBCode::cmdUnimplemented }, { "getDisplay", 0 }, { 0, 0 }, - { "lbxCreate", 0 }, - { "lbxFunc", 0 }, + { "lbxCreate", &LBCode::cmdLBXCreate }, + { "lbxFunc", &LBCode::cmdLBXFunc }, { "waitCursor", 0 }, { "debugBreak", 0 }, { "menuItemEnable", 0 }, @@ -886,6 +992,35 @@ void LBCode::cmdSubstring(const Common::Array<LBValue> ¶ms) { _stack.push(substring); } +void LBCode::cmdMax(const Common::Array<LBValue> ¶ms) { + if (params.size() != 2) + error("incorrect number of parameters (%d) to max", params.size()); + + // FIXME: fp + int a = params[0].toInt(); + int b = params[1].toInt(); + _stack.push(MAX(a, b)); +} + +void LBCode::cmdMin(const Common::Array<LBValue> ¶ms) { + if (params.size() != 2) + error("incorrect number of parameters (%d) to min", params.size()); + + // FIXME: fp + int a = params[0].toInt(); + int b = params[1].toInt(); + _stack.push(MIN(a, b)); +} + +void LBCode::cmdAbs(const Common::Array<LBValue> ¶ms) { + if (params.size() != 1) + error("incorrect number of parameters (%d) to abs", params.size()); + + // FIXME: fp + int a = params[0].toInt(); + _stack.push(ABS(a)); +} + void LBCode::cmdGetRect(const Common::Array<LBValue> ¶ms) { if (params.size() < 2) { _stack.push(getRectFromParams(params)); @@ -899,6 +1034,12 @@ void LBCode::cmdGetRect(const Common::Array<LBValue> ¶ms) { error("incorrect number of parameters (%d) to getRect", params.size()); } +void LBCode::cmdMakePoint(const Common::Array<LBValue> ¶ms) { + if (params.size() != 2) + error("incorrect number of parameters (%d) to makePoint", params.size()); + _stack.push(Common::Point(params[0].toInt(), params[1].toInt())); +} + void LBCode::cmdTopLeft(const Common::Array<LBValue> ¶ms) { if (params.size() > 1) error("too many parameters (%d) to topLeft", params.size()); @@ -915,6 +1056,14 @@ void LBCode::cmdBottomRight(const Common::Array<LBValue> ¶ms) { _stack.push(Common::Point(rect.bottom, rect.right)); } +void LBCode::cmdMousePos(const Common::Array<LBValue> ¶ms) { + if (params.size() != 0) + error("too many parameters (%d) to mousePos", params.size()); + + Common::Point pt = _vm->_system->getEventManager()->getMousePos(); + _stack.push(pt); +} + void LBCode::cmdTop(const Common::Array<LBValue> ¶ms) { if (params.size() > 1) error("too many parameters (%d) to top", params.size()); @@ -947,10 +1096,170 @@ void LBCode::cmdRight(const Common::Array<LBValue> ¶ms) { _stack.push(rect.right); } +void LBCode::cmdMove(const Common::Array<LBValue> ¶ms) { + if (params.size() != 1 && params.size() != 2) + error("incorrect number of parameters (%d) to move", params.size()); + + LBItem *target = _currSource; + Common::Point pt; + if (params.size() == 1) { + pt = params[0].toPoint(); + } else { + target = resolveItem(params[0]); + if (!target) + error("attempted move on invalid item (%s)", params[0].toString().c_str()); + pt = params[1].toPoint(); + } + + target->moveBy(pt); +} + void LBCode::cmdSetDragParams(const Common::Array<LBValue> ¶ms) { warning("ignoring setDragParams"); } +void LBCode::cmdNewList(const Common::Array<LBValue> ¶ms) { + if (params.size() != 0) + error("incorrect number of parameters (%d) to newList", params.size()); + + _stack.push(Common::SharedPtr<LBList>(new LBList)); +} + +void LBCode::cmdAdd(const Common::Array<LBValue> ¶ms) { + if (params.size() != 2) + error("incorrect number of parameters (%d) to add", params.size()); + + if (params[0].type != kLBValueList || !params[0].list) + error("invalid lbx object passed to add"); + + params[0].list->array.push_back(params[1]); +} + +void LBCode::cmdAddAt(const Common::Array<LBValue> ¶ms) { + if (params.size() != 3) + error("incorrect number of parameters (%d) to addAt", params.size()); + + if (params[0].type != kLBValueList || !params[0].list) + error("invalid lbx object passed to addAt"); + + if (params[1].type != kLBValueInteger || params[1].integer < 1) + error("invalid index passed to addAt"); + + if ((uint)params[1].integer > params[0].list->array.size()) + params[0].list->array.resize(params[1].integer); + params[0].list->array.insert_at(params[1].integer - 1, params[2]); +} + +void LBCode::cmdSetAt(const Common::Array<LBValue> ¶ms) { + if (params.size() != 3) + error("incorrect number of parameters (%d) to setAt", params.size()); + + if (params[0].type != kLBValueList || !params[0].list) + error("invalid lbx object passed to setAt"); + + if (params[1].type != kLBValueInteger || params[1].integer < 1) + error("invalid index passed to setAt"); + + if ((uint)params[1].integer > params[0].list->array.size()) + params[0].list->array.resize(params[1].integer); + params[0].list->array[params[1].integer - 1] = params[2]; +} + +void LBCode::cmdListLen(const Common::Array<LBValue> ¶ms) { + if (params.size() != 1) + error("incorrect number of parameters (%d) to listLen", params.size()); + + if (params[0].type != kLBValueList || !params[0].list) + error("invalid lbx object passed to lbxFunc"); + + _stack.push(params[0].list->array.size()); +} + +void LBCode::cmdDeleteAt(const Common::Array<LBValue> ¶ms) { + if (params.size() != 2) + error("incorrect number of parameters (%d) to deleteAt", params.size()); + + if (params[0].type != kLBValueList || !params[0].list) + error("invalid lbx object passed to deleteAt"); + + if (params[1].type != kLBValueInteger) + error("invalid index passed to deleteAt"); + if (params[1].integer < 1 || params[1].integer > (int)params[0].list->array.size()) + return; + params[0].list->array.remove_at(params[1].integer - 1); +} + +void LBCode::cmdSetProperty(const Common::Array<LBValue> ¶ms) { + if (params.size() < 2 || params.size() > 3) + error("incorrect number of parameters (%d) to setProperty", params.size()); + + Common::String name; + LBValue val; + LBItem *target = _currSource; + if (params.size() == 3) { + target = resolveItem(params[0]); + if (!target) + error("attempted setProperty on invalid item (%s)", params[0].toString().c_str()); + name = params[1].toString(); + val = params[2]; + } else { + name = params[0].toString(); + val = params[1]; + } + + target->_variables[name] = val; +} + +void LBCode::cmdGetProperty(const Common::Array<LBValue> ¶ms) { + if (params.size() < 1 || params.size() > 2) + error("incorrect number of parameters (%d) to getProperty", params.size()); + + Common::String name; + LBItem *target = _currSource; + if (params.size() == 2) { + target = resolveItem(params[0]); + if (!target) + error("attempted getProperty on invalid item (%s)", params[0].toString().c_str()); + name = params[1].toString(); + } else { + name = params[0].toString(); + } + + _stack.push(target->_variables[name]); +} + +void LBCode::cmdExec(const Common::Array<LBValue> ¶ms) { + if (params.size() != 1) + error("incorrect number of parameters (%d) to exec", params.size()); + if (params[0].type != kLBValueInteger || params[0].integer < 0) + error("invalid offset passed to exec"); + uint offset = (uint)params[0].integer; + + uint32 oldOffset = _currOffset; + byte oldToken = _currToken; + LBValue val = runCode(_currSource, offset); + _currOffset = oldOffset; + _currToken = oldToken; + + _stack.push(val); + _stack.push(val); +} + +void LBCode::cmdReturn(const Common::Array<LBValue> ¶ms) { + if (params.size() != 2) + error("incorrect number of parameters (%d) to return", params.size()); + + if (!_stack.size()) + error("empty stack on entry to return"); + + if (params[0] == _stack.top()) { + _stack.pop(); + _stack.push(params[1]); + _currToken = kTokenEndOfFile; + } else + _stack.push(_stack.top()); +} + void LBCode::cmdSetPlayParams(const Common::Array<LBValue> ¶ms) { if (params.size() > 8) error("too many parameters (%d) to setPlayParams", params.size()); @@ -994,6 +1303,32 @@ void LBCode::cmdSetHitTest(const Common::Array<LBValue> ¶ms) { warning("ignoring setHitTest"); } +void LBCode::cmdLBXCreate(const Common::Array<LBValue> ¶ms) { + if (params.size() != 1) + error("incorrect number of parameters (%d) to lbxCreate", params.size()); + + _stack.push(createLBXObject(_vm, params[0].toInt())); +} + +void LBCode::cmdLBXFunc(const Common::Array<LBValue> ¶ms) { + if (params.size() < 2) + error("incorrect number of parameters (%d) to lbxFunc", params.size()); + + if (params[0].type != kLBValueLBX || !params[0].lbx) + error("invalid lbx object passed to lbxFunc"); + + Common::SharedPtr<LBXObject> lbx = params[0].lbx; + uint callId = params[1].toInt(); + + Common::Array<LBValue> callParams; + for (uint i = 0; i < params.size() - 2; i++) + callParams.push_back(params[i + 2]); + + LBValue result; + if (lbx->call(callId, callParams, result)) + _stack.push(result); +} + void LBCode::cmdKey(const Common::Array<LBValue> ¶ms) { _stack.push(0); // FIXME warning("ignoring Key"); @@ -1001,7 +1336,7 @@ void LBCode::cmdKey(const Common::Array<LBValue> ¶ms) { #define NUM_ITEM_COMMANDS 34 CodeCommandInfo itemCommandInfo[NUM_ITEM_COMMANDS] = { - { "clone", 0 }, + { "clone", &LBCode::itemClone }, { "destroy", 0 }, { "dragBeginFrom", 0 }, { "dragEnd", 0 }, @@ -1022,14 +1357,14 @@ CodeCommandInfo itemCommandInfo[NUM_ITEM_COMMANDS] = { { "isMuted", 0 }, { "isPlaying", &LBCode::itemIsPlaying }, { "isVisible", 0 }, - { "isLoaded", 0 }, + { "isLoaded", &LBCode::itemIsLoaded }, { "isDragging", 0 }, { "load", 0 }, { "moveTo", &LBCode::itemMoveTo }, { "mute", 0 }, { "play", 0 }, { "seek", &LBCode::itemSeek }, - { "seekToFrame", 0 }, + { "seekToFrame", &LBCode::itemSeekToFrame }, { "setParent", &LBCode::itemSetParent }, { "setZOrder", 0 }, { "setText", 0 }, @@ -1054,14 +1389,50 @@ void LBCode::runItemCommand() { (this->*(info.func))(params); } +void LBCode::itemClone(const Common::Array<LBValue> ¶ms) { + // TODO: first param can be target? + if (params.size() != 2) + error("incorrect number of parameters (%d) to setParent", params.size()); + + uint id = params[0].toInt(); + const Common::String &name = params[1].toString(); + + _currSource->clone(id, name); +} + void LBCode::itemIsPlaying(const Common::Array<LBValue> ¶ms) { // TODO warning("ignoring isPlaying"); _stack.push(0); } +void LBCode::itemIsLoaded(const Common::Array<LBValue> ¶ms) { + if (params.size() != 1) + error("incorrect number of parameters (%d) to isLoaded", params.size()); + + LBItem *item = resolveItem(params[0]); + if (!item || !item->isLoaded()) + _stack.push(0); + else + _stack.push(1); +} + void LBCode::itemMoveTo(const Common::Array<LBValue> ¶ms) { - warning("ignoring moveTo"); + if (params.size() != 1 && params.size() != 2) + error("incorrect number of parameters (%d) to moveTo", params.size()); + + LBItem *target = _currSource; + Common::Point pt; + if (params.size() == 1) { + pt = params[0].toPoint(); + } else { + target = resolveItem(params[0]); + if (!target) + error("attempted moveTo on invalid item (%s)", params[0].toString().c_str()); + pt = params[1].toPoint(); + } + + target->moveTo(pt); } void LBCode::itemSeek(const Common::Array<LBValue> ¶ms) { @@ -1072,6 +1443,17 @@ void LBCode::itemSeek(const Common::Array<LBValue> ¶ms) { if (!item) error("attempted seek on invalid item (%s)", params[0].toString().c_str()); uint seekTo = params[1].toInt(); + item->seekToTime(seekTo); +} + +void LBCode::itemSeekToFrame(const Common::Array<LBValue> ¶ms) { + if (params.size() != 2) + error("incorrect number of parameters (%d) to seekToFrame", params.size()); + + LBItem *item = resolveItem(params[0]); + if (!item) + error("attempted seekToFrame on invalid item (%s)", params[0].toString().c_str()); + uint seekTo = params[1].toInt(); item->seek(seekTo); } @@ -1091,7 +1473,7 @@ void LBCode::runNotifyCommand() { debugN("goto"); Common::Array<LBValue> params = readParams(); // TODO: type-checking - NotifyEvent notifyEvent(kLBNotifyChangePage, 0); + NotifyEvent notifyEvent(kLBNotifyChangePage, 1); switch (params.size()) { case 4: notifyEvent.type = kLBNotifyChangeMode; // FIXME: type 8? @@ -1327,6 +1709,8 @@ uint LBCode::parseCode(const Common::String &source) { break; // open bracket case '(': + bool parameterless; + parameterless = false; if (wasFunction) { // function call parameters wasFunction = false; @@ -1342,6 +1726,7 @@ uint LBCode::parseCode(const Common::String &source) { continue; if (source[i] != ')') break; + parameterless = true; code[code.size() - 1] = 0; break; } @@ -1349,14 +1734,20 @@ uint LBCode::parseCode(const Common::String &source) { // brackets around expression counterPositions.push_back(0); } - code.push_back(kTokenOpenBracket); + if (!parameterless) + code.push_back(kTokenOpenBracket); break; // close bracket case ')': if (counterPositions.empty()) error("while parsing script '%s', encountered unmatched )", source.c_str()); + + // don't push a kTokenCloseBracket for a parameterless function call + uint counterPos2; + counterPos2 = counterPositions.back(); + if (!counterPos2 || code[counterPos2]) + code.push_back(kTokenCloseBracket); counterPositions.pop_back(); - code.push_back(kTokenCloseBracket); break; // comma (seperating function params) case ',': @@ -1375,7 +1766,7 @@ uint LBCode::parseCode(const Common::String &source) { { Common::String tempString; while (pos < source.size()) { - if (!isalpha(source[pos]) && !isdigit(source[pos])) + if (!Common::isAlpha(source[pos]) && !Common::isDigit(source[pos])) break; tempString += source[pos++]; } @@ -1386,7 +1777,7 @@ uint LBCode::parseCode(const Common::String &source) { } break; default: - if (isdigit(token)) { + if (Common::isDigit(token)) { const char *in = source.c_str() + pos - 1; // FIXME: handle floats? char *endptr; @@ -1401,15 +1792,21 @@ uint LBCode::parseCode(const Common::String &source) { WRITE_BE_UINT16(tmp, (int16)intValue); code.push_back(tmp[0]); code.push_back(tmp[1]); - } else if (isalpha(token)) { + } else if (Common::isAlpha(token)) { Common::String tempString; tempString += token; while (pos < source.size()) { - if (!isalpha(source[pos]) && !isdigit(source[pos])) + if (!Common::isAlpha(source[pos]) && !Common::isDigit(source[pos])) break; tempString += source[pos++]; } - wasFunction = parseCodeSymbol(tempString, pos, code); + if (tempString.equalsIgnoreCase("true")) { + code.push_back(kTokenTrue); + } else if (tempString.equalsIgnoreCase("false")) { + code.push_back(kTokenFalse); + } else { + wasFunction = parseCodeSymbol(tempString, pos, code); + } } else { error("while parsing script '%s', couldn't parse '%c'", source.c_str(), token); } diff --git a/engines/mohawk/livingbooks_code.h b/engines/mohawk/livingbooks_code.h index 79c9af94f7..47dd90f814 100644 --- a/engines/mohawk/livingbooks_code.h +++ b/engines/mohawk/livingbooks_code.h @@ -23,6 +23,7 @@ #ifndef MOHAWK_LIVINGBOOKS_CODE_H #define MOHAWK_LIVINGBOOKS_CODE_H +#include "common/ptr.h" #include "common/rect.h" #include "common/stack.h" #include "common/substream.h" @@ -31,6 +32,8 @@ namespace Mohawk { class MohawkEngine_LivingBooks; class LBItem; +class LBXObject; +struct LBList; enum LBValueType { kLBValueString, @@ -38,7 +41,9 @@ enum LBValueType { kLBValueReal, kLBValuePoint, kLBValueRect, - kLBValueItemPtr + kLBValueItemPtr, + kLBValueLBX, + kLBValueList }; struct LBValue { @@ -66,6 +71,14 @@ struct LBValue { type = kLBValueItemPtr; item = itm; } + LBValue(Common::SharedPtr<LBXObject> l) { + type = kLBValueLBX; + lbx = l; + } + LBValue(Common::SharedPtr<LBList> l) { + type = kLBValueList; + list = l; + } LBValue(const LBValue &val) { type = val.type; switch (type) { @@ -87,6 +100,12 @@ struct LBValue { case kLBValueItemPtr: item = val.item; break; + case kLBValueLBX: + lbx = val.lbx; + break; + case kLBValueList: + list = val.list; + break; } } @@ -97,6 +116,8 @@ struct LBValue { Common::Point point; Common::Rect rect; LBItem *item; + Common::SharedPtr<LBXObject> lbx; + Common::SharedPtr<LBList> list; bool operator==(const LBValue &x) const; bool operator!=(const LBValue &x) const; @@ -111,6 +132,10 @@ struct LBValue { Common::Rect toRect() const; }; +struct LBList { + Common::Array<LBValue> array; +}; + enum { kLBCodeLiteralInteger = 0x1 }; @@ -207,6 +232,7 @@ protected: void parseArithmetic2(); void parseMain(); + LBValue *getIndexedVar(Common::String varname, const Common::Array<LBValue> &index); LBItem *resolveItem(const LBValue &value); Common::Array<LBValue> readParams(); Common::Rect getRectFromParams(const Common::Array<LBValue> ¶ms); @@ -224,22 +250,43 @@ public: void cmdRandom(const Common::Array<LBValue> ¶ms); void cmdStringLen(const Common::Array<LBValue> ¶ms); void cmdSubstring(const Common::Array<LBValue> ¶ms); + void cmdMax(const Common::Array<LBValue> ¶ms); + void cmdMin(const Common::Array<LBValue> ¶ms); + void cmdAbs(const Common::Array<LBValue> ¶ms); void cmdGetRect(const Common::Array<LBValue> ¶ms); + void cmdMakePoint(const Common::Array<LBValue> ¶ms); void cmdTopLeft(const Common::Array<LBValue> ¶ms); void cmdBottomRight(const Common::Array<LBValue> ¶ms); + void cmdMousePos(const Common::Array<LBValue> ¶ms); void cmdTop(const Common::Array<LBValue> ¶ms); void cmdLeft(const Common::Array<LBValue> ¶ms); void cmdBottom(const Common::Array<LBValue> ¶ms); void cmdRight(const Common::Array<LBValue> ¶ms); + void cmdMove(const Common::Array<LBValue> ¶ms); void cmdSetDragParams(const Common::Array<LBValue> ¶ms); + void cmdNewList(const Common::Array<LBValue> ¶ms); + void cmdAdd(const Common::Array<LBValue> ¶ms); + void cmdAddAt(const Common::Array<LBValue> ¶ms); + void cmdSetAt(const Common::Array<LBValue> ¶ms); + void cmdListLen(const Common::Array<LBValue> ¶ms); + void cmdDeleteAt(const Common::Array<LBValue> ¶ms); + void cmdSetProperty(const Common::Array<LBValue> ¶ms); + void cmdGetProperty(const Common::Array<LBValue> ¶ms); + void cmdExec(const Common::Array<LBValue> ¶ms); + void cmdReturn(const Common::Array<LBValue> ¶ms); void cmdSetPlayParams(const Common::Array<LBValue> ¶ms); void cmdSetKeyEvent(const Common::Array<LBValue> ¶ms); void cmdSetHitTest(const Common::Array<LBValue> ¶ms); + void cmdLBXCreate(const Common::Array<LBValue> ¶ms); + void cmdLBXFunc(const Common::Array<LBValue> ¶ms); void cmdKey(const Common::Array<LBValue> ¶ms); + void itemClone(const Common::Array<LBValue> ¶ms); void itemIsPlaying(const Common::Array<LBValue> ¶ms); + void itemIsLoaded(const Common::Array<LBValue> ¶ms); void itemMoveTo(const Common::Array<LBValue> ¶ms); void itemSeek(const Common::Array<LBValue> ¶ms); + void itemSeekToFrame(const Common::Array<LBValue> ¶ms); void itemSetParent(const Common::Array<LBValue> ¶ms); }; diff --git a/engines/mohawk/livingbooks_graphics.cpp b/engines/mohawk/livingbooks_graphics.cpp new file mode 100644 index 0000000000..fb764fa15b --- /dev/null +++ b/engines/mohawk/livingbooks_graphics.cpp @@ -0,0 +1,102 @@ +/* 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. + * + */ + +#include "mohawk/resource.h" +#include "mohawk/livingbooks.h" +#include "mohawk/livingbooks_graphics.h" + +#include "common/substream.h" +#include "common/system.h" +#include "engines/util.h" +#include "graphics/palette.h" + +namespace Mohawk { + +LBGraphics::LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height) : GraphicsManager(), _vm(vm) { + _bmpDecoder = _vm->isPreMohawk() ? new LivingBooksBitmap_v1() : new MohawkBitmap(); + + initGraphics(width, height, true); +} + +LBGraphics::~LBGraphics() { + delete _bmpDecoder; +} + +MohawkSurface *LBGraphics::decodeImage(uint16 id) { + if (_vm->isPreMohawk()) + return _bmpDecoder->decodeImage(_vm->wrapStreamEndian(ID_BMAP, id)); + + return _bmpDecoder->decodeImage(_vm->getResource(ID_TBMP, id)); +} + +void LBGraphics::copyOffsetAnimImageToScreen(uint16 image, int left, int top) { + MohawkSurface *mhkSurface = findImage(image); + + left -= mhkSurface->getOffsetX(); + top -= mhkSurface->getOffsetY(); + + GraphicsManager::copyAnimImageToScreen(image, left, top); +} + +bool LBGraphics::imageIsTransparentAt(uint16 image, bool useOffsets, int x, int y) { + MohawkSurface *mhkSurface = findImage(image); + + if (useOffsets) { + x += mhkSurface->getOffsetX(); + y += mhkSurface->getOffsetY(); + } + + if (x < 0 || y < 0) + return true; + + Graphics::Surface *surface = mhkSurface->getSurface(); + if (x >= surface->w || y >= surface->h) + return true; + + return *(byte *)surface->getBasePtr(x, y) == 0; +} + +void LBGraphics::setPalette(uint16 id) { + // Old Living Books games use the old CTBL-style palette format while newer + // games use the better tPAL format which can store partial palettes. + if (_vm->isPreMohawk()) { + Common::SeekableSubReadStreamEndian *ctblStream = _vm->wrapStreamEndian(ID_CTBL, id); + uint16 colorCount = ctblStream->readUint16(); + byte *palette = new byte[colorCount * 3]; + + for (uint16 i = 0; i < colorCount; i++) { + palette[i * 3 + 0] = ctblStream->readByte(); + palette[i * 3 + 1] = ctblStream->readByte(); + palette[i * 3 + 2] = ctblStream->readByte(); + ctblStream->readByte(); + } + + delete ctblStream; + + _vm->_system->getPaletteManager()->setPalette(palette, 0, colorCount); + delete[] palette; + } else { + GraphicsManager::setPalette(id); + } +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/livingbooks_graphics.h b/engines/mohawk/livingbooks_graphics.h new file mode 100644 index 0000000000..3e2609750a --- /dev/null +++ b/engines/mohawk/livingbooks_graphics.h @@ -0,0 +1,52 @@ +/* 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. + * + */ + +#ifndef MOHAWK_LIVINGBOOKS_GRAPHICS_H +#define MOHAWK_LIVINGBOOKS_GRAPHICS_H + +#include "mohawk/graphics.h" + +namespace Mohawk { + +class MohawkEngine_LivingBooks; + +class LBGraphics : public GraphicsManager { +public: + LBGraphics(MohawkEngine_LivingBooks *vm, uint16 width, uint16 height); + ~LBGraphics(); + + void setPalette(uint16 id); + void copyOffsetAnimImageToScreen(uint16 image, int left = 0, int top = 0); + bool imageIsTransparentAt(uint16 image, bool useOffsets, int x, int y); + +protected: + MohawkSurface *decodeImage(uint16 id); + MohawkEngine *getVM() { return (MohawkEngine *)_vm; } + +private: + MohawkBitmap *_bmpDecoder; + MohawkEngine_LivingBooks *_vm; +}; + +} // End of namespace Mohawk + +#endif diff --git a/engines/mohawk/livingbooks_lbx.cpp b/engines/mohawk/livingbooks_lbx.cpp new file mode 100644 index 0000000000..9628e06294 --- /dev/null +++ b/engines/mohawk/livingbooks_lbx.cpp @@ -0,0 +1,141 @@ +/* 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. + * + */ + +#include "engines/mohawk/livingbooks.h" +#include "engines/mohawk/livingbooks_lbx.h" + +namespace Mohawk { + +class LBXDataFile : public LBXObject { +public: + LBXDataFile(MohawkEngine_LivingBooks *vm); + ~LBXDataFile(); + + bool call(uint callId, const Common::Array<LBValue> ¶ms, LBValue &result); + +protected: + Common::ConfigFile _dataFile; + Common::String _curSection; + + void open(const Common::String &filename); + bool sectionExists(const Common::String §ion); +}; + +LBXDataFile::LBXDataFile(MohawkEngine_LivingBooks *vm) : LBXObject(vm) { +} + +LBXDataFile::~LBXDataFile() { +} + +enum { + kLBXDataFileOpen = 1, + kLBXDataFileGetSectionList = 4, + kLBXDataFileSetCurSection = 5, + kLBXDataFileLoadCurSectionVars = 8, + kLBXDataFileDeleteCurSection = 10, + kLBXDataFileSectionExists = 14 +}; + +bool LBXDataFile::call(uint callId, const Common::Array<LBValue> ¶ms, LBValue &result) { + switch (callId) { + case kLBXDataFileOpen: + if (params.size() != 1) + error("incorrect number of parameters (%d) to LBXDataFile::open", params.size()); + + open(params[0].toString()); + return false; + + case kLBXDataFileGetSectionList: + { + Common::SharedPtr<LBList> list = Common::SharedPtr<LBList>(new LBList); + Common::ConfigFile::SectionList sections = _dataFile.getSections(); + for (Common::List<Common::ConfigFile::Section>::const_iterator i = sections.begin(); i != sections.end(); ++i) + list->array.push_back(LBValue(i->name)); + result = LBValue(list); + } + return true; + + case kLBXDataFileSetCurSection: + if (params.size() != 1) + error("incorrect number of parameters (%d) to LBXDataFile::setCurSection", params.size()); + + _curSection = params[0].toString(); + return false; + + case kLBXDataFileLoadCurSectionVars: + if (params.size() != 0) + error("incorrect number of parameters (%d) to LBXDataFile::loadCurSectionVars", params.size()); + + { + const Common::ConfigFile::SectionKeyList globals = _dataFile.getKeys(_curSection); + for (Common::ConfigFile::SectionKeyList::const_iterator i = globals.begin(); i != globals.end(); i++) { + Common::String command = Common::String::format("%s = %s", i->key.c_str(), i->value.c_str()); + LBCode tempCode(_vm, 0); + uint offset = tempCode.parseCode(command); + tempCode.runCode(NULL, offset); + } + } + return false; + + case kLBXDataFileDeleteCurSection: + if (params.size() != 0) + error("incorrect number of parameters (%d) to LBXDataFile::deleteCurSection", params.size()); + + _dataFile.removeSection(_curSection); + return false; + + case kLBXDataFileSectionExists: + if (params.size() != 1) + error("incorrect number of parameters (%d) to LBXDataFile::sectionExists", params.size()); + if (_dataFile.hasSection(params[0].toString())) + result = 1; + else + result = 0; + return true; + + default: + error("LBXDataFile call %d is unknown", callId); + } +} + +void LBXDataFile::open(const Common::String &filename) { + _dataFile.clear(); + + if (_dataFile.loadFromFile(filename)) + return; + + // FIXME: try savegames + + error("LBXDataFile::open: couldn't open '%s'", filename.c_str()); +} + +Common::SharedPtr<LBXObject> createLBXObject(MohawkEngine_LivingBooks *vm, uint16 type) { + switch (type) { + case 1001: + return Common::SharedPtr<LBXObject>(new LBXDataFile(vm)); + + default: + error("unknown LBX object type %d", type); + } +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/livingbooks_lbx.h b/engines/mohawk/livingbooks_lbx.h new file mode 100644 index 0000000000..3cca0a8e82 --- /dev/null +++ b/engines/mohawk/livingbooks_lbx.h @@ -0,0 +1,47 @@ +/* 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. + * + */ + +#ifndef MOHAWK_LIVINGBOOKS_LBX_H +#define MOHAWK_LIVINGBOOKS_LBX_H + +#include "engines/mohawk/livingbooks_code.h" + +#include "common/ptr.h" + +namespace Mohawk { + +class LBXObject { +public: + LBXObject(MohawkEngine_LivingBooks *vm) : _vm(vm) { } + virtual ~LBXObject() { } + + virtual bool call(uint callId, const Common::Array<LBValue> ¶ms, LBValue &result) = 0; + +protected: + MohawkEngine_LivingBooks *_vm; +}; + +Common::SharedPtr<LBXObject> createLBXObject(MohawkEngine_LivingBooks *vm, uint16 type); + +} // End of namespace Mohawk + +#endif diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk index 30f1d40fdb..83e541e3e4 100644 --- a/engines/mohawk/module.mk +++ b/engines/mohawk/module.mk @@ -10,6 +10,8 @@ MODULE_OBJS = \ installer_archive.o \ livingbooks.o \ livingbooks_code.o \ + livingbooks_graphics.o \ + livingbooks_lbx.o \ mohawk.o \ resource.o \ sound.o \ @@ -21,6 +23,7 @@ MODULE_OBJS += \ cstime.o \ cstime_cases.o \ cstime_game.o \ + cstime_graphics.o \ cstime_ui.o \ cstime_view.o endif @@ -29,6 +32,7 @@ ifdef ENABLE_MYST MODULE_OBJS += \ myst.o \ myst_areas.o \ + myst_graphics.o \ myst_scripts.o \ myst_state.o \ resource_cache.o \ @@ -50,6 +54,7 @@ ifdef ENABLE_RIVEN MODULE_OBJS += \ riven.o \ riven_external.o \ + riven_graphics.o \ riven_saveload.o \ riven_scripts.o \ riven_vars.o diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index eeb4594f3c..c22b30ad4d 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -27,9 +27,9 @@ #include "common/textconsole.h" #include "mohawk/cursors.h" -#include "mohawk/graphics.h" #include "mohawk/myst.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_scripts.h" #include "mohawk/myst_state.h" #include "mohawk/dialogs.h" diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h index 02f0a46e3f..30770f7ec9 100644 --- a/engines/mohawk/myst.h +++ b/engines/mohawk/myst.h @@ -173,7 +173,7 @@ public: MystGraphics *_gfx; MystGameState *_gameState; MystScriptParser *_scriptParser; - Common::Array<MystResource*> _resources; + Common::Array<MystResource *> _resources; MystResource *_dragResource; Common::RandomSource *_rnd; diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp index 294fcea2f1..fe33ceaa9b 100644 --- a/engines/mohawk/myst_areas.cpp +++ b/engines/mohawk/myst_areas.cpp @@ -20,8 +20,8 @@ * */ -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_scripts.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/myst_areas.h b/engines/mohawk/myst_areas.h index 136356ea4f..62af5ec4cf 100644 --- a/engines/mohawk/myst_areas.h +++ b/engines/mohawk/myst_areas.h @@ -20,11 +20,13 @@ * */ +#ifndef MYST_AREAS_H +#define MYST_AREAS_H + #include "mohawk/myst.h" #include "mohawk/video.h" -#ifndef MYST_AREAS_H -#define MYST_AREAS_H +#include "common/rect.h" namespace Mohawk { @@ -137,7 +139,7 @@ public: protected: uint16 _var7; uint16 _numSubResources; - Common::Array<MystResource*> _subResources; + Common::Array<MystResource *> _subResources; }; class MystResourceType8 : public MystResourceType7 { diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp new file mode 100644 index 0000000000..151390580f --- /dev/null +++ b/engines/mohawk/myst_graphics.cpp @@ -0,0 +1,493 @@ +/* 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. + * + */ + +#include "mohawk/myst.h" +#include "mohawk/myst_graphics.h" +#include "mohawk/resource.h" + +#include "common/substream.h" +#include "common/system.h" +#include "common/textconsole.h" +#include "engines/util.h" +#include "graphics/jpeg.h" +#include "graphics/pict.h" + +namespace Mohawk { + +MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { + _bmpDecoder = new MystBitmap(); + + _viewport = Common::Rect(544, 332); + + // The original version of Myst could run in 8bpp color too. + // However, it dithered videos to 8bpp and they looked considerably + // worse (than they already did :P). So we're not even going to + // support 8bpp mode in Myst (Myst ME required >8bpp anyway). + initGraphics(_viewport.width(), _viewport.height(), true, NULL); // What an odd screen size! + + _pixelFormat = _vm->_system->getScreenFormat(); + + if (_pixelFormat.bytesPerPixel == 1) + error("Myst requires greater than 256 colors to run"); + + if (_vm->getFeatures() & GF_ME) { + _jpegDecoder = new Graphics::JPEG(); + _pictDecoder = new Graphics::PictDecoder(_pixelFormat); + } else { + _jpegDecoder = NULL; + _pictDecoder = NULL; + } + + _pictureFile.entries = NULL; + + // Initialize our buffer + _backBuffer = new Graphics::Surface(); + _backBuffer->create(_vm->_system->getWidth(), _vm->_system->getHeight(), _pixelFormat); + + _nextAllowedDrawTime = _vm->_system->getMillis(); + _enableDrawingTimeSimulation = 0; +} + +MystGraphics::~MystGraphics() { + delete _bmpDecoder; + delete _jpegDecoder; + delete _pictDecoder; + delete[] _pictureFile.entries; + + _backBuffer->free(); + delete _backBuffer; +} + +static const char *s_picFileNames[] = { + "CHpics", + "", + "", + "DUpics", + "INpics", + "", + "MEpics", + "MYpics", + "SEpics", + "", + "", + "STpics" +}; + +void MystGraphics::loadExternalPictureFile(uint16 stack) { + if (_vm->getPlatform() != Common::kPlatformMacintosh) + return; + + if (_pictureFile.picFile.isOpen()) + _pictureFile.picFile.close(); + delete[] _pictureFile.entries; + + if (!scumm_stricmp(s_picFileNames[stack], "")) + return; + + if (!_pictureFile.picFile.open(s_picFileNames[stack])) + error ("Could not open external picture file \'%s\'", s_picFileNames[stack]); + + _pictureFile.pictureCount = _pictureFile.picFile.readUint32BE(); + _pictureFile.entries = new PictureFile::PictureEntry[_pictureFile.pictureCount]; + + for (uint32 i = 0; i < _pictureFile.pictureCount; i++) { + _pictureFile.entries[i].offset = _pictureFile.picFile.readUint32BE(); + _pictureFile.entries[i].size = _pictureFile.picFile.readUint32BE(); + _pictureFile.entries[i].id = _pictureFile.picFile.readUint16BE(); + _pictureFile.entries[i].type = _pictureFile.picFile.readUint16BE(); + _pictureFile.entries[i].width = _pictureFile.picFile.readUint16BE(); + _pictureFile.entries[i].height = _pictureFile.picFile.readUint16BE(); + } +} + +MohawkSurface *MystGraphics::decodeImage(uint16 id) { + MohawkSurface *mhkSurface = 0; + + // Myst ME uses JPEG/PICT images instead of compressed Windows Bitmaps for room images, + // though there are a few weird ones that use that format. For further nonsense with images, + // the Macintosh version stores images in external "picture files." We check them before + // going to check for a PICT resource. + if (_vm->getFeatures() & GF_ME && _vm->getPlatform() == Common::kPlatformMacintosh && _pictureFile.picFile.isOpen()) { + for (uint32 i = 0; i < _pictureFile.pictureCount; i++) + if (_pictureFile.entries[i].id == id) { + if (_pictureFile.entries[i].type == 0) { + Common::SeekableReadStream *stream = new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size); + + if (!_jpegDecoder->read(stream)) + error("Could not decode Myst ME Mac JPEG"); + + mhkSurface = new MohawkSurface(_jpegDecoder->getSurface(_pixelFormat)); + delete stream; + } else if (_pictureFile.entries[i].type == 1) { + mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size))); + } else + error ("Unknown Picture File type %d", _pictureFile.entries[i].type); + break; + } + } + + // We're not using the external Mac files, so it's time to delve into the main Mohawk + // archives. However, we still don't know if it's a PICT or WDIB resource. If it's Myst + // ME it's most likely a PICT, and if it's original it's definitely a WDIB. However, + // Myst ME throws us another curve ball in that PICT resources can contain WDIB's instead + // of PICT's. + if (!mhkSurface) { + bool isPict = false; + Common::SeekableReadStream *dataStream = NULL; + + if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) { + // The PICT resource exists. However, it could still contain a MystBitmap + // instead of a PICT image... + dataStream = _vm->getResource(ID_PICT, id); + } else // No PICT, so the WDIB must exist. Let's go grab it. + dataStream = _vm->getResource(ID_WDIB, id); + + if (_vm->getFeatures() & GF_ME) { + // Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap + // would be compressed, there's no way to detect for the BM without a hack. + // So, we search for the PICT version opcode for detection. + dataStream->seek(512 + 10); // 512 byte pict header + isPict = (dataStream->readUint32BE() == 0x001102FF); + dataStream->seek(0); + } + + if (isPict) + mhkSurface = new MohawkSurface(_pictDecoder->decodeImage(dataStream)); + else { + mhkSurface = _bmpDecoder->decodeImage(dataStream); + mhkSurface->convertToTrueColor(); + } + } + + assert(mhkSurface); + return mhkSurface; +} + +void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest) { + Graphics::Surface *surface = findImage(image)->getSurface(); + + // Make sure the image is bottom aligned in the dest rect + dest.top = dest.bottom - MIN<int>(surface->h, dest.height()); + + // Convert from bitmap coordinates to surface coordinates + uint16 top = surface->h - (src.top + MIN<int>(surface->h, dest.height())); + + // Do not draw the top pixels if the image is too tall + if (dest.height() > _viewport.height()) + top += dest.height() - _viewport.height(); + + // Clip the destination rect to the screen + if (dest.right > _vm->_system->getWidth() || dest.bottom > _vm->_system->getHeight()) + dest.debugPrint(4, "Clipping destination rect to the screen"); + dest.right = CLIP<int>(dest.right, 0, _vm->_system->getWidth()); + dest.bottom = CLIP<int>(dest.bottom, 0, _vm->_system->getHeight()); + + uint16 width = MIN<int>(surface->w, dest.width()); + uint16 height = MIN<int>(surface->h, dest.height()); + + // Clamp Width and Height to within src surface dimensions + if (src.left + width > surface->w) + width = surface->w - src.left; + if (src.top + height > surface->h) + height = surface->h - src.top; + + debug(3, "MystGraphics::copyImageSectionToScreen()"); + debug(3, "\tImage: %d", image); + debug(3, "\tsrc.left: %d", src.left); + debug(3, "\tsrc.top: %d", src.top); + debug(3, "\tdest.left: %d", dest.left); + debug(3, "\tdest.top: %d", dest.top); + debug(3, "\twidth: %d", width); + debug(3, "\theight: %d", height); + + simulatePreviousDrawDelay(dest); + + _vm->_system->copyRectToScreen((byte *)surface->getBasePtr(src.left, top), surface->pitch, dest.left, dest.top, width, height); +} + +void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest) { + Graphics::Surface *surface = findImage(image)->getSurface(); + + // Make sure the image is bottom aligned in the dest rect + dest.top = dest.bottom - MIN<int>(surface->h, dest.height()); + + // Convert from bitmap coordinates to surface coordinates + uint16 top = surface->h - (src.top + MIN<int>(surface->h, dest.height())); + + // Do not draw the top pixels if the image is too tall + if (dest.height() > _viewport.height()) { + top += dest.height() - _viewport.height(); + } + + // Clip the destination rect to the screen + if (dest.right > _vm->_system->getWidth() || dest.bottom > _vm->_system->getHeight()) + dest.debugPrint(4, "Clipping destination rect to the screen"); + dest.right = CLIP<int>(dest.right, 0, _vm->_system->getWidth()); + dest.bottom = CLIP<int>(dest.bottom, 0, _vm->_system->getHeight()); + + uint16 width = MIN<int>(surface->w, dest.width()); + uint16 height = MIN<int>(surface->h, dest.height()); + + // Clamp Width and Height to within src surface dimensions + if (src.left + width > surface->w) + width = surface->w - src.left; + if (src.top + height > surface->h) + height = surface->h - src.top; + + debug(3, "MystGraphics::copyImageSectionToBackBuffer()"); + debug(3, "\tImage: %d", image); + debug(3, "\tsrc.left: %d", src.left); + debug(3, "\tsrc.top: %d", src.top); + debug(3, "\tdest.left: %d", dest.left); + debug(3, "\tdest.top: %d", dest.top); + debug(3, "\twidth: %d", width); + debug(3, "\theight: %d", height); + + for (uint16 i = 0; i < height; i++) + memcpy(_backBuffer->getBasePtr(dest.left, i + dest.top), surface->getBasePtr(src.left, top + i), width * surface->format.bytesPerPixel); +} + +void MystGraphics::copyImageToScreen(uint16 image, Common::Rect dest) { + copyImageSectionToScreen(image, Common::Rect(544, 333), dest); +} + +void MystGraphics::copyImageToBackBuffer(uint16 image, Common::Rect dest) { + copyImageSectionToBackBuffer(image, Common::Rect(544, 333), dest); +} + +void MystGraphics::copyBackBufferToScreen(Common::Rect r) { + r.clip(_viewport); + + simulatePreviousDrawDelay(r); + + _vm->_system->copyRectToScreen((byte *)_backBuffer->getBasePtr(r.left, r.top), _backBuffer->pitch, r.left, r.top, r.width(), r.height()); +} + +void MystGraphics::runTransition(uint16 type, Common::Rect rect, uint16 steps, uint16 delay) { + + // Do not artificially delay during transitions + int oldEnableDrawingTimeSimulation = _enableDrawingTimeSimulation; + _enableDrawingTimeSimulation = 0; + + switch (type) { + case 0: { + debugC(kDebugScript, "Left to Right"); + + uint16 step = (rect.right - rect.left) / steps; + Common::Rect area = rect; + for (uint i = 0; i < steps; i++) { + area.left = rect.left + step * i; + area.right = area.left + step; + + _vm->_system->delayMillis(delay); + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + if (area.right < rect.right) { + area.left = area.right; + area.right = rect.right; + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + } + break; + case 1: { + debugC(kDebugScript, "Right to Left"); + + uint16 step = (rect.right - rect.left) / steps; + Common::Rect area = rect; + for (uint i = 0; i < steps; i++) { + area.right = rect.right - step * i; + area.left = area.right - step; + + _vm->_system->delayMillis(delay); + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + if (area.left > rect.left) { + area.right = area.left; + area.left = rect.left; + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + } + break; + case 5: { + debugC(kDebugScript, "Top to Bottom"); + + uint16 step = (rect.bottom - rect.top) / steps; + Common::Rect area = rect; + for (uint i = 0; i < steps; i++) { + area.top = rect.top + step * i; + area.bottom = area.top + step; + + _vm->_system->delayMillis(delay); + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + if (area.bottom < rect.bottom) { + area.top = area.bottom; + area.bottom = rect.bottom; + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + } + break; + case 6: { + debugC(kDebugScript, "Bottom to Top"); + + uint16 step = (rect.bottom - rect.top) / steps; + Common::Rect area = rect; + for (uint i = 0; i < steps; i++) { + area.bottom = rect.bottom - step * i; + area.top = area.bottom - step; + + _vm->_system->delayMillis(delay); + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + if (area.top > rect.top) { + area.bottom = area.top; + area.top = rect.top; + + copyBackBufferToScreen(area); + _vm->_system->updateScreen(); + } + } + break; + default: + warning("Unknown Update Direction"); + + //TODO: Replace minimal implementation + copyBackBufferToScreen(rect); + _vm->_system->updateScreen(); + break; + } + + _enableDrawingTimeSimulation = oldEnableDrawingTimeSimulation; +} + +void MystGraphics::drawRect(Common::Rect rect, RectState state) { + rect.clip(_viewport); + + // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active. + if (!rect.isValidRect() || rect.width() == 0 || rect.height() == 0) + return; + + Graphics::Surface *screen = _vm->_system->lockScreen(); + + if (state == kRectEnabled) + screen->frameRect(rect, _pixelFormat.RGBToColor(0, 255, 0)); + else if (state == kRectUnreachable) + screen->frameRect(rect, _pixelFormat.RGBToColor(0, 0, 255)); + else + screen->frameRect(rect, _pixelFormat.RGBToColor(255, 0, 0)); + + _vm->_system->unlockScreen(); +} + +void MystGraphics::drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color) { + _backBuffer->drawLine(p1.x, p1.y, p2.x, p2.y, color); +} + +void MystGraphics::enableDrawingTimeSimulation(bool enable) { + if (enable) + _enableDrawingTimeSimulation++; + else + _enableDrawingTimeSimulation--; + + if (_enableDrawingTimeSimulation < 0) + _enableDrawingTimeSimulation = 0; +} + +void MystGraphics::simulatePreviousDrawDelay(const Common::Rect &dest) { + uint32 time = 0; + + if (_enableDrawingTimeSimulation) { + time = _vm->_system->getMillis(); + + // Do not draw anything new too quickly after the previous draw call + // so that images stay at least a little while on screen + // This is enabled only for scripted draw calls + if (time < _nextAllowedDrawTime) + _vm->_system->delayMillis(_nextAllowedDrawTime - time); + } + + // Next draw call allowed at DELAY + AERA * COEFF milliseconds from now + time = _vm->_system->getMillis(); + _nextAllowedDrawTime = time + _constantDrawDelay + dest.height() * dest.width() / _proportionalDrawDelay; +} + +void MystGraphics::copyBackBufferToScreenWithSaturation(int16 saturation) { + Graphics::Surface *screen = _vm->_system->lockScreen(); + + for (uint16 y = 0; y < _viewport.height(); y++) + for (uint16 x = 0; x < _viewport.width(); x++) { + uint32 color; + uint8 r, g, b; + + if (_pixelFormat.bytesPerPixel == 2) + color = *(const uint16 *)_backBuffer->getBasePtr(x, y); + else + color = *(const uint32 *)_backBuffer->getBasePtr(x, y); + + _pixelFormat.colorToRGB(color, r, g, b); + + r = CLIP<int16>((int16)r - saturation, 0, 255); + g = CLIP<int16>((int16)g - saturation, 0, 255); + b = CLIP<int16>((int16)b - saturation, 0, 255); + + color = _pixelFormat.RGBToColor(r, g, b); + + if (_pixelFormat.bytesPerPixel == 2) { + uint16 *dst = (uint16 *)screen->getBasePtr(x, y); + *dst = color; + } else { + uint32 *dst = (uint32 *)screen->getBasePtr(x, y); + *dst = color; + } + } + + _vm->_system->unlockScreen(); + _vm->_system->updateScreen(); +} + +void MystGraphics::fadeToBlack() { + for (int16 i = 0; i < 256; i += 32) { + copyBackBufferToScreenWithSaturation(i); + } +} + +void MystGraphics::fadeFromBlack() { + for (int16 i = 256; i >= 0; i -= 32) { + copyBackBufferToScreenWithSaturation(i); + } +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h new file mode 100644 index 0000000000..e2b02db5fc --- /dev/null +++ b/engines/mohawk/myst_graphics.h @@ -0,0 +1,102 @@ +/* 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. + * + */ + +#ifndef MOHAWK_MYST_GRAPHICS_H +#define MOHAWK_MYST_GRAPHICS_H + +#include "mohawk/graphics.h" + +#include "common/file.h" + +namespace Graphics { +class JPEG; +class PictDecoder; +} + +namespace Mohawk { + +class MystBitmap; +class MohawkEngine_Myst; + +enum RectState { + kRectEnabled, + kRectDisabled, + kRectUnreachable +}; + +class MystGraphics : public GraphicsManager { +public: + MystGraphics(MohawkEngine_Myst*); + ~MystGraphics(); + + void loadExternalPictureFile(uint16 stack); + void copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest); + void copyImageSectionToBackBuffer(uint16 image, Common::Rect src, Common::Rect dest); + void copyImageToScreen(uint16 image, Common::Rect dest); + void copyImageToBackBuffer(uint16 image, Common::Rect dest); + void copyBackBufferToScreen(Common::Rect r); + void runTransition(uint16 type, Common::Rect rect, uint16 steps, uint16 delay); + void drawRect(Common::Rect rect, RectState state); + void drawLine(const Common::Point &p1, const Common::Point &p2, uint32 color); + void enableDrawingTimeSimulation(bool enable); + void fadeToBlack(); + void fadeFromBlack(); + +protected: + MohawkSurface *decodeImage(uint16 id); + MohawkEngine *getVM() { return (MohawkEngine *)_vm; } + void simulatePreviousDrawDelay(const Common::Rect &dest); + void copyBackBufferToScreenWithSaturation(int16 saturation); + +private: + MohawkEngine_Myst *_vm; + MystBitmap *_bmpDecoder; + Graphics::PictDecoder *_pictDecoder; + Graphics::JPEG *_jpegDecoder; + + struct PictureFile { + uint32 pictureCount; + struct PictureEntry { + uint32 offset; + uint32 size; + uint16 id; + uint16 type; + uint16 width; + uint16 height; + } *entries; + + Common::File picFile; + } _pictureFile; + + Graphics::Surface *_backBuffer; + Graphics::PixelFormat _pixelFormat; + Common::Rect _viewport; + + int _enableDrawingTimeSimulation; + uint32 _nextAllowedDrawTime; + static const uint _constantDrawDelay = 10; // ms + static const uint _proportionalDrawDelay = 500; // pixels per ms +}; + +} // End of namespace Mohawk + +#endif diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp index ca8e985491..b9353312c7 100644 --- a/engines/mohawk/myst_scripts.cpp +++ b/engines/mohawk/myst_scripts.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_scripts.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/myst_scripts.h b/engines/mohawk/myst_scripts.h index 18f5b27a6d..ccb76e0dc8 100644 --- a/engines/mohawk/myst_scripts.h +++ b/engines/mohawk/myst_scripts.h @@ -143,7 +143,7 @@ protected: const char *desc; }; - Common::Array<MystOpcode*> _opcodes; + Common::Array<MystOpcode *> _opcodes; MystResource *_invokingResource; diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp index 9ca47cc92a..069281f5dc 100644 --- a/engines/mohawk/myst_stacks/channelwood.cpp +++ b/engines/mohawk/myst_stacks/channelwood.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_state.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/myst_stacks/credits.cpp b/engines/mohawk/myst_stacks/credits.cpp index ad593e3542..192e55d5e3 100644 --- a/engines/mohawk/myst_stacks/credits.cpp +++ b/engines/mohawk/myst_stacks/credits.cpp @@ -21,8 +21,8 @@ */ #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/sound.h" #include "mohawk/video.h" #include "mohawk/myst_stacks/credits.h" diff --git a/engines/mohawk/myst_stacks/demo.cpp b/engines/mohawk/myst_stacks/demo.cpp index fbad7dc384..29a12571fd 100644 --- a/engines/mohawk/myst_stacks/demo.cpp +++ b/engines/mohawk/myst_stacks/demo.cpp @@ -21,8 +21,8 @@ */ #include "mohawk/cursors.h" -#include "mohawk/graphics.h" #include "mohawk/myst.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_stacks/demo.h" #include "common/system.h" diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp index 7d3179fa24..0af386f51f 100644 --- a/engines/mohawk/myst_stacks/intro.cpp +++ b/engines/mohawk/myst_stacks/intro.cpp @@ -21,8 +21,8 @@ */ #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_state.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp index 12d9dc7e2f..79de03308c 100644 --- a/engines/mohawk/myst_stacks/mechanical.cpp +++ b/engines/mohawk/myst_stacks/mechanical.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_state.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp index b67b333a85..c1ddc74c82 100644 --- a/engines/mohawk/myst_stacks/myst.cpp +++ b/engines/mohawk/myst_stacks/myst.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_state.h" #include "mohawk/sound.h" #include "mohawk/video.h" @@ -2138,7 +2138,7 @@ void Myst::rocketSliderMove() { } uint16 Myst::rocketSliderGetSound(uint16 pos) { - return (uint16)(9530 + (pos - 216) * 35.0 * 0.01639344262295082); + return (uint16)(9530 + (pos - 216) * 35.0 / 61.0); } void Myst::rocketCheckSolution() { @@ -2978,15 +2978,17 @@ void Myst::clockReset() { } void Myst::clockResetWeight() { - // Set video bounds, weight going up + _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack) , 124, 0); + if (!(_vm->getFeatures() & GF_ME)) { - _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack) , 124, 0); + // Set video bounds, weight going up _vm->_video->setVideoBounds(_clockWeightVideo, Audio::Timestamp(0, 2214 * 2 - _clockWeightPosition, 600), Audio::Timestamp(0, 2214 * 2, 600)); } else { - //FIXME: Needs QT backwards playing + //FIXME: Needs QT backwards playing, for now just display the weight up warning("Weight going back up not implemented"); + _vm->_video->drawVideoFrame(_clockWeightVideo, Audio::Timestamp(0, 0, 600)); } // Reset position diff --git a/engines/mohawk/myst_stacks/preview.cpp b/engines/mohawk/myst_stacks/preview.cpp index 31e22bb8c5..0b8dcf897a 100644 --- a/engines/mohawk/myst_stacks/preview.cpp +++ b/engines/mohawk/myst_stacks/preview.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/sound.h" #include "mohawk/video.h" #include "mohawk/myst_stacks/preview.h" diff --git a/engines/mohawk/myst_stacks/slides.cpp b/engines/mohawk/myst_stacks/slides.cpp index 794793e49c..c0bb400db1 100644 --- a/engines/mohawk/myst_stacks/slides.cpp +++ b/engines/mohawk/myst_stacks/slides.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/sound.h" #include "mohawk/video.h" #include "mohawk/myst_stacks/slides.h" diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp index e0c374a926..ef228e62f3 100644 --- a/engines/mohawk/myst_stacks/stoneship.cpp +++ b/engines/mohawk/myst_stacks/stoneship.cpp @@ -22,8 +22,8 @@ #include "mohawk/cursors.h" #include "mohawk/myst.h" -#include "mohawk/graphics.h" #include "mohawk/myst_areas.h" +#include "mohawk/myst_graphics.h" #include "mohawk/myst_state.h" #include "mohawk/sound.h" #include "mohawk/video.h" @@ -623,7 +623,7 @@ void Stoneship::o_hologramSelectionMove(uint16 op, uint16 var, uint16 argc, uint uint16 selectionPos = position * 1500 / 243; VideoHandle handleMovie = _hologramSelection->playMovie(); - _vm->_video->setVideoBounds(handleMovie, Audio::Timestamp(0, selectionPos, 600), Audio::Timestamp(0, selectionPos, 600)); + _vm->_video->drawVideoFrame(handleMovie, Audio::Timestamp(0, selectionPos, 600)); _hologramDisplayPos = position * 1450 / 243 + 350; @@ -631,7 +631,7 @@ void Stoneship::o_hologramSelectionMove(uint16 op, uint16 var, uint16 argc, uint if (_hologramTurnedOn) { _hologramDisplay->setBlocking(false); VideoHandle displayMovie = _hologramDisplay->playMovie(); - _vm->_video->setVideoBounds(displayMovie, Audio::Timestamp(0, _hologramDisplayPos, 600), Audio::Timestamp(0, _hologramDisplayPos, 600)); + _vm->_video->drawVideoFrame(displayMovie, Audio::Timestamp(0, _hologramDisplayPos, 600)); } } } @@ -655,7 +655,7 @@ void Stoneship::o_compassButton(uint16 op, uint16 var, uint16 argc, uint16 *argv _state.generatorPowerAvailable = 2; _state.lightState = 0; _state.generatorDepletionTime = 0; - _state.generatorDepletionTime = 0; + _state.generatorDuration = 0; _batteryDepleting = false; } diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 3e2fa4f979..38b38d2c56 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -27,11 +27,11 @@ #include "common/system.h" #include "mohawk/cursors.h" -#include "mohawk/graphics.h" #include "mohawk/installer_archive.h" #include "mohawk/resource.h" #include "mohawk/riven.h" #include "mohawk/riven_external.h" +#include "mohawk/riven_graphics.h" #include "mohawk/riven_saveload.h" #include "mohawk/dialogs.h" #include "mohawk/sound.h" diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 9e1365f8da..8dfc74ebf0 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -21,9 +21,9 @@ */ #include "mohawk/cursors.h" -#include "mohawk/graphics.h" #include "mohawk/riven.h" #include "mohawk/riven_external.h" +#include "mohawk/riven_graphics.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/riven_external.h b/engines/mohawk/riven_external.h index 5f5d0cb0b2..9f076325a2 100644 --- a/engines/mohawk/riven_external.h +++ b/engines/mohawk/riven_external.h @@ -53,7 +53,7 @@ private: ExternalCmd proc; }; - Common::Array<RivenExternalCmd*> _externalCommands; + Common::Array<RivenExternalCmd *> _externalCommands; void setupCommands(); // Supplementary Functions diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp new file mode 100644 index 0000000000..9415e51412 --- /dev/null +++ b/engines/mohawk/riven_graphics.cpp @@ -0,0 +1,445 @@ +/* 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. + * + */ + +#include "mohawk/resource.h" +#include "mohawk/riven.h" +#include "mohawk/riven_graphics.h" + +#include "common/system.h" +#include "engines/util.h" + +namespace Mohawk { + +RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm) { + _bitmapDecoder = new MohawkBitmap(); + + // Give me the best you've got! + initGraphics(608, 436, true, NULL); + _pixelFormat = _vm->_system->getScreenFormat(); + + if (_pixelFormat.bytesPerPixel == 1) + error("Riven requires greater than 256 colors to run"); + + // The actual game graphics only take up the first 392 rows. The inventory + // occupies the rest of the screen and we don't use the buffer to hold that. + _mainScreen = new Graphics::Surface(); + _mainScreen->create(608, 392, _pixelFormat); + + _updatesEnabled = true; + _scheduledTransition = -1; // no transition + _dirtyScreen = false; + _inventoryDrawn = false; + + _creditsImage = 302; + _creditsPos = 0; +} + +RivenGraphics::~RivenGraphics() { + _mainScreen->free(); + delete _mainScreen; + delete _bitmapDecoder; +} + +MohawkSurface *RivenGraphics::decodeImage(uint16 id) { + MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getResource(ID_TBMP, id)); + surface->convertToTrueColor(); + return surface; +} + +void RivenGraphics::copyImageToScreen(uint16 image, uint32 left, uint32 top, uint32 right, uint32 bottom) { + Graphics::Surface *surface = findImage(image)->getSurface(); + + // Clip the width to fit on the screen. Fixes some images. + if (left + surface->w > 608) + surface->w = 608 - left; + + for (uint16 i = 0; i < surface->h; i++) + memcpy(_mainScreen->getBasePtr(left, i + top), surface->getBasePtr(0, i), surface->w * surface->format.bytesPerPixel); + + _dirtyScreen = true; +} + +void RivenGraphics::drawPLST(uint16 x) { + Common::SeekableReadStream* plst = _vm->getResource(ID_PLST, _vm->getCurCard()); + uint16 recordCount = plst->readUint16BE(); + + for (uint16 i = 0; i < recordCount; i++) { + uint16 index = plst->readUint16BE(); + uint16 id = plst->readUint16BE(); + uint16 left = plst->readUint16BE(); + uint16 top = plst->readUint16BE(); + uint16 right = plst->readUint16BE(); + uint16 bottom = plst->readUint16BE(); + + // We are also checking here to make sure we haven't drawn the image yet on screen. + // This fixes problems with drawing PLST 1 twice and some other images twice. PLST + // 1 is sometimes not called by the scripts, so some cards don't appear if we don't + // draw PLST 1 each time. This "hack" is here to catch any PLST attempting to draw + // twice. There should never be a problem with doing it this way. + if (index == x && !(Common::find(_activatedPLSTs.begin(), _activatedPLSTs.end(), x) != _activatedPLSTs.end())) { + debug(0, "Drawing image %d", id); + copyImageToScreen(id, left, top, right, bottom); + _activatedPLSTs.push_back(x); + break; + } + } + + delete plst; +} + +void RivenGraphics::updateScreen(Common::Rect updateRect) { + if (_updatesEnabled) { + _vm->runUpdateScreenScript(); + + if (_dirtyScreen) { + _activatedPLSTs.clear(); + + // Copy to screen if there's no transition. Otherwise transition. ;) + if (_scheduledTransition < 0) + _vm->_system->copyRectToScreen((byte *)_mainScreen->getBasePtr(updateRect.left, updateRect.top), _mainScreen->pitch, updateRect.left, updateRect.top, updateRect.width(), updateRect.height()); + else + runScheduledTransition(); + + // Finally, update the screen. + _vm->_system->updateScreen(); + _dirtyScreen = false; + } + } +} + +void RivenGraphics::scheduleWaterEffect(uint16 sfxeID) { + Common::SeekableReadStream *sfxeStream = _vm->getResource(ID_SFXE, sfxeID); + + if (sfxeStream->readUint16BE() != 'SL') + error ("Unknown sfxe tag"); + + // Read in header info + SFXERecord sfxeRecord; + sfxeRecord.frameCount = sfxeStream->readUint16BE(); + uint32 offsetTablePosition = sfxeStream->readUint32BE(); + sfxeRecord.rect.left = sfxeStream->readUint16BE(); + sfxeRecord.rect.top = sfxeStream->readUint16BE(); + sfxeRecord.rect.right = sfxeStream->readUint16BE(); + sfxeRecord.rect.bottom = sfxeStream->readUint16BE(); + sfxeRecord.speed = sfxeStream->readUint16BE(); + // Skip the rest of the fields... + + // Read in offsets + sfxeStream->seek(offsetTablePosition); + uint32 *frameOffsets = new uint32[sfxeRecord.frameCount]; + for (uint16 i = 0; i < sfxeRecord.frameCount; i++) + frameOffsets[i] = sfxeStream->readUint32BE(); + sfxeStream->seek(frameOffsets[0]); + + // Read in the scripts + for (uint16 i = 0; i < sfxeRecord.frameCount; i++) + sfxeRecord.frameScripts.push_back(sfxeStream->readStream((i == sfxeRecord.frameCount - 1) ? sfxeStream->size() - frameOffsets[i] : frameOffsets[i + 1] - frameOffsets[i])); + + // Set it to the first frame + sfxeRecord.curFrame = 0; + sfxeRecord.lastFrameTime = 0; + + delete[] frameOffsets; + delete sfxeStream; + _waterEffects.push_back(sfxeRecord); +} + +void RivenGraphics::clearWaterEffects() { + _waterEffects.clear(); +} + +bool RivenGraphics::runScheduledWaterEffects() { + // Don't run the effect if it's disabled + if (_vm->_vars["waterenabled"] == 0) + return false; + + Graphics::Surface *screen = NULL; + + for (uint16 i = 0; i < _waterEffects.size(); i++) { + if (_vm->_system->getMillis() > _waterEffects[i].lastFrameTime + 1000 / _waterEffects[i].speed) { + // Lock the screen! + if (!screen) + screen = _vm->_system->lockScreen(); + + // Make sure the script is at the starting point + Common::SeekableReadStream *script = _waterEffects[i].frameScripts[_waterEffects[i].curFrame]; + if (script->pos() != 0) + script->seek(0); + + // Run script + uint16 curRow = 0; + for (uint16 op = script->readUint16BE(); op != 4; op = script->readUint16BE()) { + if (op == 1) { // Increment Row + curRow++; + } else if (op == 3) { // Copy Pixels + uint16 dstLeft = script->readUint16BE(); + uint16 srcLeft = script->readUint16BE(); + uint16 srcTop = script->readUint16BE(); + uint16 rowWidth = script->readUint16BE(); + memcpy ((byte *)screen->getBasePtr(dstLeft, curRow + _waterEffects[i].rect.top), (byte *)_mainScreen->getBasePtr(srcLeft, srcTop), rowWidth * _pixelFormat.bytesPerPixel); + } else if (op != 4) { // End of Script + error ("Unknown SFXE opcode %d", op); + } + } + + // Increment frame + _waterEffects[i].curFrame++; + if (_waterEffects[i].curFrame == _waterEffects[i].frameCount) + _waterEffects[i].curFrame = 0; + + // Set the new time + _waterEffects[i].lastFrameTime = _vm->_system->getMillis(); + } + } + + // Unlock the screen if it has been locked and return true to update the screen + if (screen) { + _vm->_system->unlockScreen(); + return true; + } + + return false; +} + +void RivenGraphics::scheduleTransition(uint16 id, Common::Rect rect) { + _scheduledTransition = id; + _transitionRect = rect; +} + +void RivenGraphics::runScheduledTransition() { + if (_scheduledTransition < 0) // No transition is scheduled + return; + + // TODO: There's a lot to be done here... + + // Note: Transitions 0-11 are actual transitions, but none are used in-game. + // There's no point in implementing them if they're not used. These extra + // transitions were found by hacking scripts. + + switch (_scheduledTransition) { + case 0: // Swipe Left + case 1: // Swipe Right + case 2: // Swipe Up + case 3: // Swipe Down + case 12: // Pan Left + case 13: // Pan Right + case 14: // Pan Up + case 15: // Pan Down + case 16: // Dissolve + case 17: // Dissolve (tspit CARD 155) + break; + default: + if (_scheduledTransition >= 4 && _scheduledTransition <= 11) + error("Found unused transition %d", _scheduledTransition); + else + error("Found unknown transition %d", _scheduledTransition); + } + + // For now, just copy the image to screen without doing any transition. + _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); + _vm->_system->updateScreen(); + + _scheduledTransition = -1; // Clear scheduled transition +} + +void RivenGraphics::clearMainScreen() { + _mainScreen->fillRect(Common::Rect(0, 0, 608, 392), _pixelFormat.RGBToColor(0, 0, 0)); +} + +void RivenGraphics::fadeToBlack() { + // The transition speed is forced to best here + setTransitionSpeed(kRivenTransitionSpeedBest); + scheduleTransition(16); + clearMainScreen(); + runScheduledTransition(); +} + +void RivenGraphics::showInventory() { + // Don't redraw the inventory + if (_inventoryDrawn) + return; + + // Clear the inventory area + clearInventoryArea(); + + // Draw the demo's exit button + if (_vm->getFeatures() & GF_DEMO) { + // extras.mhk tBMP 101 contains "EXIT" instead of Atrus' journal in the demo! + // The demo's extras.mhk contains all the other inventory/marble/credits image + // but has hacked tBMP 101 with "EXIT". *sigh* + drawInventoryImage(101, g_demoExitRect); + } else { + // We don't want to show the inventory on setup screens or in other journals. + if (_vm->getCurStack() == aspit) + return; + + // There are three books and three vars. We have three different + // combinations. At the start you have just Atrus' journal. Later, + // you get Catherine's journal and the trap book. Near the end, + // you lose the trap book and have just the two journals. + + bool hasCathBook = _vm->_vars["acathbook"] != 0; + bool hasTrapBook = _vm->_vars["atrapbook"] != 0; + + if (!hasCathBook) { + drawInventoryImage(101, g_atrusJournalRect1); + } else if (!hasTrapBook) { + drawInventoryImage(101, g_atrusJournalRect2); + drawInventoryImage(102, g_cathJournalRect2); + } else { + drawInventoryImage(101, g_atrusJournalRect3); + drawInventoryImage(102, g_cathJournalRect3); + drawInventoryImage(100, g_trapBookRect3); + } + } + + _vm->_system->updateScreen(); + _inventoryDrawn = true; +} + +void RivenGraphics::hideInventory() { + // Don't hide the inventory twice + if (!_inventoryDrawn) + return; + + // Clear the area + clearInventoryArea(); + + _inventoryDrawn = false; +} + +void RivenGraphics::clearInventoryArea() { + // Clear the inventory area + static const Common::Rect inventoryRect = Common::Rect(0, 392, 608, 436); + + // Lock the screen + Graphics::Surface *screen = _vm->_system->lockScreen(); + + // Fill the inventory area with black + screen->fillRect(inventoryRect, _pixelFormat.RGBToColor(0, 0, 0)); + + _vm->_system->unlockScreen(); +} + +void RivenGraphics::drawInventoryImage(uint16 id, const Common::Rect *rect) { + MohawkSurface *mhkSurface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id)); + mhkSurface->convertToTrueColor(); + Graphics::Surface *surface = mhkSurface->getSurface(); + + _vm->_system->copyRectToScreen((byte *)surface->pixels, surface->pitch, rect->left, rect->top, surface->w, surface->h); + + delete mhkSurface; +} + +void RivenGraphics::drawRect(Common::Rect rect, bool active) { + // Useful with debugging. Shows where hotspots are on the screen and whether or not they're active. + Graphics::Surface *screen = _vm->_system->lockScreen(); + + if (active) + screen->frameRect(rect, _pixelFormat.RGBToColor(0, 255, 0)); + else + screen->frameRect(rect, _pixelFormat.RGBToColor(255, 0, 0)); + + _vm->_system->unlockScreen(); +} + +void RivenGraphics::drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect) { + // Draw tBMP id from srcRect to dstRect + Graphics::Surface *surface = findImage(id)->getSurface(); + + assert(srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height()); + + for (uint16 i = 0; i < srcRect.height(); i++) + memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(srcRect.left, i + srcRect.top), srcRect.width() * surface->format.bytesPerPixel); + + _dirtyScreen = true; +} + +void RivenGraphics::drawExtrasImage(uint16 id, Common::Rect dstRect) { + MohawkSurface *mhkSurface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, id)); + mhkSurface->convertToTrueColor(); + Graphics::Surface *surface = mhkSurface->getSurface(); + + assert(dstRect.width() == surface->w); + + for (uint16 i = 0; i < surface->h; i++) + memcpy(_mainScreen->getBasePtr(dstRect.left, i + dstRect.top), surface->getBasePtr(0, i), surface->pitch); + + delete mhkSurface; + _dirtyScreen = true; +} + +void RivenGraphics::beginCredits() { + // Clear the old cache + clearCache(); + + // Now cache all the credits images + for (uint16 i = 302; i <= 320; i++) { + MohawkSurface *surface = _bitmapDecoder->decodeImage(_vm->getExtrasResource(ID_TBMP, i)); + surface->convertToTrueColor(); + addImageToCache(i, surface); + } + + // And clear our screen too + clearMainScreen(); +} + +void RivenGraphics::updateCredits() { + if ((_creditsImage == 303 || _creditsImage == 304) && _creditsPos == 0) + fadeToBlack(); + + if (_creditsImage < 304) { + // For the first two credit images, they are faded from black to the image and then out again + scheduleTransition(16); + + Graphics::Surface *frame = findImage(_creditsImage++)->getSurface(); + + for (int y = 0; y < frame->h; y++) + memcpy(_mainScreen->getBasePtr(124, y), frame->getBasePtr(0, y), frame->pitch); + + runScheduledTransition(); + } else { + // Otheriwse, we're scrolling + // Move the screen up one row + memmove(_mainScreen->pixels, _mainScreen->getBasePtr(0, 1), _mainScreen->pitch * (_mainScreen->h - 1)); + + // Only update as long as we're not before the last frame + // Otherwise, we're just moving up a row (which we already did) + if (_creditsImage <= 320) { + // Copy the next row to the bottom of the screen + Graphics::Surface *frame = findImage(_creditsImage)->getSurface(); + memcpy(_mainScreen->getBasePtr(124, _mainScreen->h - 1), frame->getBasePtr(0, _creditsPos), frame->pitch); + _creditsPos++; + + if (_creditsPos == _mainScreen->h) { + _creditsImage++; + _creditsPos = 0; + } + } + + // Now flush the new screen + _vm->_system->copyRectToScreen((byte *)_mainScreen->pixels, _mainScreen->pitch, 0, 0, _mainScreen->w, _mainScreen->h); + _vm->_system->updateScreen(); + } +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/riven_graphics.h b/engines/mohawk/riven_graphics.h new file mode 100644 index 0000000000..48dda28afd --- /dev/null +++ b/engines/mohawk/riven_graphics.h @@ -0,0 +1,110 @@ +/* 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. + * + */ + +#ifndef MOHAWK_RIVEN_GRAPHICS_H +#define MOHAWK_RIVEN_GRAPHICS_H + +#include "mohawk/graphics.h" + +namespace Mohawk { + +class MohawkEngine_Riven; + +class RivenGraphics : public GraphicsManager { +public: + RivenGraphics(MohawkEngine_Riven *vm); + ~RivenGraphics(); + + void copyImageToScreen(uint16, uint32, uint32, uint32, uint32); + void updateScreen(Common::Rect updateRect = Common::Rect(0, 0, 608, 392)); + bool _updatesEnabled; + Common::Array<uint16> _activatedPLSTs; + void drawPLST(uint16 x); + void drawRect(Common::Rect rect, bool active); + void drawImageRect(uint16 id, Common::Rect srcRect, Common::Rect dstRect); + void drawExtrasImage(uint16 id, Common::Rect dstRect); + + // Water Effect + void scheduleWaterEffect(uint16); + void clearWaterEffects(); + bool runScheduledWaterEffects(); + + // Transitions + void scheduleTransition(uint16 id, Common::Rect rect = Common::Rect(0, 0, 608, 392)); + void runScheduledTransition(); + void fadeToBlack(); + void setTransitionSpeed(uint32 speed) { _transitionSpeed = speed; } + + // Inventory + void showInventory(); + void hideInventory(); + + // Credits + void beginCredits(); + void updateCredits(); + uint getCurCreditsImage() { return _creditsImage; } + +protected: + MohawkSurface *decodeImage(uint16 id); + MohawkEngine *getVM() { return (MohawkEngine *)_vm; } + +private: + MohawkEngine_Riven *_vm; + MohawkBitmap *_bitmapDecoder; + + // Water Effects + struct SFXERecord { + // Record values + uint16 frameCount; + Common::Rect rect; + uint16 speed; + Common::Array<Common::SeekableReadStream *> frameScripts; + + // Cur frame + uint16 curFrame; + uint32 lastFrameTime; + }; + Common::Array<SFXERecord> _waterEffects; + + // Transitions + int16 _scheduledTransition; + Common::Rect _transitionRect; + uint32 _transitionSpeed; + + // Inventory + void clearInventoryArea(); + void drawInventoryImage(uint16 id, const Common::Rect *rect); + bool _inventoryDrawn; + + // Screen Related + Graphics::Surface *_mainScreen; + bool _dirtyScreen; + Graphics::PixelFormat _pixelFormat; + void clearMainScreen(); + + // Credits + uint _creditsImage, _creditsPos; +}; + +} // End of namespace Mohawk + +#endif diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp index 6e3e9a34dc..352a018990 100644 --- a/engines/mohawk/riven_scripts.cpp +++ b/engines/mohawk/riven_scripts.cpp @@ -21,9 +21,9 @@ */ #include "mohawk/cursors.h" -#include "mohawk/graphics.h" #include "mohawk/riven.h" #include "mohawk/riven_external.h" +#include "mohawk/riven_graphics.h" #include "mohawk/riven_scripts.h" #include "mohawk/sound.h" #include "mohawk/video.h" diff --git a/engines/mohawk/riven_scripts.h b/engines/mohawk/riven_scripts.h index 2932ba5939..6df4a2e523 100644 --- a/engines/mohawk/riven_scripts.h +++ b/engines/mohawk/riven_scripts.h @@ -27,8 +27,6 @@ #include "common/ptr.h" #include "common/textconsole.h" -class MohawkEngine_Riven; - #define DECLARE_OPCODE(x) void x(uint16 op, uint16 argc, uint16 *argv) namespace Mohawk { @@ -50,6 +48,7 @@ enum { kStoredOpcodeScript // This is ScummVM-only to denote the script from a storeMovieOpcode() call }; +class MohawkEngine_Riven; class RivenScript; class RivenScript { @@ -125,7 +124,7 @@ private: DECLARE_OPCODE(activateMLST); }; -typedef Common::Array<RivenScript*> RivenScriptList; +typedef Common::Array<RivenScript *> RivenScriptList; class RivenScriptManager { public: diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index cd8fc8ef80..8d72fa3f72 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -261,7 +261,7 @@ bool VideoManager::updateMovies() { // Clip the width/height to make sure we stay on the screen (Myst does this a few times) uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x); uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y); - _vm->_system->copyRectToScreen((byte*)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); + _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); // We've drawn something to the screen, make sure we update it updateScreen = true; @@ -529,6 +529,15 @@ void VideoManager::setVideoBounds(VideoHandle handle, Audio::Timestamp start, Au _videoStreams[handle]->seekToTime(start); } +void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) { + assert(handle != NULL_VID_HANDLE); + _videoStreams[handle].end = Audio::Timestamp(0xffffffff, 1); + _videoStreams[handle]->seekToTime(time); + updateMovies(); + delete _videoStreams[handle].video; + _videoStreams[handle].clear(); +} + void VideoManager::seekToTime(VideoHandle handle, Audio::Timestamp time) { assert(handle != NULL_VID_HANDLE); _videoStreams[handle]->seekToTime(time); diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index efa81edfbd..34c287497f 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -104,6 +104,7 @@ public: uint32 getDuration(VideoHandle videoHandle); bool endOfVideo(VideoHandle handle); void setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end); + void drawVideoFrame(VideoHandle handle, Audio::Timestamp time); void seekToTime(VideoHandle handle, Audio::Timestamp time); void setVideoLooping(VideoHandle handle, bool loop); void waitUntilMovieEnds(VideoHandle videoHandle); |