aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorNeeraj Kumar2010-06-08 17:24:29 +0000
committerNeeraj Kumar2010-06-08 17:24:29 +0000
commit207a5e0779de9f0002b0b1984bde90ce6597e1f2 (patch)
tree98883ef89261afd4288f6dadbffe436d5d966dfc /engines
parente00e94ae18aeb1ed460476f822e20b5bdfe171a4 (diff)
parent356728dab7f2c4cedf73684d7fe3b968be7396fd (diff)
downloadscummvm-rg350-207a5e0779de9f0002b0b1984bde90ce6597e1f2.tar.gz
scummvm-rg350-207a5e0779de9f0002b0b1984bde90ce6597e1f2.tar.bz2
scummvm-rg350-207a5e0779de9f0002b0b1984bde90ce6597e1f2.zip
updated my outdate copy of trunk, added couple of more tests in gfxtests
svn-id: r49510
Diffstat (limited to 'engines')
-rw-r--r--engines/dialogs.cpp45
-rw-r--r--engines/dialogs.h43
-rw-r--r--engines/drascula/animation.cpp2
-rw-r--r--engines/drascula/drascula.cpp1
-rw-r--r--engines/drascula/objects.cpp3
-rw-r--r--engines/m4/animation.cpp546
-rw-r--r--engines/m4/animation.h109
-rw-r--r--engines/m4/assets.cpp36
-rw-r--r--engines/m4/assets.h8
-rw-r--r--engines/m4/compression.h4
-rw-r--r--engines/m4/console.cpp56
-rw-r--r--engines/m4/console.h3
-rw-r--r--engines/m4/converse.cpp8
-rw-r--r--engines/m4/dialogs.cpp26
-rw-r--r--engines/m4/font.cpp57
-rw-r--r--engines/m4/font.h48
-rw-r--r--engines/m4/graphics.cpp104
-rw-r--r--engines/m4/graphics.h18
-rw-r--r--engines/m4/gui.cpp30
-rw-r--r--engines/m4/m4.cpp18
-rw-r--r--engines/m4/m4.h3
-rw-r--r--engines/m4/m4_views.cpp2
-rw-r--r--engines/m4/mads_anim.cpp149
-rw-r--r--engines/m4/mads_anim.h39
-rw-r--r--engines/m4/mads_logic.cpp29
-rw-r--r--engines/m4/mads_logic.h3
-rw-r--r--engines/m4/mads_menus.cpp52
-rw-r--r--engines/m4/mads_scene.cpp606
-rw-r--r--engines/m4/mads_scene.h69
-rw-r--r--engines/m4/mads_views.cpp813
-rw-r--r--engines/m4/mads_views.h147
-rw-r--r--engines/m4/viewmgr.h13
-rw-r--r--engines/mohawk/console.cpp2
-rw-r--r--engines/mohawk/detection.cpp36
-rw-r--r--engines/mohawk/graphics.cpp12
-rw-r--r--engines/mohawk/graphics.h12
-rw-r--r--engines/mohawk/jpeg.cpp87
-rw-r--r--engines/mohawk/jpeg.h59
-rw-r--r--engines/mohawk/module.mk10
-rw-r--r--engines/mohawk/mohawk.cpp2
-rw-r--r--engines/mohawk/myst.cpp2
-rw-r--r--engines/mohawk/myst_pict.cpp272
-rw-r--r--engines/mohawk/myst_pict.h57
-rw-r--r--engines/mohawk/myst_scripts.cpp2
-rw-r--r--engines/mohawk/riven.cpp18
-rw-r--r--engines/mohawk/riven.h8
-rw-r--r--engines/mohawk/riven_external.cpp58
-rw-r--r--engines/mohawk/riven_external.h2
-rw-r--r--engines/mohawk/riven_scripts.cpp18
-rw-r--r--engines/mohawk/video.cpp (renamed from engines/mohawk/video/video.cpp)66
-rw-r--r--engines/mohawk/video.h (renamed from engines/mohawk/video/video.h)21
-rw-r--r--engines/mohawk/video/cinepak.cpp286
-rw-r--r--engines/mohawk/video/cinepak.h81
-rw-r--r--engines/mohawk/video/qdm2.cpp3063
-rw-r--r--engines/mohawk/video/qdm2.h289
-rw-r--r--engines/mohawk/video/qdm2data.h531
-rw-r--r--engines/mohawk/video/qt_player.cpp1272
-rw-r--r--engines/mohawk/video/qt_player.h282
-rw-r--r--engines/mohawk/video/qtrle.cpp420
-rw-r--r--engines/mohawk/video/qtrle.h58
-rw-r--r--engines/mohawk/video/rpza.cpp208
-rw-r--r--engines/mohawk/video/smc.cpp385
-rw-r--r--engines/mohawk/video/smc.h59
-rw-r--r--engines/parallaction/input.cpp2
-rw-r--r--engines/parallaction/parser_ns.cpp2
-rw-r--r--engines/saga/saga.cpp14
-rw-r--r--engines/sci/console.cpp171
-rw-r--r--engines/sci/console.h1
-rw-r--r--engines/sci/detection.cpp223
-rw-r--r--engines/sci/engine/features.cpp88
-rw-r--r--engines/sci/engine/game.cpp173
-rw-r--r--engines/sci/engine/kernel.cpp8
-rw-r--r--engines/sci/engine/kernel.h1
-rw-r--r--engines/sci/engine/kernel32.cpp95
-rw-r--r--engines/sci/engine/kevent.cpp58
-rw-r--r--engines/sci/engine/kfile.cpp132
-rw-r--r--engines/sci/engine/kgraphics.cpp117
-rw-r--r--engines/sci/engine/klists.cpp52
-rw-r--r--engines/sci/engine/kmisc.cpp24
-rw-r--r--engines/sci/engine/kmovement.cpp141
-rw-r--r--engines/sci/engine/kparse.cpp40
-rw-r--r--engines/sci/engine/kpathing.cpp66
-rw-r--r--engines/sci/engine/kscripts.cpp36
-rw-r--r--engines/sci/engine/kstring.cpp36
-rw-r--r--engines/sci/engine/savegame.cpp206
-rw-r--r--engines/sci/engine/savegame.h2
-rw-r--r--engines/sci/engine/script.cpp277
-rw-r--r--engines/sci/engine/scriptdebug.cpp86
-rw-r--r--engines/sci/engine/seg_manager.cpp46
-rw-r--r--engines/sci/engine/seg_manager.h44
-rw-r--r--engines/sci/engine/segment.cpp425
-rw-r--r--engines/sci/engine/segment.h238
-rw-r--r--engines/sci/engine/selector.cpp44
-rw-r--r--engines/sci/engine/selector.h31
-rw-r--r--engines/sci/engine/state.cpp70
-rw-r--r--engines/sci/engine/state.h41
-rw-r--r--engines/sci/engine/vm.cpp425
-rw-r--r--engines/sci/engine/vm.h86
-rw-r--r--engines/sci/event.cpp3
-rw-r--r--engines/sci/graphics/animate.cpp87
-rw-r--r--engines/sci/graphics/animate.h3
-rw-r--r--engines/sci/graphics/compare.cpp68
-rw-r--r--engines/sci/graphics/controls.cpp18
-rw-r--r--engines/sci/graphics/coordadjuster.cpp16
-rw-r--r--engines/sci/graphics/frameout.cpp54
-rw-r--r--engines/sci/graphics/gui.cpp7
-rw-r--r--engines/sci/graphics/gui.h2
-rw-r--r--engines/sci/graphics/maciconbar.cpp91
-rw-r--r--engines/sci/graphics/maciconbar.h (renamed from engines/mohawk/video/rpza.h)32
-rw-r--r--engines/sci/graphics/menu.cpp8
-rw-r--r--engines/sci/graphics/paint16.cpp5
-rw-r--r--engines/sci/graphics/paint16.h2
-rw-r--r--engines/sci/graphics/palette.cpp9
-rw-r--r--engines/sci/graphics/picture.cpp51
-rw-r--r--engines/sci/graphics/picture.h9
-rw-r--r--engines/sci/graphics/ports.cpp3
-rw-r--r--engines/sci/graphics/ports.h2
-rw-r--r--engines/sci/graphics/screen.cpp13
-rw-r--r--engines/sci/module.mk2
-rw-r--r--engines/sci/parser/grammar.cpp5
-rw-r--r--engines/sci/parser/said.cpp7
-rw-r--r--engines/sci/parser/said.y7
-rw-r--r--engines/sci/resource.cpp1065
-rw-r--r--engines/sci/resource.h64
-rw-r--r--engines/sci/resource_audio.cpp711
-rw-r--r--engines/sci/sci.cpp21
-rw-r--r--engines/sci/sci.h3
-rw-r--r--engines/sci/sound/audio.cpp12
-rw-r--r--engines/sci/sound/midiparser_sci.cpp26
-rw-r--r--engines/sci/sound/midiparser_sci.h13
-rw-r--r--engines/sci/sound/music.cpp95
-rw-r--r--engines/sci/sound/music.h11
-rw-r--r--engines/sci/sound/soundcmd.cpp231
-rw-r--r--engines/scumm/charset.cpp2
-rw-r--r--engines/scumm/debugger.cpp2
-rw-r--r--engines/scumm/dialogs.cpp213
-rw-r--r--engines/scumm/dialogs.h24
-rw-r--r--engines/scumm/he/resource_he.cpp4
-rw-r--r--engines/scumm/input.cpp2
-rw-r--r--engines/scumm/scumm-md5.h5
-rw-r--r--engines/scumm/scumm.cpp18
-rw-r--r--engines/scumm/scumm.h2
-rw-r--r--engines/sword1/animation.cpp38
-rw-r--r--engines/sword1/animation.h1
-rw-r--r--engines/sword2/animation.cpp37
-rw-r--r--engines/sword2/animation.h1
-rw-r--r--engines/testbed/gfxtests.cpp93
-rw-r--r--engines/testbed/gfxtests.h2
-rw-r--r--engines/testbed/graphics.cpp11
-rw-r--r--engines/testbed/graphics.h4
-rw-r--r--engines/tinsel/handle.cpp3
-rw-r--r--engines/tinsel/saveload.cpp3
-rw-r--r--engines/tucker/sequences.cpp67
-rw-r--r--engines/tucker/tucker.h5
154 files changed, 5663 insertions, 11899 deletions
diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp
index 73ba591b4b..954bc81470 100644
--- a/engines/dialogs.cpp
+++ b/engines/dialogs.cpp
@@ -35,8 +35,9 @@
#include "gui/GuiManager.h"
#include "gui/launcher.h"
#include "gui/ListWidget.h"
-#include "gui/ThemeEval.h"
+#include "gui/options.h"
#include "gui/saveload.h"
+#include "gui/ThemeEval.h"
#include "engines/dialogs.h"
#include "engines/engine.h"
@@ -49,16 +50,17 @@
using GUI::CommandSender;
using GUI::StaticTextWidget;
-enum {
- kSaveCmd = 'SAVE',
- kLoadCmd = 'LOAD',
- kPlayCmd = 'PLAY',
- kOptionsCmd = 'OPTN',
- kHelpCmd = 'HELP',
- kAboutCmd = 'ABOU',
- kQuitCmd = 'QUIT',
- kRTLCmd = 'RTL ',
- kChooseCmd = 'CHOS'
+class ConfigDialog : public GUI::OptionsDialog {
+protected:
+#ifdef SMALL_SCREEN_DEVICE
+ GUI::Dialog *_keysDialog;
+#endif
+
+public:
+ ConfigDialog(bool subtitleControls);
+ ~ConfigDialog();
+
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
};
MainMenuDialog::MainMenuDialog(Engine *engine)
@@ -95,6 +97,12 @@ MainMenuDialog::MainMenuDialog(Engine *engine)
new GUI::ButtonWidget(this, "GlobalMenu.Options", "Options", kOptionsCmd, 'O');
+ // The help button is disabled by default.
+ // To enable "Help", an engine needs to use a subclass of MainMenuDialog
+ // (at least for now, we might change how this works in the future).
+ _helpButton = new GUI::ButtonWidget(this, "GlobalMenu.Help", "Help", kHelpCmd, 'H');
+ _helpButton->setEnabled(false);
+
new GUI::ButtonWidget(this, "GlobalMenu.About", "About", kAboutCmd, 'A');
_rtlButton = new GUI::ButtonWidget(this, "GlobalMenu.RTL", "Return to Launcher", kRTLCmd, 'R');
@@ -135,6 +143,9 @@ void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
case kAboutCmd:
_aboutDialog->runModal();
break;
+ case kHelpCmd:
+ // Not handled here -- needs to be handled by a subclass (for now)
+ break;
case kRTLCmd: {
Common::Event eventRTL;
eventRTL.type = Common::EVENT_RTL;
@@ -263,13 +274,13 @@ enum {
// "" as value for the domain, and in fact provide a somewhat better user
// experience at the same time.
ConfigDialog::ConfigDialog(bool subtitleControls)
- : GUI::OptionsDialog("", "ScummConfig") {
+ : GUI::OptionsDialog("", "GlobalConfig") {
//
// Sound controllers
//
- addVolumeControls(this, "ScummConfig.");
+ addVolumeControls(this, "GlobalConfig.");
setVolumeSettingsState(true); // could disable controls by GUI options
//
@@ -278,7 +289,7 @@ ConfigDialog::ConfigDialog(bool subtitleControls)
if (subtitleControls) {
// Global talkspeed range of 0-255
- addSubtitleControls(this, "ScummConfig.", 255);
+ addSubtitleControls(this, "GlobalConfig.", 255);
setSubtitleSettingsState(true); // could disable controls by GUI options
}
@@ -286,11 +297,11 @@ ConfigDialog::ConfigDialog(bool subtitleControls)
// Add the buttons
//
- new GUI::ButtonWidget(this, "ScummConfig.Ok", "OK", GUI::kOKCmd, 'O');
- new GUI::ButtonWidget(this, "ScummConfig.Cancel", "Cancel", GUI::kCloseCmd, 'C');
+ new GUI::ButtonWidget(this, "GlobalConfig.Ok", "OK", GUI::kOKCmd, 'O');
+ new GUI::ButtonWidget(this, "GlobalConfig.Cancel", "Cancel", GUI::kCloseCmd, 'C');
#ifdef SMALL_SCREEN_DEVICE
- new GUI::ButtonWidget(this, "ScummConfig.Keys", "Keys", kKeysCmd, 'K');
+ new GUI::ButtonWidget(this, "GlobalConfig.Keys", "Keys", kKeysCmd, 'K');
_keysDialog = NULL;
#endif
}
diff --git a/engines/dialogs.h b/engines/dialogs.h
index 6bee7c5fb1..6e5338b317 100644
--- a/engines/dialogs.h
+++ b/engines/dialogs.h
@@ -27,7 +27,6 @@
#include "common/str.h"
#include "gui/dialog.h"
-#include "gui/options.h"
class Engine;
@@ -39,6 +38,19 @@ namespace GUI {
class MainMenuDialog : public GUI::Dialog {
public:
+ enum {
+ kSaveCmd = 'SAVE',
+ kLoadCmd = 'LOAD',
+ kPlayCmd = 'PLAY',
+ kOptionsCmd = 'OPTN',
+ kHelpCmd = 'HELP',
+ kAboutCmd = 'ABOU',
+ kQuitCmd = 'QUIT',
+ kRTLCmd = 'RTL ',
+ kChooseCmd = 'CHOS'
+ };
+
+public:
MainMenuDialog(Engine *engine);
~MainMenuDialog();
@@ -51,29 +63,20 @@ protected:
void load();
protected:
- Engine *_engine;
+ Engine *_engine;
- GUI::GraphicsWidget *_logo;
- GUI::ButtonWidget *_rtlButton;
- GUI::ButtonWidget *_loadButton;
- GUI::ButtonWidget *_saveButton;
- GUI::Dialog *_aboutDialog;
- GUI::Dialog *_optionsDialog;
- GUI::SaveLoadChooser *_loadDialog;
- GUI::SaveLoadChooser *_saveDialog;
-};
+ GUI::GraphicsWidget *_logo;
-class ConfigDialog : public GUI::OptionsDialog {
-protected:
-#ifdef SMALL_SCREEN_DEVICE
- GUI::Dialog *_keysDialog;
-#endif
+ GUI::ButtonWidget *_rtlButton;
+ GUI::ButtonWidget *_loadButton;
+ GUI::ButtonWidget *_saveButton;
+ GUI::ButtonWidget *_helpButton;
-public:
- ConfigDialog(bool subtitleControls);
- ~ConfigDialog();
+ GUI::Dialog *_aboutDialog;
+ GUI::Dialog *_optionsDialog;
- virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+ GUI::SaveLoadChooser *_loadDialog;
+ GUI::SaveLoadChooser *_saveDialog;
};
#endif
diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp
index 4a0b82d746..e4bd844d75 100644
--- a/engines/drascula/animation.cpp
+++ b/engines/drascula/animation.cpp
@@ -1602,7 +1602,7 @@ void DrasculaEngine::animation_9_6() {
// We set the room number to -1 for the same purpose.
// Also check animation_2_1(), where the same hack was used
// by the original
- roomNumber = -1;
+ roomNumber = -2;
loadPic("nota2.alg", bgSurface, HALF_PAL);
black();
trackProtagonist = 1;
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index 276554a24c..2c3ca63600 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -87,6 +87,7 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam
_textverbs = 0;
_textmisc = 0;
_textd1 = 0;
+ _talkSequences = 0;
_color = 0;
blinking = 0;
diff --git a/engines/drascula/objects.cpp b/engines/drascula/objects.cpp
index c4dc3df1f6..13c8a742ca 100644
--- a/engines/drascula/objects.cpp
+++ b/engines/drascula/objects.cpp
@@ -89,7 +89,8 @@ void DrasculaEngine::gotoObject(int pointX, int pointY) {
updateRoom();
updateScreen();
- if (cursorVisible)
+ // roomNumber -2 is end credits. Do not show cursor there
+ if (cursorVisible && roomNumber != -2)
showCursor();
}
diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp
index fe46e121f0..1142ba48d1 100644
--- a/engines/m4/animation.cpp
+++ b/engines/m4/animation.cpp
@@ -26,181 +26,463 @@
#include "m4/assets.h"
#include "m4/animation.h"
#include "m4/compression.h"
+#include "m4/mads_scene.h"
namespace M4 {
// TODO: this code needs cleanup
-Animation::Animation(MadsM4Engine *vm) {
- _vm = vm;
- _playing = false;
+MadsAnimation::MadsAnimation(MadsM4Engine *vm, MadsView *view): Animation(vm), _view(view) {
+ _font = NULL;
+ _resetFlag = false;
+ _freeFlag = false;
+ _skipLoad = false;
+ _unkIndex = -1;
+ _messageCtr= 0;
+ _field12 = 0;
+
+ _currentFrame = 0;
+ _oldFrameEntry = 0;
+ _nextFrameTimer = _madsVm->_currentTimer;
}
-void Animation::loadFullScreen(const char *filename) {
- _vm->_palette->deleteAllRanges();
- load(filename);
+MadsAnimation::~MadsAnimation() {
+ for (uint i = 0; i < _messages.size(); ++i) {
+ if (_messages[i].kernelMsgIndex >= 0)
+ _view->_kernelMessages.remove(_messages[i].kernelMsgIndex);
+ }
+
+ // Further deletion logic
+ if (_field12) {
+ _view->_spriteSlots.deleteSprites(_spriteListIndexes[_spriteListIndex]);
+ }
+
+ delete _font;
}
-void Animation::load(const char *filename) {
- MadsPack anim(filename, _vm);
+/**
+ * Initialises and loads the data of an animation
+ */
+void MadsAnimation::initialise(const Common::String &filename, uint16 flags, M4Surface *interfaceSurface, M4Surface *sceneSurface) {
+ MadsPack anim(filename.c_str(), _vm);
+ bool madsRes = filename[0] == '*';
char buffer[20];
+ int streamIndex = 1;
// Chunk 1: header
// header
- // TODO: there are some unknown fields here, plus we don't read
- // the entire chunk
+
Common::SeekableReadStream *animStream = anim.getItemStream(0);
- Common::SeekableReadStream *spriteSeriesStream;
- //printf("Chunk 0, size %i\n", animStream->size());
- _seriesCount = animStream->readUint16LE();
- _frameCount = animStream->readUint16LE();
- _frameEntryCount = animStream->readUint16LE();
- // Unknown
- for (int i = 0; i < 43; i++)
- animStream->readByte();
+ int spriteListCount = animStream->readUint16LE();
+ int miscEntriesCount = animStream->readUint16LE();
+ int frameEntryCount = animStream->readUint16LE();
+ int messagesCount = animStream->readUint16LE();
+ animStream->skip(1);
+ _flags = animStream->readByte();
+
+ animStream->skip(2);
+ _animMode = animStream->readUint16LE();
+ _roomNumber = animStream->readUint16LE();
+ animStream->skip(2);
+ _field12 = animStream->readUint16LE() != 0;
+ _spriteListIndex = animStream->readUint16LE();
+ _scrollX = animStream->readUint16LE();
+ _scrollY = animStream->readSint16LE();
+ animStream->skip(10);
+
+ animStream->read(buffer, 13);
+ _interfaceFile = Common::String(buffer, 13);
+
+ for (int i = 0; i < 10; ++i) {
+ animStream->read(buffer, 13);
+ _spriteSetNames[i] = Common::String(buffer, 13);
+ }
- _spriteSeriesNames = new Common::String[_seriesCount];
- printf("%i sprite series\n", _seriesCount);
+ animStream->skip(81);
+ animStream->read(buffer, 13);
+ _lbmFilename = Common::String(buffer, 13);
+ animStream->read(buffer, 13);
+ _spritesFilename = Common::String(buffer, 13);
+ animStream->skip(48);
+ animStream->read(buffer, 13);
+ _soundName = Common::String(buffer, 13);
+ animStream->skip(26);
+ animStream->read(buffer, 13);
+ Common::String fontResource(buffer, 13);
+
+ if (_animMode == 4)
+ flags |= 0x4000;
+ if (flags & 0x100)
+ loadInterface(interfaceSurface, sceneSurface);
+
+ // Initialise the reference list
+ for (int i = 0; i < spriteListCount; ++i)
+ _spriteListIndexes.push_back(-1);
- // TODO: for now, we only load the first sprite series
- if (_seriesCount > 1)
- printf("TODO: Anim has %i sprite series, for now, we only load the first one\n", _seriesCount);
- _seriesCount = 1; // TODO
+ delete animStream;
- for (int i = 0; i < _seriesCount; i++) {
- animStream->read(buffer, 13);
- _spriteSeriesNames[i] = Common::String(buffer);
- //printf("%03d: %s\n", i, _spriteSeriesNames[i].c_str());
-
- spriteSeriesStream = _vm->res()->get(_spriteSeriesNames[i].c_str());
- _spriteSeries = new SpriteAsset(_vm, spriteSeriesStream,
- spriteSeriesStream->size(), _spriteSeriesNames[i].c_str());
- _vm->res()->toss(_spriteSeriesNames[i].c_str());
-
- // Adjust the palette of the sprites in the sprite series
- // so that they can be displayed on screen correctly
- RGBList *palData = new RGBList(_spriteSeries->getColorCount(), _spriteSeries->getPalette(), true);
- _vm->_palette->addRange(palData);
-
- for (int k = 0; k < _spriteSeries->getCount(); k++) {
- M4Sprite *spr = _spriteSeries->getFrame(k);
- spr->translate(palData); // sprite pixel translation
+ if (messagesCount > 0) {
+ // Chunk 2
+ // Following is a list of any messages for the animation
+
+ animStream = anim.getItemStream(streamIndex++);
+
+ for (int i = 0; i < messagesCount; ++i) {
+ AnimMessage rec;
+ animStream->read(rec.msg, 70);
+ rec.pos.x = animStream->readUint16LE();
+ rec.pos.y = animStream->readUint16LE();
+ animStream->readUint16LE();
+ rec.rgb1.r = animStream->readByte();
+ rec.rgb1.g = animStream->readByte();
+ rec.rgb1.b = animStream->readByte();
+ rec.rgb2.r = animStream->readByte();
+ rec.rgb2.g = animStream->readByte();
+ rec.rgb2.b = animStream->readByte();
+ rec.kernelMsgIndex = animStream->readUint16LE();
+ animStream->skip(6);
+ rec.startFrame = animStream->readUint16LE();
+ rec.endFrame = animStream->readUint16LE();
+ animStream->readUint16LE();
+
+ _messages.push_back(rec);
}
+
+ delete animStream;
}
- //printf("End pos: %i\n", animStream->pos());
+ if (frameEntryCount > 0) {
+ // Chunk 3: animation frame info
+ animStream = anim.getItemStream(streamIndex++);
+
+ for (int i = 0; i < frameEntryCount; i++) {
+ AnimFrameEntry rec;
+ rec.frameNumber = animStream->readUint16LE();
+ rec.seqIndex = animStream->readByte();
+ rec.spriteSlot.spriteListIndex = animStream->readByte();
+ rec.spriteSlot.frameNumber = animStream->readUint16LE();
+ rec.spriteSlot.xp = animStream->readUint16LE();
+ rec.spriteSlot.yp = animStream->readUint16LE();
+ rec.spriteSlot.depth = animStream->readByte();
+ rec.spriteSlot.scale = (int8)animStream->readByte();
+
+ _frameEntries.push_back(rec);
+ }
- delete animStream;
+ delete animStream;
+ }
- // ------------------
-
- // Chunk 2: anim info
- AnimationFrame frame;
- animStream = anim.getItemStream(1);
- //printf("Chunk 1, size %i\n", animStream->size());
-
- _frameEntries = new AnimationFrame[_frameEntryCount];
-
- for (int i = 0; i < _frameEntryCount; i++) {
-
- frame.animFrameIndex = animStream->readUint16LE();
- frame.u = animStream->readByte();
- frame.seriesIndex = animStream->readByte();
- frame.seriesFrameIndex = animStream->readUint16LE();
- frame.x = animStream->readUint16LE();
- frame.y = animStream->readUint16LE();
- frame.v = animStream->readByte();
- frame.w = animStream->readByte();
-
- _frameEntries[i] = frame;
-
- /*
- printf(
- "animFrameIndex = %4d, "
- "u = %3d, "
- "seriesIndex = %3d, "
- "seriesFrameIndex = %6d, "
- "x = %3d, "
- "y = %3d, "
- "v = %3d, "
- "w = %3d\n",
-
- frame.animFrameIndex,
- frame.u,
- frame.seriesIndex,
- frame.seriesFrameIndex,
- frame.x,
- frame.y,
- frame.v,
- frame.w
- );
- */
- }
- //printf("End pos: %i\n", animStream->pos());
+ if (miscEntriesCount > 0) {
+ // Chunk 4: Misc Data
+ animStream = anim.getItemStream(streamIndex);
- delete animStream;
+ for (int i = 0; i < miscEntriesCount; ++i) {
+ AnimMiscEntry rec;
+ rec.soundNum = animStream->readByte();
+ animStream->skip(1);
+ rec.numTicks = animStream->readUint16LE();
+ rec.posAdjust.x = animStream->readUint16LE();
+ rec.posAdjust.y = animStream->readUint16LE();
+ animStream->readUint16LE();
- // Chunk 3: unknown (seems to be sound data?)
- // TODO
-}
+ _miscEntries.push_back(rec);
+ }
+
+ delete animStream;
+ }
+
+ // If the animation specifies a font, then load it for access
+ if (_flags & ANIM_CUSTOM_FONT) {
+ Common::String fontName;
+ if (madsRes)
+ fontName += "*";
+ fontName += fontResource;
-Animation::~Animation() {
- //delete[] _spriteSeriesNames;
- //delete[] _spriteSeries;
- //delete[] _frameEntries;
+ _font = _vm->_font->getFont(fontName);
+ }
+
+ // Load all the sprite sets for the animation
+ for (int i = 0; i < spriteListCount; ++i) {
+ if (_field12 && (i == _spriteListIndex))
+ // Skip over field, since it's manually loaded
+ continue;
+
+ _spriteListIndexes[i] = _view->_spriteSlots.addSprites(_spriteSetNames[i].c_str());
+ }
+
+
+ if (_field12) {
+ Common::String resName;
+ if (madsRes)
+ resName += "*";
+ resName += _spriteSetNames[_spriteListIndex];
+
+ _spriteListIndexes[_spriteListIndex] = _view->_spriteSlots.addSprites(resName.c_str());
+ }
+
+ // TODO: Unknown section about handling sprite set list combined with messages size
+
+ // TODO: The original has two separate loops for the loop below based on _animMode == 4. Is it
+ // perhaps that in that mode the sprite frames has a different format..?
+
+ // Remap the sprite list index fields from the initial value to the indexes of the loaded
+ // sprite sets for the animation
+ for (uint i = 0; i < _frameEntries.size(); ++i) {
+ int idx = _frameEntries[i].spriteSlot.spriteListIndex;
+ _frameEntries[i].spriteSlot.spriteListIndex = _spriteListIndexes[idx];
+ }
}
-void Animation::start() {
- _curFrame = 0;
- _curFrameEntry = 0;
- //for (int i = 0; i < _seriesCount; i++) {
- //_spriteSeries[i] = new SpriteSeries((char*)_spriteSeriesNames[i].c_str());
- //}
- _playing = true;
- updateAnim();
+/**
+ * Loads an animation file for display
+ */
+void MadsAnimation::load(const Common::String &filename, int abortTimers) {
+ initialise(filename, 0, NULL, NULL);
+ _messageCtr = 0;
+ _skipLoad = true;
+
+/* TODO: figure out extra stuff in this routine
+ if (_field12) {
+ _unkIndex = -1;
+ int listIndex = _spriteListIndexes[_spriteListIndex];
+ SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(listIndex);
+ ..?..
+ }
+*/
+
+ // Initialise miscellaneous fields
+ _currentFrame = 0;
+ _oldFrameEntry = 0;
+ _nextFrameTimer = _madsVm->_currentTimer;
+ _abortTimers = abortTimers;
+ _abortMode = _madsVm->scene()->_abortTimersMode2;
+
+ for (int i = 0; i < 3; ++i)
+ _actionNouns[i] = _madsVm->scene()->actionNouns[i];
+
+ // Initialise kernel message list
+ for (uint i = 0; i < _messages.size(); ++i)
+ _messages[i].kernelMsgIndex = -1;
}
-bool Animation::updateAnim() {
- if (!_playing)
- return true;
+void MadsAnimation::update() {
+ if (_field12) {
+ int spriteListIndex = _spriteListIndexes[_spriteListIndex];
+ int newIndex = -1;
+
+ for (uint idx = _oldFrameEntry; idx < _frameEntries.size(); ++idx) {
+ if (_frameEntries[idx].frameNumber > _currentFrame)
+ break;
+ if (_frameEntries[idx].spriteSlot.spriteListIndex == spriteListIndex)
+ newIndex = _frameEntries[idx].spriteSlot.frameNumber;
+ }
+
+ if (newIndex >= 0)
+ load1(newIndex);
+ }
+
+ // If it's not time for the next frame, then exit
+ if (_madsVm->_currentTimer < _nextFrameTimer)
+ return;
- // Get the scene background surface
- M4Surface *bg = _vm->_scene->getBackgroundSurface();
+ // Loop checks for any prior animation sprite slots to be expired
+ for (int slotIndex = 0; slotIndex < _view->_spriteSlots.startIndex; ++slotIndex) {
+ if (_view->_spriteSlots[slotIndex].seqIndex >= 0x80) {
+ // Flag the frame as animation sprite slot
+ _view->_spriteSlots[slotIndex].spriteType = EXPIRED_SPRITE;
+ }
+ }
- while (_frameEntries[_curFrameEntry].animFrameIndex == _curFrame) {
- AnimationFrame *frame = &_frameEntries[_curFrameEntry];
- int seriesFrameIndex = (frame->seriesFrameIndex & 0x7FFF) - 1;
+ // Validate the current frame
+ if (_currentFrame >= (int)_miscEntries.size()) {
+ // Is the animation allowed to be repeated?
+ if (_resetFlag) {
+ _currentFrame = 0;
+ _oldFrameEntry = 0;
+ } else {
+ _freeFlag = true;
+ return;
+ }
+ }
- // Write the sprite onto the screen
- M4Sprite *spr = _spriteSeries->getFrame(seriesFrameIndex);
+ // Handle starting any sound for this frame
+ AnimMiscEntry &misc = _miscEntries[_currentFrame];
+ if (misc.soundNum)
+ _vm->_sound->playSound(misc.soundNum);
- // FIXME: correct x, y
- spr->copyTo(bg, frame->x, frame->y, (int)spr->getTransparentColor());
+ bool screenChanged = false;
- // HACK: wait a bit
- g_system->delayMillis(100);
+ // Handle any scrolling of the screen surface
+ if ((_scrollX != 0) || (_scrollY != 0)) {
+ _view->_bgSurface->scrollX(_scrollX);
+ _view->_bgSurface->scrollY(_scrollY);
- //printf("_curFrameEntry = %d\n", _curFrameEntry);
- _curFrameEntry++;
+ screenChanged = true;
}
- //printf("_curFrame = %d\n", _curFrame);
+ // Handle any offset adjustment for sprites as of this frame
+ if (_view->_posAdjust.x != misc.posAdjust.x) {
+ misc.posAdjust.x = _view->_posAdjust.x;
+ screenChanged = true;
+ }
+ if (_view->_posAdjust.y != misc.posAdjust.y) {
+ misc.posAdjust.y = _view->_posAdjust.y;
+ screenChanged = true;
+ }
+ if (screenChanged) {
+ // Signal the entire screen needs refreshing
+ _view->_spriteSlots.fullRefresh();
+ }
- _curFrame++;
- if (_curFrame >= _frameCount) // anim done
- stop();
+ int spriteSlotsMax = _view->_spriteSlots.startIndex;
+
+ // Main frame animation loop - frames get animated by being placed, as necessary, into the
+ // main sprite slot array
+ while ((uint)_oldFrameEntry < _frameEntries.size()) {
+ if (_frameEntries[_oldFrameEntry].frameNumber > _currentFrame)
+ break;
+ else if (_frameEntries[_oldFrameEntry].frameNumber == _currentFrame) {
+ // Found the correct frame
+ int spriteSlotIndex = 0;
+ int index = 0;
+
+ for (;;) {
+ if ((spriteSlotIndex == 0) && (index < spriteSlotsMax)) {
+ int seqIndex = _frameEntries[_oldFrameEntry].seqIndex - _view->_spriteSlots[index].seqIndex;
+ if (seqIndex == 0x80) {
+ if (_view->_spriteSlots[index] == _frameEntries[_oldFrameEntry].spriteSlot) {
+ _view->_spriteSlots[index].spriteType = SPRITE_ZERO;
+ spriteSlotIndex = -1;
+ }
+ }
+ ++index;
+ continue;
+ }
+
+ if (spriteSlotIndex == 0) {
+ int slotIndex = _view->_spriteSlots.getIndex();
+ MadsSpriteSlot &slot = _view->_spriteSlots[slotIndex];
+ slot.copy(_frameEntries[_oldFrameEntry].spriteSlot);
+ slot.seqIndex = _frameEntries[_oldFrameEntry].seqIndex + 0x80;
+
+ SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(
+ _view->_spriteSlots[slotIndex].spriteListIndex);
+ slot.spriteType = spriteSet.isBackground() ? BACKGROUND_SPRITE : FOREGROUND_SPRITE;
+ }
+ break;
+ }
+ }
+
+ ++_oldFrameEntry;
+ }
+
+ // Handle the display of any messages
+ for (uint idx = 0; idx < _messages.size(); ++idx) {
+ if (_messages[idx].kernelMsgIndex >= 0) {
+ // Handle currently active message
+ if ((_currentFrame < _messages[idx].startFrame) || (_currentFrame > _messages[idx].endFrame)) {
+ _view->_kernelMessages.remove(_messages[idx].kernelMsgIndex);
+ _messages[idx].kernelMsgIndex = -1;
+ --_messageCtr;
+ }
+ } else if ((_currentFrame >= _messages[idx].startFrame) && (_currentFrame <= _messages[idx].endFrame)) {
+ // Start displaying the message
+ AnimMessage &me = _messages[idx];
+
+ // The colour index to use is dependant on how many messages are currently on-screen
+ uint8 colIndex;
+ switch (_messageCtr) {
+ case 1:
+ colIndex = 252;
+ break;
+ case 2:
+ colIndex = 16;
+ break;
+ default:
+ colIndex = 250;
+ break;
+ }
+
+ _vm->_palette->setEntry(colIndex, me.rgb1.r, me.rgb1.g, me.rgb1.b);
+ _vm->_palette->setEntry(colIndex + 1, me.rgb2.r, me.rgb2.g, me.rgb2.b);
+
+ // Add a kernel message to display the given text
+ me.kernelMsgIndex = _view->_kernelMessages.add(me.pos, colIndex * 101, 0, 0, INDEFINITE_TIMEOUT, me.msg);
+ ++_messageCtr;
+ }
+ }
+
+ // Move to the next frame
+ _currentFrame++;
+ if (_currentFrame >= (int)_miscEntries.size()) {
+ // Animation is complete
+ if (_abortTimers != 0) {
+ _view->_abortTimers = _abortTimers;
+ _view->_abortTimersMode = _abortMode;
+
+ if (_abortMode != ABORTMODE_1) {
+ // Copy the noun list
+ for (int i = 0; i < 3; ++i)
+ _madsVm->scene()->actionNouns[i] = _actionNouns[i];
+ }
+ }
+ }
- return _curFrame >= _frameCount;
+ int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1);
+ _nextFrameTimer = _madsVm->_currentTimer + _miscEntries[frameNum].numTicks;
}
-void Animation::stop() {
- _playing = false;
+void MadsAnimation::setCurrentFrame(int frameNumber) {
+ _currentFrame = frameNumber;
+ _oldFrameEntry = 0;
+ _freeFlag = false;
+}
+
+void MadsAnimation::load1(int frameNumber) {
+ if (_skipLoad)
+ return;
+
+ Common::Point pt;
+ int listIndex = _spriteListIndexes[_spriteListIndex];
+ SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(listIndex);
+
+ if (_unkIndex < 0) {
+ M4Surface *frame = spriteSet.getFrame(0);
+ pt.x = frame->bounds().left;
+ pt.y = frame->bounds().top;
+ } else {
+ pt.x = _unkList[_unkIndex].x;
+ pt.y = _unkList[_unkIndex].y;
+ _unkIndex = 1 - _unkIndex;
+ }
+
+ if (proc1(spriteSet, pt, frameNumber))
+ error("proc1 failure");
+}
+
+bool MadsAnimation::proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber) {
+ return 0;
+}
- for (int i = 0; i < _seriesCount; i++) {
- // TODO: cleanup
- //delete _spriteSeries[i];
- //_spriteSeries[i] = NULL;
+void MadsAnimation::loadInterface(M4Surface *&interfaceSurface, M4Surface *&depthSurface) {
+ if (_animMode <= 2) {
+ MadsSceneResources sceneResources;
+ sceneResources.load(_roomNumber, _interfaceFile.c_str(), 0, depthSurface, interfaceSurface);
+
+ } else if (_animMode == 4) {
+ // Load a scene interface
+ interfaceSurface->madsLoadInterface(_interfaceFile);
+ } else {
+ // This mode allocates two large surfaces for the animation
+ // TODO: Are these ever properly freed?
+error("Anim mode %d - need to check free logic", _animMode);
+ assert(!interfaceSurface);
+ assert(!depthSurface);
+ depthSurface = new M4Surface(MADS_SURFACE_WIDTH, MADS_SCREEN_HEIGHT);
+ interfaceSurface = new M4Surface(MADS_SURFACE_WIDTH, MADS_SCREEN_HEIGHT);
+ depthSurface->clear();
+ interfaceSurface->clear();
}
}
diff --git a/engines/m4/animation.h b/engines/m4/animation.h
index c8be7f5cb3..5c7227a256 100644
--- a/engines/m4/animation.h
+++ b/engines/m4/animation.h
@@ -29,39 +29,92 @@
#include "m4/m4.h"
#include "m4/graphics.h"
#include "m4/assets.h"
+#include "m4/mads_views.h"
+#include "common/array.h"
namespace M4 {
-struct AnimationFrame {
- uint16 animFrameIndex;
- byte u;
- byte seriesIndex;
- uint16 seriesFrameIndex;
- uint16 x, y;
- byte v, w;
+class MadsView;
+class SpriteSlotSubset;
+
+class AnimMessage {
+public:
+ char msg[70];
+ Common::Point pos;
+ RGB8 rgb1, rgb2;
+ int kernelMsgIndex;
+
+ int startFrame, endFrame;
+};
+
+class AnimFrameEntry {
+public:
+ int frameNumber;
+ int seqIndex;
+ SpriteSlotSubset spriteSlot;
};
-class Animation {
- public:
- Animation(MadsM4Engine *vm);
- ~Animation();
-
- void load(const char *filename);
- void loadFullScreen(const char *filename);
- void start();
- bool updateAnim();
- void stop();
-
- private:
- bool _playing;
- MadsM4Engine *_vm;
- int _seriesCount;
- int _frameCount;
- int _frameEntryCount;
- AnimationFrame *_frameEntries;
- Common::String *_spriteSeriesNames;
- SpriteAsset *_spriteSeries;
- int _curFrame, _curFrameEntry;
+class AnimMiscEntry {
+public:
+ int soundNum;
+ int numTicks;
+ Common::Point posAdjust;
+};
+
+#define ANIM_SPRITE_SET_SIZE 50
+
+enum MadsAnimationFlags {ANIM_CUSTOM_FONT = 0x20, ANIM_HAS_SOUND = 0x8000};
+
+class MadsAnimation: public Animation {
+private:
+ MadsView *_view;
+
+ int _spriteListCount;
+ Common::Array<AnimMessage> _messages;
+ Common::Array<AnimFrameEntry> _frameEntries;
+ Common::Array<AnimMiscEntry> _miscEntries;
+ Font *_font;
+
+ uint8 _flags;
+ int _animMode;
+ int _roomNumber;
+ bool _field12;
+ int _spriteListIndex;
+ int _scrollX;
+ int _scrollY;
+ Common::String _interfaceFile;
+ Common::String _spriteSetNames[10];
+ Common::String _lbmFilename;
+ Common::String _spritesFilename;
+ Common::String _soundName;
+ Common::Array<int> _spriteListIndexes;
+
+ int _currentFrame, _oldFrameEntry;
+ bool _resetFlag;
+ bool _freeFlag;
+ bool _skipLoad;
+ int _unkIndex;
+ Common::Point _unkList[2];
+ uint32 _nextFrameTimer;
+ int _messageCtr;
+ int _abortTimers;
+ AbortTimerMode _abortMode;
+ uint16 _actionNouns[3];
+
+ void load1(int frameNumber);
+ bool proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber);
+ void loadInterface(M4Surface *&interfaceSurface, M4Surface *&depthSurface);
+public:
+ MadsAnimation(MadsM4Engine *vm, MadsView *view);
+ virtual ~MadsAnimation();
+
+ virtual void initialise(const Common::String &filename, uint16 flags, M4Surface *interfaceSurface, M4Surface *sceneSurface);
+ virtual void load(const Common::String &filename, int abortTimers);
+ virtual void update();
+ virtual void setCurrentFrame(int frameNumber);
+
+ bool freeFlag() const { return _freeFlag; }
+ int roomNumber() const { return _roomNumber; }
};
} // End of namespace M4
diff --git a/engines/m4/assets.cpp b/engines/m4/assets.cpp
index 14857e6f2b..1f3cf278ae 100644
--- a/engines/m4/assets.cpp
+++ b/engines/m4/assets.cpp
@@ -30,13 +30,13 @@
namespace M4 {
-BaseAsset::BaseAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : _vm(vm) {
+BaseAsset::BaseAsset(MadsM4Engine *vm) : _vm(vm) {
}
BaseAsset::~BaseAsset() {
}
-MachineAsset::MachineAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
+MachineAsset::MachineAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm) {
uint32 stateCount = stream->readUint32LE();
for (uint32 curState = 0; curState < stateCount; curState++) {
uint32 stateOffset = stream->readUint32LE();
@@ -61,7 +61,7 @@ uint32 MachineAsset::getStateOffset(uint32 state) {
return _stateTable[state];
}
-SequenceAsset::SequenceAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
+SequenceAsset::SequenceAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm) {
_localVarCount = stream->readUint32LE();
_codeSize = size - 4;
_code = new byte[_codeSize];
@@ -78,7 +78,7 @@ void SequenceAsset::getCode(byte *&code, uint32 &codeSize) {
}
-DataAsset::DataAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
+DataAsset::DataAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm) {
_recCount = stream->readUint32LE();
_recSize = stream->readUint32LE();
@@ -98,7 +98,8 @@ long *DataAsset::getRow(int index) {
return &_data[_recSize * index];
}
-SpriteAsset::SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream) : BaseAsset(vm, stream, size, name) {
+SpriteAsset::SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream) :
+ BaseAsset(vm) {
_stream = stream;
_palInterface = NULL;
_paletteData = NULL;
@@ -110,6 +111,20 @@ SpriteAsset::SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, i
}
}
+SpriteAsset::SpriteAsset(MadsM4Engine *vm, const char *name): BaseAsset(vm) {
+ _stream = vm->res()->get(name);
+ _palInterface = NULL;
+ _paletteData = NULL;
+
+ if (_vm->isM4()) {
+ loadM4SpriteAsset(vm, _stream, true);
+ } else {
+ loadMadsSpriteAsset(vm, _stream);
+ }
+
+ vm->res()->toss(name);
+}
+
SpriteAsset::~SpriteAsset() {
if (_palInterface) {
// Internally stored palette translation data, so release it
@@ -195,11 +210,12 @@ void SpriteAsset::loadMadsSpriteAsset(MadsM4Engine *vm, Common::SeekableReadStre
_maxHeight = 0;
Common::SeekableReadStream *spriteStream = sprite.getItemStream(0);
-
- _assetType = spriteStream->readUint16LE();
- for (int i = 0; i < 18; i++) {
- spriteStream->readUint16LE();
- }
+ _mode = spriteStream->readByte();
+ spriteStream->skip(1);
+ int type1 = spriteStream->readUint16LE();
+ int type2 = spriteStream->readUint16LE();
+ _isBackground = (type1 != 0) && (type2 < 4);
+ spriteStream->skip(32);
_frameCount = spriteStream->readUint16LE();
// we skip the rest of the data
delete spriteStream;
diff --git a/engines/m4/assets.h b/engines/m4/assets.h
index cd0ae6ba78..e5beffbcae 100644
--- a/engines/m4/assets.h
+++ b/engines/m4/assets.h
@@ -49,7 +49,7 @@ class Palette;
class BaseAsset {
public:
- BaseAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name);
+ BaseAsset(MadsM4Engine *vm);
~BaseAsset();
const Common::String getName() const { return _name; }
protected:
@@ -103,6 +103,7 @@ struct SpriteAssetFrame {
class SpriteAsset : public BaseAsset {
public:
SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream = false);
+ SpriteAsset(MadsM4Engine *vm, const char *name);
~SpriteAsset();
void loadM4SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, bool asStream);
void loadMadsSpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream);
@@ -113,7 +114,7 @@ public:
int32 getFrameHeight(int index);
int32 getMaxFrameWidth() const { return _maxWidth; }
int32 getMaxFrameHeight() const { return _maxHeight; }
- uint16 getAssetType() const { return _assetType; }
+ bool isBackground() const { return _isBackground; }
M4Sprite *getFrame(int frameIndex);
void loadStreamingFrame(M4Sprite *frame, int frameIndex, int destX, int destY);
RGB8* getPalette() { return _palette; }
@@ -136,7 +137,8 @@ protected:
uint32 _frameStartOffset;
// MADS sprite set fields
- uint16 _assetType;
+ uint8 _mode;
+ bool _isBackground;
int32 parseSprite(bool isBigEndian = false);
void loadFrameHeader(SpriteAssetFrame &frameHeader, bool isBigEndian = false);
diff --git a/engines/m4/compression.h b/engines/m4/compression.h
index 74fed357ff..00e3d1f927 100644
--- a/engines/m4/compression.h
+++ b/engines/m4/compression.h
@@ -66,8 +66,8 @@ public:
class FabDecompressor {
private:
- int _bitsLeft;
- uint32 _bitBuffer;
+ int _bitsLeft;
+ uint32 _bitBuffer;
const byte *_srcData, *_srcP;
int _srcSize;
diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp
index 0c2e80df0e..4e14afdfaf 100644
--- a/engines/m4/console.cpp
+++ b/engines/m4/console.cpp
@@ -47,7 +47,6 @@ Console::Console(MadsM4Engine *vm) : GUI::Debugger() {
DCmd_Register("start_conv", WRAP_METHOD(Console, cmdStartConversation));
DCmd_Register("textview", WRAP_METHOD(Console, cmdShowTextview));
DCmd_Register("animview", WRAP_METHOD(Console, cmdShowAnimview));
- DCmd_Register("anim", WRAP_METHOD(Console, cmdPlayAnimation));
}
Console::~Console() {
@@ -247,33 +246,6 @@ bool Console::cmdShowAnimview(int argc, const char **argv) {
return false;
}
-bool Console::cmdPlayAnimation(int argc, const char **argv) {
- View *view = _vm->_viewManager->getView(VIEWID_SCENE);
- if (view == NULL) {
- DebugPrintf("The scene view isn't currently active\n");
- } else if (argc != 2 && argc != 3) {
- DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
- DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
- } else {
- char resourceName[20];
- strncpy(resourceName, argv[1], 15);
- resourceName[15] = '\0';
- if (!strchr(resourceName, '.'))
- strcat(resourceName, ".AA");
-
- _vm->_viewManager->moveToFront(view);
- if (argc == 3 && atoi(argv[2]) == 1)
- _vm->_animation->loadFullScreen(resourceName);
- else
- _vm->_animation->load(resourceName);
- _vm->_animation->start();
- view->restore(0, 0, view->width(), view->height());
- return false;
- }
-
- return true;
-}
-
/*--------------------------------------------------------------------------*/
MadsConsole::MadsConsole(MadsEngine *vm): Console(vm) {
@@ -282,6 +254,7 @@ MadsConsole::MadsConsole(MadsEngine *vm): Console(vm) {
DCmd_Register("object", WRAP_METHOD(MadsConsole, cmdObject));
DCmd_Register("message", WRAP_METHOD(MadsConsole, cmdMessage));
DCmd_Register("scene_info", WRAP_METHOD(MadsConsole, cmdSceneInfo));
+ DCmd_Register("anim", WRAP_METHOD(MadsConsole, cmdPlayAnimation));
}
bool MadsConsole::cmdObject(int argc, const char **argv) {
@@ -386,6 +359,33 @@ bool MadsConsole::cmdSceneInfo(int argc, const char **argv) {
return true;
}
+bool MadsConsole::cmdPlayAnimation(int argc, const char **argv) {
+ View *view = _vm->_viewManager->getView(VIEWID_SCENE);
+ if (view == NULL) {
+ DebugPrintf("The scene view isn't currently active\n");
+ } else if (argc != 2 && argc != 3) {
+ DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
+ DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
+ } else {
+ char resourceName[20];
+ strncpy(resourceName, argv[1], 15);
+ resourceName[15] = '\0';
+ if (!strchr(resourceName, '.'))
+ strcat(resourceName, ".AA");
+
+ _vm->_viewManager->moveToFront(view);
+ if (argc == 3 && atoi(argv[2]) == 1)
+ _madsVm->_palette->deleteAllRanges();
+
+ _madsVm->scene()->_sceneAnimation->load(resourceName, 0);
+
+ view->restore(0, 0, view->width(), view->height());
+ return false;
+ }
+
+ return true;
+}
+
/*--------------------------------------------------------------------------*/
M4Console::M4Console(M4Engine *vm): Console(vm) {
diff --git a/engines/m4/console.h b/engines/m4/console.h
index b592f041cf..53a47dada9 100644
--- a/engines/m4/console.h
+++ b/engines/m4/console.h
@@ -50,7 +50,6 @@ private:
bool cmdStartConversation(int argc, const char **argv);
bool cmdShowTextview(int argc, const char **argv);
bool cmdShowAnimview(int argc, const char **argv);
- bool cmdPlayAnimation(int argc, const char **argv);
public:
Console(MadsM4Engine *vm);
@@ -64,6 +63,8 @@ private:
bool cmdObject(int argc, const char **argv);
bool cmdMessage(int argc, const char **argv);
bool cmdSceneInfo(int argc, const char **argv);
+ bool cmdPlayAnimation(int argc, const char **argv);
+
public:
MadsConsole(MadsEngine *vm);
virtual ~MadsConsole() {}
diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp
index 746ced5d11..11bc165811 100644
--- a/engines/m4/converse.cpp
+++ b/engines/m4/converse.cpp
@@ -96,7 +96,7 @@ void ConversationView::setNode(int32 nodeIndex) {
_vm->_font->setFont(FONT_CONVERSATION);
// TODO: Conversation styles and colors
- _vm->_font->setColors(2, 1, 3);
+ _vm->_font->current()->setColours(2, 1, 3);
_currentNodeIndex = nodeIndex;
@@ -124,7 +124,7 @@ void ConversationView::setNode(int32 nodeIndex) {
}
// Figure out the longest string to determine where option highlighting ends
- int tempX = _vm->_font->getWidth(node->entries[i]->text, 0) +
+ int tempX = _vm->_font->current()->getWidth(node->entries[i]->text, 0) +
CONV_ENTRIES_X_OFFSET + 10;
_xEnd = MAX(_xEnd, tempX);
}
@@ -163,10 +163,10 @@ void ConversationView::onRefresh(RectList *rects, M4Surface *destSurface) {
if (i > CONV_MAX_SHOWN_ENTRIES - 1)
break;
- _vm->_font->setColor((_highlightedIndex == i) ? CONVERSATION_ENTRY_HIGHLIGHTED :
+ _vm->_font->current()->setColour((_highlightedIndex == i) ? CONVERSATION_ENTRY_HIGHLIGHTED :
CONVERSATION_ENTRY_NORMAL);
- _vm->_font->writeString(this, _activeItems[i]->text, CONV_ENTRIES_X_OFFSET,
+ _vm->_font->current()->writeString(this, _activeItems[i]->text, CONV_ENTRIES_X_OFFSET,
CONV_ENTRIES_Y_OFFSET + CONV_ENTRIES_HEIGHT * i, 0, 0);
}
}
diff --git a/engines/m4/dialogs.cpp b/engines/m4/dialogs.cpp
index 3af94af262..a7104537f5 100644
--- a/engines/m4/dialogs.cpp
+++ b/engines/m4/dialogs.cpp
@@ -127,7 +127,7 @@ void Dialog::writeChars(const char *srcLine) {
strcat(line, wordStr);
lineLen = strlen(line);
- lineWidth = _vm->_font->getWidth(line, DIALOG_SPACING);
+ lineWidth = _vm->_font->current()->getWidth(line, DIALOG_SPACING);
if (((_lineX + lineLen) > _widthChars) || ((_widthX + lineWidth) > _dialogWidth)) {
incLine();
@@ -146,7 +146,7 @@ void Dialog::writeChars(const char *srcLine) {
*/
void Dialog::appendText(const char *line) {
_lineX += strlen(line);
- _widthX += _vm->_font->getWidth(line, DIALOG_SPACING);
+ _widthX += _vm->_font->current()->getWidth(line, DIALOG_SPACING);
strcat(_lines[_lines.size() - 1].data, line);
}
@@ -158,7 +158,7 @@ void Dialog::addLine(const char *line, bool underlineP) {
if ((_widthX > 0) || (_lineX > 0))
incLine();
- int lineWidth = _vm->_font->getWidth(line, DIALOG_SPACING);
+ int lineWidth = _vm->_font->current()->getWidth(line, DIALOG_SPACING);
int lineLen = strlen(line);
if ((lineWidth > _dialogWidth) || (lineLen >= _widthChars))
@@ -383,7 +383,7 @@ Dialog::Dialog(MadsM4Engine *vm, const char *msgData, const char *title): View(v
if (id > 0) {
// Suffix provided - specifies the dialog width in number of chars
_widthChars = id * 2;
- _dialogWidth = id * (_vm->_font->getMaxWidth() + DIALOG_SPACING) + 10;
+ _dialogWidth = id * (_vm->_font->current()->getMaxWidth() + DIALOG_SPACING) + 10;
}
} else if (matchCommand(cmdText, "UNDER")) {
@@ -416,7 +416,7 @@ Dialog::Dialog(MadsM4Engine *vm, const char *msgData, const char *title): View(v
Dialog::Dialog(MadsM4Engine *vm, int widthChars): View(vm, Common::Rect(0, 0, 0, 0)) {
_vm->_font->setFont(FONT_INTERFACE_MADS);
_widthChars = widthChars * 2;
- _dialogWidth = widthChars * (_vm->_font->getMaxWidth() + DIALOG_SPACING) + 10;
+ _dialogWidth = widthChars * (_vm->_font->current()->getMaxWidth() + DIALOG_SPACING) + 10;
_screenType = LAYER_DIALOG;
_lineX = 0;
_widthX = 0;
@@ -439,7 +439,7 @@ void Dialog::draw() {
// Calculate bounds
int dlgWidth = _dialogWidth;
- int dlgHeight = _lines.size() * (_vm->_font->getHeight() + 1) + 10;
+ int dlgHeight = _lines.size() * (_vm->_font->current()->getHeight() + 1) + 10;
int dialogX = (_vm->_screen->width() - dlgWidth) / 2;
int dialogY = (_vm->_screen->height() - dlgHeight) / 2;
@@ -480,26 +480,26 @@ void Dialog::draw() {
}
// Handle drawing the text contents
- _vm->_font->setColours(7, 7, 7);
+ _vm->_font->current()->setColours(7, 7, 7);
setColour(7);
- for (uint lineCtr = 0, yp = 5; lineCtr < _lines.size(); ++lineCtr, yp += _vm->_font->getHeight() + 1) {
+ for (uint lineCtr = 0, yp = 5; lineCtr < _lines.size(); ++lineCtr, yp += _vm->_font->current()->getHeight() + 1) {
if (_lines[lineCtr].barLine) {
// Bar separation line
- hLine(5, width() - 6, ((_vm->_font->getHeight() + 1) >> 1) + yp);
+ hLine(5, width() - 6, ((_vm->_font->current()->getHeight() + 1) >> 1) + yp);
} else {
// Standard line
Common::Point pt(_lines[lineCtr].xp + 5, yp);
if (_lines[lineCtr].xp & 0x40)
++pt.y;
- _vm->_font->writeString(this, _lines[lineCtr].data, pt.x, pt.y, 0, DIALOG_SPACING);
+ _vm->_font->current()->writeString(this, _lines[lineCtr].data, pt.x, pt.y, 0, DIALOG_SPACING);
if (_lines[lineCtr].underline)
// Underline needed
- hLine(pt.x, pt.x + _vm->_font->getWidth(_lines[lineCtr].data, DIALOG_SPACING),
- pt.y + _vm->_font->getHeight());
+ hLine(pt.x, pt.x + _vm->_font->current()->getWidth(_lines[lineCtr].data, DIALOG_SPACING),
+ pt.y + _vm->_font->current()->getHeight());
}
}
@@ -528,7 +528,7 @@ void Dialog::display(MadsM4Engine *vm, int widthChars, const char **descEntries)
dlg->incLine();
dlg->writeChars(*descEntries);
- int lineWidth = vm->_font->getWidth(*descEntries, DIALOG_SPACING);
+ int lineWidth = vm->_font->current()->getWidth(*descEntries, DIALOG_SPACING);
dlg->_lines[dlg->_lines.size() - 1].xp = (dlg->_dialogWidth - 10 - lineWidth) / 2;
++descEntries;
}
diff --git a/engines/m4/font.cpp b/engines/m4/font.cpp
index f8dec65412..4afa158976 100644
--- a/engines/m4/font.cpp
+++ b/engines/m4/font.cpp
@@ -29,28 +29,46 @@
namespace M4 {
-Font::Font(MadsM4Engine *vm) : _vm(vm) {
+FontManager::~FontManager() {
+ for (uint i = 0; i < _entries.size(); ++i)
+ delete _entries[i];
+ _entries.clear();
+}
+
+Font *FontManager::getFont(const Common::String &filename) {
+ // Check if the font is already loaded
+ for (uint i = 0; i < _entries.size(); ++i)
+ {
+ if (_entries[i]->_filename.equals(filename))
+ return _entries[i];
+ }
+
+ Font *f = new Font(_vm, filename);
+ _entries.push_back(f);
+ return f;
+}
+
+void FontManager::setFont(const Common::String &filename) {
+ _currentFont = getFont(filename);
+}
+
+//--------------------------------------------------------------------------
+
+Font::Font(MadsM4Engine *vm, const Common::String &filename) : _vm(vm), _filename(filename) {
_sysFont = true;
- _filename = NULL;
+
//TODO: System font
_fontColors[0] = _vm->_palette->BLACK;
_fontColors[1] = _vm->_palette->WHITE;
_fontColors[2] = _vm->_palette->BLACK;
_fontColors[3] = _vm->_palette->DARK_GRAY;
-}
-
-void Font::setFont(const char *filename) {
- if ((_filename != NULL) && (strcmp(filename, _filename) == 0))
- // Already using specified font, so don't bother reloading
- return;
_sysFont = false;
- _filename = filename;
if (_vm->isM4())
- setFontM4(filename);
+ setFontM4(filename.c_str());
else
- setFontMads(filename);
+ setFontMads(filename.c_str());
}
void Font::setFontM4(const char *filename) {
@@ -134,20 +152,21 @@ Font::~Font() {
}
}
-void Font::setColor(uint8 color) {
+void Font::setColour(uint8 colour) {
if (_sysFont)
- _fontColors[1] = color;
+ _fontColors[1] = colour;
else
- _fontColors[3] = color;
+ _fontColors[3] = colour;
}
-void Font::setColors(uint8 alt1, uint8 alt2, uint8 foreground) {
+void Font::setColours(uint8 col1, uint8 col2, uint8 col3) {
if (_sysFont)
- _fontColors[1] = foreground;
+ _fontColors[1] = col3;
else {
- _fontColors[1] = alt1;
- _fontColors[2] = alt2;
- _fontColors[3] = foreground;
+ _fontColors[0] = 0xFF;
+ _fontColors[1] = col1;
+ _fontColors[2] = col2;
+ _fontColors[3] = col3;
}
}
diff --git a/engines/m4/font.h b/engines/m4/font.h
index e64f80b70d..ca47848c61 100644
--- a/engines/m4/font.h
+++ b/engines/m4/font.h
@@ -59,19 +59,11 @@ namespace M4 {
class Font {
public:
- Font(MadsM4Engine *vm);
+ Font(MadsM4Engine *vm, const Common::String &filename);
~Font();
- Font *getFont(const char *filename) {
- // TODO: Proper separation of font instances
- setFont(filename);
- return this;
- }
- void setFont(const char *filename);
- void setColor(uint8 color);
- void setColors(uint8 alt1, uint8 alt2, uint8 foreground);
- void setColour(uint8 colour) { setColor(colour); }
- void setColours(uint8 alt1, uint8 alt2, uint8 foreground) { setColors(alt1, alt2, foreground); }
+ void setColour(uint8 colour);
+ void setColours(uint8 col1, uint8 col2, uint8 col3);
int32 getWidth(const char *text, int spaceWidth = -1);
int32 getHeight() const { return _maxHeight; }
@@ -80,7 +72,8 @@ public:
int32 writeString(M4Surface *surface, const char *text, int x, int y, int width = 0, int spaceWidth = -1) {
return write(surface, text, x, y, width, spaceWidth, _fontColors);
}
-
+public:
+ const Common::String _filename;
private:
void setFontM4(const char *filename);
void setFontMads(const char *filename);
@@ -91,10 +84,39 @@ private:
uint16 *_charOffs;
uint8 *_charData;
bool _sysFont;
- const char *_filename;
uint8 _fontColors[4];
};
+class FontEntry {
+public:
+ Font *_font;
+
+ FontEntry() {
+ _font = NULL;
+ }
+ ~FontEntry() {
+ delete _font;
+ }
+};
+
+class FontManager {
+private:
+ MadsM4Engine *_vm;
+ Common::Array<Font *> _entries;
+ Font *_currentFont;
+public:
+ FontManager(MadsM4Engine *vm): _vm(vm) { _currentFont = NULL; }
+ ~FontManager();
+
+ Font *getFont(const Common::String &filename);
+ void setFont(const Common::String &filename);
+
+ Font *current() {
+ assert(_currentFont);
+ return _currentFont;
+ }
+};
+
} // End of namespace M4
#endif
diff --git a/engines/m4/graphics.cpp b/engines/m4/graphics.cpp
index fa0cd7ccd3..8624f18da1 100644
--- a/engines/m4/graphics.cpp
+++ b/engines/m4/graphics.cpp
@@ -69,6 +69,13 @@ void RGBList::setRange(int start, int count, const RGB8 *src) {
#define VGA_COLOR_TRANS(x) (x == 0x3f ? 255 : x << 2)
+M4Surface::~M4Surface() {
+ if (_rgbList) {
+ _madsVm->_palette->deleteRange(_rgbList);
+ delete _rgbList;
+ }
+}
+
void M4Surface::loadCodesM4(Common::SeekableReadStream *source) {
if (!source) {
free();
@@ -472,9 +479,18 @@ void M4Surface::loadBackground(int sceneNumber, RGBList **palData) {
if (_vm->getGameType() == GType_RexNebular) {
// Load Rex Nebular screen
+ bool hasPalette = palData != NULL;
+ if (!hasPalette)
+ palData = &_rgbList;
+
sprintf(resourceName, "rm%d.art", sceneNumber);
stream = _vm->_resourceManager->get(resourceName);
rexLoadBackground(stream, palData);
+
+ if (!hasPalette) {
+ _vm->_palette->addRange(_rgbList);
+ this->translate(_rgbList);
+ }
} else {
// Loads M4 game scene
if (palData)
@@ -617,16 +633,6 @@ void M4Surface::rexLoadBackground(Common::SeekableReadStream *source, RGBList **
int sceneWidth = sourceUnc->readUint16LE();
int sceneHeight = sourceUnc->readUint16LE();
int sceneSize = sceneWidth * sceneHeight;
- if (sceneWidth > this->width()) {
- warning("Background width is %i, too large to fit in screen. Setting it to %i", sceneWidth, this->width());
- sceneWidth = this->width();
- sceneSize = sceneWidth * sceneHeight;
- }
- if (sceneHeight > this->height()) {
- warning("Background height is %i, too large to fit in screen.Setting it to %i", sceneHeight, this->height());
- sceneHeight = this->height();
- sceneSize = sceneWidth * sceneHeight;
- }
// Set palette
if (!palData) {
@@ -642,6 +648,7 @@ void M4Surface::rexLoadBackground(Common::SeekableReadStream *source, RGBList **
sourceUnc = packData.getItemStream(1);
assert((int)sourceUnc->size() >= sceneSize);
+ create(sceneWidth, sceneHeight, 1);
byte *pData = (byte *)pixels;
sourceUnc->read(pData, sceneSize);
@@ -711,10 +718,8 @@ void M4Surface::m4LoadBackground(Common::SeekableReadStream *source) {
delete tileBuffer;
}
-void M4Surface::madsloadInterface(int index, RGBList **palData) {
- char resourceName[20];
- sprintf(resourceName, "i%d.int", index);
- MadsPack intFile(resourceName, _vm);
+void M4Surface::madsLoadInterface(const Common::String &filename) {
+ MadsPack intFile(filename.c_str(), _vm);
RGB8 *palette = new RGB8[16];
// Chunk 0, palette
@@ -728,7 +733,7 @@ void M4Surface::madsloadInterface(int index, RGBList **palData) {
intStream->readByte();
intStream->readByte();
}
- *palData = new RGBList(16, palette, true);
+ _rgbList = new RGBList(16, palette, true);
delete intStream;
// Chunk 1, data
@@ -736,8 +741,77 @@ void M4Surface::madsloadInterface(int index, RGBList **palData) {
create(320, 44, 1);
intStream->read(pixels, 320 * 44);
delete intStream;
+
+ // Translate the interface palette
+ _vm->_palette->addRange(_rgbList);
+ this->translate(_rgbList);
}
+void M4Surface::scrollX(int xAmount) {
+ if (xAmount == 0)
+ return;
+
+ byte buffer[80];
+ int direction = (xAmount > 0) ? 1 : -1;
+ int xSize = ABS(xAmount);
+ assert(xSize <= 80);
+
+ byte *srcP = (byte *)getBasePtr(0, 0);
+
+ for (int y = 0; y < height(); ++y, srcP += pitch) {
+ if (direction < 0) {
+ // Copy area to be overwritten
+ Common::copy(srcP, srcP + xSize, &buffer[0]);
+ // Shift the remainder of the line over the given area
+ Common::copy(srcP + xSize, srcP + width(), srcP);
+ // Move buffered area to the end of the line
+ Common::copy(&buffer[0], &buffer[xSize], srcP + width() - xSize);
+ } else {
+ // Copy area to be overwritten
+ Common::copy_backward(srcP + width() - xSize, srcP + width(), &buffer[80]);
+ // Shift the remainder of the line over the given area
+ Common::copy_backward(srcP, srcP + width() - xSize, srcP + width());
+ // Move buffered area to the start of the line
+ Common::copy_backward(&buffer[80 - xSize], &buffer[80], srcP + xSize);
+ }
+ }
+}
+
+void M4Surface::scrollY(int yAmount) {
+ if (yAmount == 0)
+ return;
+
+ int direction = (yAmount > 0) ? 1 : -1;
+ int ySize = ABS(yAmount);
+ assert(ySize < (height() / 2));
+ assert(width() == pitch);
+
+ int blockSize = ySize * width();
+ byte *tempData = (byte *)malloc(blockSize);
+ byte *pixelsP = (byte *)getBasePtr(0, 0);
+
+ if (direction > 0) {
+ // Buffer the lines to be overwritten
+ byte *srcP = (byte *)getBasePtr(0, height() - ySize);
+ Common::copy(srcP, srcP + (pitch * ySize), tempData);
+ // Vertically shift all the lines
+ Common::copy_backward(pixelsP, pixelsP + (pitch * (height() - ySize)),
+ pixelsP + (pitch * height()));
+ // Transfer the buffered lines top the top of the screen
+ Common::copy(tempData, tempData + blockSize, pixelsP);
+ } else {
+ // Buffer the lines to be overwritten
+ Common::copy(pixelsP, pixelsP + (pitch * ySize), tempData);
+ // Vertically shift all the lines
+ Common::copy(pixelsP + (pitch * ySize), pixelsP + (pitch * height()), pixelsP);
+ // Transfer the buffered lines to the bottom of the screen
+ Common::copy(tempData, tempData + blockSize, pixelsP + (pitch * (height() - ySize)));
+ }
+
+ ::free(tempData);
+}
+
+
void M4Surface::translate(RGBList *list, bool isTransparent) {
byte *p = getBasePtr(0, 0);
byte *palIndexes = list->palIndexes();
diff --git a/engines/m4/graphics.h b/engines/m4/graphics.h
index 6d0a82ad25..8c4b9ac072 100644
--- a/engines/m4/graphics.h
+++ b/engines/m4/graphics.h
@@ -35,6 +35,12 @@
namespace M4 {
+#define MADS_SURFACE_WIDTH 320
+#define MADS_SURFACE_HEIGHT 156
+#define MADS_SCREEN_HEIGHT 200
+#define MADS_Y_OFFSET ((MADS_SCREEN_HEIGHT - MADS_SURFACE_HEIGHT) / 2)
+
+
struct BGR8 {
uint8 b, g, r;
};
@@ -89,19 +95,23 @@ class M4Surface : protected Graphics::Surface {
private:
byte _color;
bool _isScreen;
+ RGBList *_rgbList;
void rexLoadBackground(Common::SeekableReadStream *source, RGBList **palData = NULL);
void madsLoadBackground(int roomNumber, RGBList **palData = NULL);
void m4LoadBackground(Common::SeekableReadStream *source);
public:
M4Surface(bool isScreen = false) {
- create(g_system->getWidth(), g_system->getHeight(), 1);
+ create(g_system->getWidth(), isScreen ? g_system->getHeight() : MADS_SURFACE_HEIGHT, 1);
_isScreen = isScreen;
+ _rgbList = NULL;
}
M4Surface(int width_, int height_) {
create(width_, height_, 1);
_isScreen = false;
+ _rgbList = NULL;
}
+ virtual ~M4Surface();
// loads a .COD file into the M4Surface
// TODO: maybe move this to the rail system? check where it makes sense
@@ -112,7 +122,8 @@ public:
// loads the specified background
void loadBackground(int sceneNumber, RGBList **palData = NULL);
void loadBackgroundRiddle(const char *sceneName);
- void madsloadInterface(int index, RGBList **palData);
+ void madsLoadInterface(int index, RGBList **palData = NULL);
+ void madsLoadInterface(const Common::String &filename);
void setColor(byte value) { _color = value; }
void setColour(byte value) { _color = value; }
@@ -173,7 +184,8 @@ public:
dest->copyFrom(this, destX, destY, depth, depthsSurface, scale, transparentColour);
}
-
+ void scrollX(int xAmount);
+ void scrollY(int yAmount);
void translate(RGBList *list, bool isTransparent = false);
};
diff --git a/engines/m4/gui.cpp b/engines/m4/gui.cpp
index 8f949de9c5..8665b4e767 100644
--- a/engines/m4/gui.cpp
+++ b/engines/m4/gui.cpp
@@ -290,26 +290,26 @@ void MenuButton::onRefresh() {
case OBJTYPE_SL_TEXT:
switch (_objectState) {
case OS_MOUSEOVER:
- _vm->_font->setColors(TEXT_COLOR_MOUSEOVER_SHADOW, TEXT_COLOR_MOUSEOVER_FOREGROUND,
+ _vm->_font->current()->setColours(TEXT_COLOR_MOUSEOVER_SHADOW, TEXT_COLOR_MOUSEOVER_FOREGROUND,
TEXT_COLOR_MOUSEOVER_HILIGHT);
sprite = sprites[SL_LINE_MOUSEOVER];
break;
case OS_PRESSED:
- _vm->_font->setColors(TEXT_COLOR_PRESSED_SHADOW, TEXT_COLOR_PRESSED_FOREGROUND,
+ _vm->_font->current()->setColours(TEXT_COLOR_PRESSED_SHADOW, TEXT_COLOR_PRESSED_FOREGROUND,
TEXT_COLOR_PRESSED_HILIGHT);
sprite = sprites[SL_LINE_PRESSED];
break;
case OS_GREYED:
- _vm->_font->setColors(TEXT_COLOR_GREYED_SHADOW, TEXT_COLOR_GREYED_FOREGROUND,
+ _vm->_font->current()->setColours(TEXT_COLOR_GREYED_SHADOW, TEXT_COLOR_GREYED_FOREGROUND,
TEXT_COLOR_GREYED_HILIGHT);
sprite = sprites[SL_LINE_NORMAL];
break;
default:
case OS_NORMAL:
- _vm->_font->setColors(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
+ _vm->_font->current()->setColours(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
TEXT_COLOR_NORMAL_HILIGHT);
sprite = sprites[SL_LINE_NORMAL];
break;
@@ -849,11 +849,11 @@ void MenuSaveLoadText::onRefresh() {
if (_displayValue != 0) {
char tempBuffer[5];
sprintf(tempBuffer, "%02d", _displayValue);
- _vm->_font->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->current()->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
xp = _bounds.left + 26;
}
- _vm->_font->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->current()->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
}
}
@@ -955,18 +955,18 @@ void MenuTextField::onRefresh() {
// Draw the text
_vm->_font->setFont(FONT_MENU);
- _vm->_font->setColors(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
+ _vm->_font->current()->setColours(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
TEXT_COLOR_NORMAL_HILIGHT);
int xp = _bounds.left + 4;
if (_displayValue != 0) {
char tempBuffer[5];
sprintf(tempBuffer, "%02d", _displayValue);
- _vm->_font->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->current()->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
xp = _bounds.left + 26;
}
- _vm->_font->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->current()->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
if (focused) {
// Draw in the cursor
@@ -975,7 +975,7 @@ void MenuTextField::onRefresh() {
// Get the width of the string up to the cursor position
char tempCh = *_cursor;
*_cursor = '\0';
- int stringWidth = _vm->_font->getWidth(_displayText);
+ int stringWidth = _vm->_font->current()->getWidth(_displayText);
*_cursor = tempCh;
parent()->setColor(TEXT_COLOR_MOUSEOVER_FOREGROUND);
@@ -1015,10 +1015,10 @@ bool MenuTextField::onEvent(M4EventType event, int32 param, int x, int y, MenuOb
tempP = &tempStr[tempLen];
_vm->_font->setFont(FONT_MENU);
- tempLen = _vm->_font->getWidth(tempStr);
+ tempLen = _vm->_font->current()->getWidth(tempStr);
while ((tempP != &tempStr[0]) && (tempLen > x - _bounds.left - 26)) {
*--tempP = '\0';
- tempLen = _vm->_font->getWidth(tempStr);
+ tempLen = _vm->_font->current()->getWidth(tempStr);
}
_cursor = &_displayText[tempP - &tempStr[0]];
@@ -1098,7 +1098,7 @@ bool MenuTextField::onEvent(M4EventType event, int32 param, int x, int y, MenuOb
parent()->_deleteSaveDesc = false;
_vm->_font->setFont(FONT_MENU);
- tempLen = _vm->_font->getWidth(_displayText);
+ tempLen = _vm->_font->current()->getWidth(_displayText);
if ((strlen(_displayText) < MAX_SAVEGAME_NAME - 1) &&
(tempLen < _pixelWidth - 12) && (param >= 32) && (param <= 127)) {
@@ -1140,9 +1140,9 @@ GUITextField::GUITextField(View *owner, const Common::Rect &bounds): GUIRect(own
void GUITextField::onRefresh() {
_parent->fillRect(_bounds, _vm->_palette->BLACK);
- _vm->_font->setColors(3, 3, 3);
+ _vm->_font->current()->setColours(3, 3, 3);
_vm->_font->setFont(FONT_INTERFACE);
- _vm->_font->writeString(_parent, _text.c_str(), _bounds.left, _bounds.top, 0, 1);
+ _vm->_font->current()->writeString(_parent, _text.c_str(), _bounds.left, _bounds.top, 0, 1);
}
//--------------------------------------------------------------------------
diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp
index 897fb468cd..a5db6660d8 100644
--- a/engines/m4/m4.cpp
+++ b/engines/m4/m4.cpp
@@ -145,8 +145,9 @@ MadsM4Engine::~MadsM4Engine() {
delete _script;
delete _ws;
delete _random;
- delete _animation;
delete _palette;
+ delete _globals;
+ delete _resourceManager;
}
Common::Error MadsM4Engine::run() {
@@ -170,7 +171,7 @@ Common::Error MadsM4Engine::run() {
_events = new Events(this);
_kernel = new Kernel(this);
_player = new Player(this);
- _font = new Font(this);
+ _font = new FontManager(this);
if (getGameType() == GType_Burger) {
_actor = new Actor(this);
_conversationView = new ConversationView(this);
@@ -184,7 +185,6 @@ Common::Error MadsM4Engine::run() {
_sound = new Sound(this, _mixer, 255);
_script = new ScriptInterpreter(this);
_ws = new WoodScript(this);
- _animation = new Animation(this);
//_callbacks = new Callbacks(this);
_random = new Common::RandomSource();
g_eventRec.registerRandomSource(*_random, "m4");
@@ -305,8 +305,6 @@ M4Engine::M4Engine(OSystem *syst, const M4GameDescription *gameDesc): MadsM4Engi
}
M4Engine::~M4Engine() {
- delete _resourceManager;
- delete _globals;
delete _converse;
}
@@ -502,8 +500,6 @@ MadsEngine::MadsEngine(OSystem *syst, const M4GameDescription *gameDesc): MadsM4
}
MadsEngine::~MadsEngine() {
- delete _globals;
- delete _resourceManager;
}
Common::Error MadsEngine::run() {
@@ -554,9 +550,9 @@ Common::Error MadsEngine::run() {
_scene->show();
_font->setFont(FONT_MAIN_MADS);
- _font->setColors(2, 1, 3);
- _font->writeString(_scene->getBackgroundSurface(), "Testing the M4/MADS ScummVM engine", 5, 160, 310, 2);
- _font->writeString(_scene->getBackgroundSurface(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 5, 180, 310, 2);
+ _font->current()->setColours(2, 1, 3);
+ _font->current()->writeString(_scene->getBackgroundSurface(), "Testing the M4/MADS ScummVM engine", 5, 160, 310, 2);
+ _font->current()->writeString(_scene->getBackgroundSurface(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 5, 180, 310, 2);
if (getGameType() == GType_DragonSphere) {
//_scene->showMADSV2TextBox("Test", 10, 10, NULL);
@@ -581,8 +577,6 @@ Common::Error MadsEngine::run() {
while (!_events->quitFlag) {
eventHandler();
- _animation->updateAnim();
-
if (g_system->getMillis() >= nextFrame) {
nextFrame = g_system->getMillis() + GAME_FRAME_DELAY;
++_currentTimer;
diff --git a/engines/m4/m4.h b/engines/m4/m4.h
index 1f34bd3685..9937107668 100644
--- a/engines/m4/m4.h
+++ b/engines/m4/m4.h
@@ -189,7 +189,7 @@ public:
Player *_player;
Mouse *_mouse;
Events *_events;
- Font *_font;
+ FontManager *_font;
Actor *_actor;
Scene *_scene;
Dialogs *_dialogs;
@@ -200,7 +200,6 @@ public:
Rails *_rails;
ScriptInterpreter *_script;
WoodScript *_ws;
- Animation *_animation;
Common::RandomSource *_random;
Scene *scene() { return _scene; }
diff --git a/engines/m4/m4_views.cpp b/engines/m4/m4_views.cpp
index 3d633cef0d..f4345787df 100644
--- a/engines/m4/m4_views.cpp
+++ b/engines/m4/m4_views.cpp
@@ -34,7 +34,7 @@ namespace M4 {
GUIInventory::GUIInventory(View *owner, MadsM4Engine *vm, const Common::Rect &bounds, int horizCells,
int vertCells, int cellWidth, int cellHeight, int tag): GUIRect(owner, bounds, tag) {
- _vm = vm;
+ _vm = vm;
_cellCount.x = horizCells;
_cellCount.y = vertCells;
_cellSize.x = cellWidth;
diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp
index 954916700c..e1dbbaf106 100644
--- a/engines/m4/mads_anim.cpp
+++ b/engines/m4/mads_anim.cpp
@@ -37,7 +37,7 @@ namespace M4 {
TextviewView::TextviewView(MadsM4Engine *vm):
View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())),
_bgSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT),
- _textSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT + vm->_font->getHeight() +
+ _textSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT + vm->_font->current()->getHeight() +
TEXTVIEW_LINE_SPACING) {
_screenType = VIEWID_TEXTVIEW;
@@ -60,7 +60,7 @@ TextviewView::TextviewView(MadsM4Engine *vm):
_vm->_palette->setPalette(&palData[0], 4, 3);
_vm->_palette->blockRange(4, 3);
- _vm->_font->setColors(5, 6, 4);
+ _vm->_font->current()->setColours(5, 6, 4);
clear();
_bgSurface.clear();
@@ -222,7 +222,7 @@ void TextviewView::updateState() {
}
} else {
// Handling a text row
- if (++_lineY == (_vm->_font->getHeight() + TEXTVIEW_LINE_SPACING))
+ if (++_lineY == (_vm->_font->current()->getHeight() + TEXTVIEW_LINE_SPACING))
processLines();
}
@@ -404,7 +404,7 @@ void TextviewView::processText() {
if (!strcmp(_currentLine, "***")) {
// Special signifier for end of script
- _scrollCount = _vm->_font->getHeight() * 13;
+ _scrollCount = _vm->_font->current()->getHeight() * 13;
_lineY = -1;
return;
}
@@ -416,7 +416,7 @@ void TextviewView::processText() {
char *centerP = strchr(_currentLine, '@');
if (centerP) {
*centerP = '\0';
- xStart = (width() / 2) - _vm->_font->getWidth(_currentLine);
+ xStart = (width() / 2) - _vm->_font->current()->getWidth(_currentLine);
// Delete the @ character and shift back the remainder of the string
char *p = centerP + 1;
@@ -424,16 +424,16 @@ void TextviewView::processText() {
strcpy(centerP, p);
} else {
- lineWidth = _vm->_font->getWidth(_currentLine);
+ lineWidth = _vm->_font->current()->getWidth(_currentLine);
xStart = (width() - lineWidth) / 2;
}
// Copy the text line onto the bottom of the textSurface surface, which will allow it
// to gradually scroll onto the screen
- int yp = _textSurface.height() - _vm->_font->getHeight() - TEXTVIEW_LINE_SPACING;
+ int yp = _textSurface.height() - _vm->_font->current()->getHeight() - TEXTVIEW_LINE_SPACING;
_textSurface.fillRect(Common::Rect(0, yp, _textSurface.width(), _textSurface.height()),
_vm->_palette->BLACK);
- _vm->_font->writeString(&_textSurface, _currentLine, xStart, yp);
+ _vm->_font->current()->writeString(&_textSurface, _currentLine, xStart, yp);
}
@@ -441,7 +441,12 @@ void TextviewView::processText() {
AnimviewView::AnimviewView(MadsM4Engine *vm):
View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())),
- _bgSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT) {
+ MadsView(this), _backgroundSurface(MADS_SURFACE_WIDTH, MADS_SURFACE_HEIGHT),
+ _codeSurface(MADS_SURFACE_WIDTH, MADS_SURFACE_HEIGHT) {
+
+ MadsView::_bgSurface = &_backgroundSurface;
+ MadsView::_depthSurface = &_codeSurface;
+ MadsView::_yOffset = MADS_Y_OFFSET;
_screenType = VIEWID_ANIMVIEW;
_screenFlags.layer = LAYER_BACKGROUND;
@@ -452,27 +457,28 @@ AnimviewView::AnimviewView(MadsM4Engine *vm):
_palData = NULL;
_previousUpdate = 0;
_transition = kTransitionNone;
+ _activeAnimation = NULL;
reset();
// Set up system palette colors
_vm->_palette->setMadsSystemPalette();
clear();
- _bgSurface.clear();
+ _backgroundSurface.clear();
- int y = (height() - MADS_SURFACE_HEIGHT) / 2;
setColor(2);
- hLine(0, width() - 1, y - 2);
- hLine(0, width() - 1, height() - y + 1);
+ hLine(0, width() - 1, MADS_Y_OFFSET - 2);
+ hLine(0, width() - 1, MADS_Y_OFFSET + MADS_SURFACE_HEIGHT + 2);
}
AnimviewView::~AnimviewView() {
if (_script)
_vm->res()->toss(_resourceName);
+ delete _activeAnimation;
}
void AnimviewView::reset() {
- _bgSurface.clear();
+ _backgroundSurface.clear();
_soundDriverLoaded = false;
}
@@ -507,27 +513,26 @@ void AnimviewView::updateState() {
if (!_script)
return;
- // Only update state if wait period has expired
- if (_previousUpdate > 0) {
- if (g_system->getMillis() - _previousUpdate < 100)
- return;
-
- _previousUpdate = g_system->getMillis();
+ if (!_activeAnimation) {
+ readNextCommand();
+ assert(_activeAnimation);
}
- // Check if we're ready for the next command
- bool animRunning = false;
- if (!animRunning) {
+ // Update the current animation
+ _activeAnimation->update();
+ if (_activeAnimation->freeFlag()) {
+ delete _activeAnimation;
+ _activeAnimation = NULL;
+
if (_script->eos() || _script->err()) {
scriptDone();
return;
}
readNextCommand();
-
- // FIXME: Replace flag with proper animation end check
- animRunning = true;
}
+
+ refresh();
}
void AnimviewView::readNextCommand() {
@@ -562,46 +567,15 @@ void AnimviewView::readNextCommand() {
if (strchr(_currentLine, '.') == NULL)
strcat(_currentLine, ".aa");
- AAFile aaFile(_currentLine, _vm);
-
- // Initial validation
- if (aaFile.flags & AA_HAS_FONT) {
- assert(_vm->_resourceManager->resourceExists(aaFile.fontResource.c_str()));
- }
-
- for (int seriesCtr = 0; seriesCtr < aaFile.seriesCount; ++seriesCtr)
- assert(_vm->_resourceManager->resourceExists(aaFile.filenames[seriesCtr].c_str()));
-
- // Start sound
- if (aaFile.flags & AA_HAS_SOUND) {
- char buffer[100];
- strcpy(buffer, aaFile.soundName.c_str());
- buffer[0] = 'A'; // A for AdLib resource
-
- /*Common::SeekableReadStream *stream = */_vm->_resourceManager->get(buffer);
-
- _vm->_resourceManager->toss(buffer);
- }
-
-
- char artFile[80];
- sprintf(artFile, "rm%d.art", aaFile.roomNumber);
-
- // Not all scenes have a background. If there is one, refresh it
- if (_vm->_resourceManager->resourceExists(artFile)) {
- if (_palData) {
- _vm->_palette->deleteRange(_palData);
- delete _palData;
- }
- _bgSurface.loadBackground(aaFile.roomNumber, &_palData);
- _vm->_palette->addRange(_palData);
- _bgSurface.translate(_palData);
- }
+ _activeAnimation = new MadsAnimation(_vm, this);
+ _activeAnimation->load(_currentLine, 0);
- // Grab what the final palete will be
- RGB8 destPalette[256];
- _vm->_palette->grabPalette(destPalette, 0, 256);
+ _backgroundSurface.loadBackground(_activeAnimation->roomNumber());
+ _codeSurface.setSize(_backgroundSurface.width(), _backgroundSurface.height());
+ _codeSurface.fillRect(_codeSurface.bounds(), 0xff);
+ _spriteSlots.fullRefresh();
+/*
// Handle scene transition
switch (_transition) {
case kTransitionNone:
@@ -631,16 +605,14 @@ void AnimviewView::readNextCommand() {
// nothing to do
break;
}
-
- // Refresh the view
- int yp = (height() - _bgSurface.height()) / 2;
- _bgSurface.copyTo(this, 0, yp);
+*/
_vm->_resourceManager->toss(_currentLine);
}
void AnimviewView::scriptDone() {
+return;
AnimviewCallback fn = _callback;
MadsM4Engine *vm = _vm;
@@ -714,45 +686,4 @@ void AnimviewView::processCommand() {
}
}
-AAFile::AAFile(const char *resourceName, MadsM4Engine* vm): MadsPack(resourceName, vm) {
- Common::MemoryReadStream stream1(*getItemStream(1));
- Common::MemoryReadStream stream2(*getItemStream(2));
-
- Common::MemoryReadStream stream(*getItemStream(0));
-
- seriesCount = stream.readUint16LE();
- frameCount = stream.readUint16LE();
- frameEntryCount = stream.readUint16LE();
- stream.skip(3);
- flags = stream.readByte();
- stream.skip(4);
- roomNumber = stream.readUint16LE();
- stream.skip(10);
- frameTicks = stream.readUint16LE();
-
- stream.skip(21);
- for (int i = 0; i < 10; ++i) {
- char filename[13];
- stream.read(filename, 13);
- filenames.push_back(Common::String(filename, 13));
- }
-
- stream.skip(81);
- char name[100];
- stream.read(name, 13);
- lbmFilename = Common::String(name, 13);
-
- stream.skip(365);
- stream.read(name, 13);
- spritesFilename = Common::String(name, 13);
-
- stream.skip(48);
- stream.read(name, 13);
- soundName = Common::String(name, 13);
-
- stream.skip(26);
- stream.read(name, 14);
- fontResource = Common::String(name, 14);
-}
-
}
diff --git a/engines/m4/mads_anim.h b/engines/m4/mads_anim.h
index 680c5ff901..8c4a5e6fb7 100644
--- a/engines/m4/mads_anim.h
+++ b/engines/m4/mads_anim.h
@@ -28,24 +28,12 @@
#include "m4/viewmgr.h"
#include "m4/compression.h"
+#include "m4/animation.h"
#include "common/str-array.h"
namespace M4 {
-enum SceneTransition {
- kTransitionNone = 0,
- kTransitionFadeIn = 1,
- kTransitionFadeIn2 = 2,
- kTransitionBoxInBottomLeft = 3,
- kTransitionBoxInBottomRight = 4,
- kTransitionBoxInTopLeft = 5,
- kTransitionBoxInTopRight = 6,
- kTransitionPanLeftToRight = 7,
- kTransitionPanRightToLeft = 8,
- kTransitionCircleIn = 9
-};
-
typedef void (*TextviewCallback)(MadsM4Engine *vm);
class TextviewView : public View {
@@ -89,36 +77,19 @@ public:
typedef void (*AnimviewCallback)(MadsM4Engine *vm);
-class AAFile : public MadsPack {
-public:
- AAFile(const char *resourceName, MadsM4Engine* vm);
-
- uint16 seriesCount;
- uint16 frameCount;
- uint16 frameEntryCount;
- uint8 flags;
- uint16 roomNumber;
- uint16 frameTicks;
- Common::StringArray filenames;
- Common::String lbmFilename;
- Common::String spritesFilename;
- Common::String soundName;
- Common::String fontResource;
-};
-
-enum AAFlags {AA_HAS_FONT = 0x20, AA_HAS_SOUND = 0x8000};
-
-class AnimviewView : public View {
+class AnimviewView : public View, MadsView {
private:
char _resourceName[80];
Common::SeekableReadStream *_script;
uint32 _previousUpdate;
char _currentLine[80];
- M4Surface _bgSurface;
+ M4Surface _backgroundSurface;
+ M4Surface _codeSurface;
AnimviewCallback _callback;
bool _soundDriverLoaded;
RGBList *_palData;
int _transition;
+ MadsAnimation *_activeAnimation;
void reset();
void readNextCommand();
diff --git a/engines/m4/mads_logic.cpp b/engines/m4/mads_logic.cpp
index 1fe5f4beb3..9cb053a876 100644
--- a/engines/m4/mads_logic.cpp
+++ b/engines/m4/mads_logic.cpp
@@ -59,8 +59,8 @@ void MadsSceneLogic::getSceneSpriteSet() {
// if ((_sceneNumber == 105) ((_sceneNumber == 109) && (word_84800 != 0)))
// _madsVm->globals()->playerSpriteChanged = true;
-// _vm->_palette->setEntry(16, 0x38, 0xFF, 0xFF);
-// _vm->_palette->setEntry(17, 0x38, 0xb4, 0xb4);
+ _vm->_palette->setEntry(16, 0x38, 0xFF, 0xFF);
+ _vm->_palette->setEntry(17, 0x38, 0xb4, 0xb4);
}
void MadsSceneLogic::getAnimName() {
@@ -83,7 +83,7 @@ uint16 MadsSceneLogic::startReversibleSpriteSequence(uint16 srcSpriteIdx, int v0
spriteFrame->y + (spriteFrame->height() / 2)));
return _madsVm->scene()->_sequenceList.add(srcSpriteIdx, v0, 1, triggerCountdown, timeoutTicks, extraTicks, numTicks, 0, 0,
- -1, 100, depth - 1, 1, ANIMTYPE_REVERSIBLE, 0, 0);
+ true, 100, depth - 1, 1, ANIMTYPE_REVERSIBLE, 0, 0);
}
uint16 MadsSceneLogic::startCycledSpriteSequence(uint16 srcSpriteIdx, int v0, int numTicks, int triggerCountdown, int timeoutTicks, int extraTicks) {
@@ -92,7 +92,7 @@ uint16 MadsSceneLogic::startCycledSpriteSequence(uint16 srcSpriteIdx, int v0, in
spriteFrame->y + (spriteFrame->height() / 2)));
return _madsVm->scene()->_sequenceList.add(srcSpriteIdx, v0, 1, triggerCountdown, timeoutTicks, extraTicks, numTicks, 0, 0,
- -1, 100, depth - 1, 1, ANIMTYPE_CYCLED, 0, 0);
+ true, 100, depth - 1, 1, ANIMTYPE_CYCLED, 0, 0);
}
uint16 MadsSceneLogic::startSpriteSequence3(uint16 srcSpriteIdx, int v0, int numTicks, int triggerCountdown, int timeoutTicks, int extraTicks) {
@@ -101,7 +101,7 @@ uint16 MadsSceneLogic::startSpriteSequence3(uint16 srcSpriteIdx, int v0, int num
spriteFrame->y + (spriteFrame->height() / 2)));
return _madsVm->scene()->_sequenceList.add(srcSpriteIdx, v0, 1, triggerCountdown, timeoutTicks, extraTicks, numTicks, 0, 0,
- -1, 100, depth - 1, -1, ANIMTYPE_CYCLED, 0, 0);
+ true, 100, depth - 1, -1, ANIMTYPE_CYCLED, 0, 0);
}
void MadsSceneLogic::activateHotspot(int idx, bool active) {
@@ -146,6 +146,7 @@ void MadsSceneLogic::lowRoomsEntrySound() {
}
}
+
/*--------------------------------------------------------------------------*/
/**
@@ -169,7 +170,9 @@ void MadsSceneLogic::setupScene() {
// sub_1e754(animName, 3);
- getSceneSpriteSet();
+ if ((_sceneNumber >= 101) && (_sceneNumber <= 112))
+ getSceneSpriteSet();
+
getAnimName();
}
@@ -231,7 +234,8 @@ void MadsSceneLogic::enterScene() {
_madsVm->globals()->loadQuoteSet(0x31, 0x32, 0x37, 0x38, 0x39, -1);
if (_madsVm->globals()->_globals[10]) {
- // TODO: Load scene animation
+ const char *animName = MADSResourceManager::getResourceName('S', 'e', EXTTYPE_AA, NULL, -1);
+ _madsVm->scene()->loadAnimation(animName, 0x47);
_madsVm->scene()->getSceneResources().playerPos = Common::Point(68, 140);
_madsVm->scene()->getSceneResources().playerDir = 4;
@@ -245,4 +249,15 @@ void MadsSceneLogic::doAction() {
}
+void MadsSceneLogic::sceneStep() {
+ // FIXME: Temporary code to display a message on-screen
+ static bool tempBool = false;
+ if (!tempBool) {
+ tempBool = true;
+
+ _madsVm->scene()->_kernelMessages.add(Common::Point(63, 100), 0x1110, 0, 0, 240,
+ _madsVm->globals()->getQuote(49));
+ }
+}
+
}
diff --git a/engines/m4/mads_logic.h b/engines/m4/mads_logic.h
index a589556a21..8c3f41d08b 100644
--- a/engines/m4/mads_logic.h
+++ b/engines/m4/mads_logic.h
@@ -29,6 +29,8 @@
#ifndef M4_MADS_LOGIC_H
#define M4_MADS_LOGIC_H
+#include "m4/mads_views.h"
+
namespace M4 {
class MadsSceneLogic {
@@ -54,6 +56,7 @@ public:
void setupScene();
void enterScene();
void doAction();
+ void sceneStep();
};
}
diff --git a/engines/m4/mads_menus.cpp b/engines/m4/mads_menus.cpp
index da8ac4230e..94894e78be 100644
--- a/engines/m4/mads_menus.cpp
+++ b/engines/m4/mads_menus.cpp
@@ -49,7 +49,7 @@ RexMainMenuView::RexMainMenuView(MadsM4Engine *vm):
_skipFlag = false;
// Load the background for the Rex Nebular game
- _bgSurface = new M4Surface(width(), MADS_SURFACE_HEIGHT);
+ _bgSurface = new M4Surface();
_bgSurface->loadBackground(REX_MENUSCREEN, &_bgPalData);
_vm->_palette->addRange(_bgPalData);
_bgSurface->translate(_bgPalData);
@@ -619,7 +619,7 @@ void RexDialogView::initialiseLines() {
// Set up a default sprite slot entry for a full screen refresh
_spriteSlots.startIndex = 1;
_spriteSlots[0].spriteType = FULL_SCREEN_REFRESH;
- _spriteSlots[0].timerIndex = -1;
+ _spriteSlots[0].seqIndex = -1;
}
void RexDialogView::initialiseGraphics() {
@@ -796,7 +796,7 @@ bool RexDialogView::onEvent(M4EventType eventType, int32 param1, int x, int y, b
void RexDialogView::setFrame(int frameNumber, int depth) {
int slotIndex = _spriteSlots.getIndex();
_spriteSlots[slotIndex].spriteType = FOREGROUND_SPRITE;
- _spriteSlots[slotIndex].timerIndex = 1;
+ _spriteSlots[slotIndex].seqIndex = 1;
_spriteSlots[slotIndex].spriteListIndex = 0; //_menuSpritesIndex;
_spriteSlots[slotIndex].frameNumber = frameNumber;
@@ -985,15 +985,15 @@ RexGameMenuDialog::RexGameMenuDialog(): RexDialogView() {
void RexGameMenuDialog::addLines() {
// Add the title
- int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->getHeight() + 2) * 6) >> 1) - 78);
+ int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->current()->getHeight() + 2) * 6) >> 1) - 78);
- addQuote(_vm->_font, ALIGN_CENTER, 0, top, 10);
+ addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 10);
// Loop for adding the option lines of the dialog
top += 6;
for (int idx = 0; idx < 5; ++idx) {
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CENTER, 0, top, 11 + idx);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 11 + idx);
}
}
@@ -1069,42 +1069,42 @@ void RexOptionsDialog::reload() {
void RexOptionsDialog::addLines() {
// Add the title
- int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->getHeight() + 1) * 9 + 12) >> 1) - 78);
+ int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->current()->getHeight() + 1) * 9 + 12) >> 1) - 78);
- addQuote(_vm->_font, ALIGN_CENTER, 0, top, 16);
+ addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 16);
// Music state line
- top += _vm->_font->getHeight() + 1 + 6;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 17, _tempConfig.musicFlag ? 24 : 25);
+ top += _vm->_font->current()->getHeight() + 1 + 6;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 17, _tempConfig.musicFlag ? 24 : 25);
// Sound state line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 18, _tempConfig.soundFlag ? 26 : 27);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 18, _tempConfig.soundFlag ? 26 : 27);
// Interface easy state line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 19, _tempConfig.easyMouse ? 29 : 28);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 19, _tempConfig.easyMouse ? 29 : 28);
// Inventory sppinng state line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 20, _tempConfig.invObjectsStill ? 31 : 30);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 20, _tempConfig.invObjectsStill ? 31 : 30);
// Text window state line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 21, _tempConfig.textWindowStill ? 33 : 32);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 21, _tempConfig.textWindowStill ? 33 : 32);
// Screen fade state line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 22, _tempConfig.screenFades + 34);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 22, _tempConfig.screenFades + 34);
// Storyline mode line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 23, (_tempConfig.storyMode == 1) ? 37 : 38);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 23, (_tempConfig.storyMode == 1) ? 37 : 38);
// Add Done and Cancel button texts
- top += _vm->_font->getHeight() + 1 + 6;
- addQuote(_vm->_font, ALIGN_CENTER, -54, top, 1, 0);
- addQuote(_vm->_font, ALIGN_CENTER, 54, top, 2, 0);
+ top += _vm->_font->current()->getHeight() + 1 + 6;
+ addQuote(_vm->_font->current(), ALIGN_CENTER, -54, top, 1, 0);
+ addQuote(_vm->_font->current(), ALIGN_CENTER, 54, top, 2, 0);
}
bool RexOptionsDialog::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp
index 4f28cdc6da..a65224c722 100644
--- a/engines/m4/mads_scene.cpp
+++ b/engines/m4/mads_scene.cpp
@@ -37,11 +37,20 @@
#include "m4/mads_views.h"
#include "m4/compression.h"
#include "m4/staticres.h"
+#include "m4/animation.h"
namespace M4 {
+static const int INV_ANIM_FRAME_SPEED = 2;
+static const int INVENTORY_X = 160;
+static const int INVENTORY_Y = 159;
+static const int SCROLLER_DELAY = 200;
+
+//--------------------------------------------------------------------------
+
MadsScene::MadsScene(MadsEngine *vm): _sceneResources(), Scene(vm, &_sceneResources), MadsView(this) {
_vm = vm;
+ _activeAnimation = NULL;
MadsView::_bgSurface = Scene::_backgroundSurface;
MadsView::_depthSurface = Scene::_walkSurface;
@@ -51,6 +60,8 @@ MadsScene::MadsScene(MadsEngine *vm): _sceneResources(), Scene(vm, &_sceneResour
}
MadsScene::~MadsScene() {
+ delete _activeAnimation;
+ _activeAnimation = NULL;
leaveScene();
_vm->_viewManager->deleteView(_interfaceSurface);
}
@@ -66,10 +77,17 @@ void MadsScene::loadScene2(const char *aaName) {
_kernelMessages.clear();
// Load up the properties for the scene
- _sceneResources.load(_currentScene);
+ _sceneResources.load(_currentScene, NULL, 0/*word_83546*/, _walkSurface, _backgroundSurface);
// Load scene walk paths
loadSceneCodes(_currentScene);
+
+ // Initialise the scene animation
+ uint16 flags = 0x4100;
+ if (_madsVm->globals()->_config.textWindowStill)
+ flags |= 0x200;
+
+ _sceneAnimation->initialise(aaName, flags, _interfaceSurface, NULL);
}
/**
@@ -78,27 +96,12 @@ void MadsScene::loadScene2(const char *aaName) {
void MadsScene::loadSceneTemporary() {
/* Existing code that eventually needs to be replaced with the proper MADS code */
// Set system palette entries
- _vm->_palette->blockRange(0, 7);
+ _vm->_palette->blockRange(0, 18);
RGB8 sysColors[3] = { {0x1f<<2, 0x2d<<2, 0x31<<2, 0}, {0x24<<2, 0x37<<2, 0x3a<<2, 0},
{0x00<<2, 0x10<<2, 0x16<<2, 0}};
_vm->_palette->setPalette(&sysColors[0], 4, 3);
- _backgroundSurface->loadBackground(_currentScene, &_palData);
- _vm->_palette->addRange(_palData);
- _backgroundSurface->translate(_palData);
-
- if (_currentScene < 900) {
- _interfaceSurface->madsloadInterface(0, &_interfacePal);
- _vm->_palette->addRange(_interfacePal);
- _interfaceSurface->translate(_interfacePal);
- _backgroundSurface->copyFrom(_interfaceSurface, Common::Rect(0, 0, 320, 44), 0, 200 - 44);
-
- _interfaceSurface->initialise();
- }
-
- // Don't load other screen resources for system screens
- if (_currentScene >= 900)
- return;
+ _interfaceSurface->initialise();
loadSceneHotspots(_currentScene);
@@ -167,6 +170,11 @@ void MadsScene::leaveScene() {
delete _sceneResources.props;
delete _walkSurface;
+ if (_activeAnimation) {
+ delete _activeAnimation;
+ _activeAnimation = NULL;
+ }
+
Scene::leaveScene();
}
@@ -185,15 +193,6 @@ void MadsScene::loadSceneCodes(int sceneNumber, int index) {
sceneS = walkData.getItemStream(0);
_walkSurface->loadCodesMads(sceneS);
_vm->res()->toss(filename);
- } else if (_vm->getGameType() == GType_RexNebular) {
- // For Rex Nebular, the walk areas are part of the scene info
- byte *destP = _walkSurface->getBasePtr(0, 0);
- const byte *srcP = _sceneResources.walkData;
- byte runLength;
- while ((runLength = *srcP++) != 0) {
- Common::set_to(destP, destP + runLength, *srcP++);
- destP += runLength;
- }
}
}
@@ -289,20 +288,28 @@ void MadsScene::update() {
if (sStatusText[0]) {
// Text colors are inverted in Dragonsphere
if (_vm->getGameType() == GType_DragonSphere)
- _vm->_font->setColors(_vm->_palette->BLACK, _vm->_palette->WHITE, _vm->_palette->BLACK);
+ _vm->_font->current()->setColours(_vm->_palette->BLACK, _vm->_palette->WHITE, _vm->_palette->BLACK);
else
- _vm->_font->setColors(_vm->_palette->WHITE, _vm->_palette->BLACK, _vm->_palette->BLACK);
+ _vm->_font->current()->setColours(_vm->_palette->WHITE, _vm->_palette->BLACK, _vm->_palette->BLACK);
_vm->_font->setFont(FONT_MAIN_MADS);
- _vm->_font->writeString(this, sStatusText, (width() - _vm->_font->getWidth(sStatusText)) / 2, 142, 0);
+ _vm->_font->current()->writeString(this, sStatusText, (width() - _vm->_font->current()->getWidth(sStatusText)) / 2, 142, 0);
}
-
- //***DEBUG***
- _spriteSlots.getSprite(0).getFrame(1)->copyTo(this, 120, 90, 0);
}
void MadsScene::updateState() {
+ _sceneLogic.sceneStep();
_sequenceList.tick();
+
+ if ((_activeAnimation) && !_abortTimers) {
+ _activeAnimation->update();
+ if (((MadsAnimation *) _activeAnimation)->freeFlag()) {
+ delete _activeAnimation;
+ _activeAnimation = NULL;
+ }
+ }
+
+ _kernelMessages.update();
}
int MadsScene::loadSceneSpriteSet(const char *setName) {
@@ -435,6 +442,15 @@ void MadsScene::showMADSV2TextBox(char *text, int x, int y, char *faceName) {
boxSprites->getFrame(bottomRight)->copyTo(_backgroundSurface, curX, curY + 1);
}
+void MadsScene::loadAnimation(const Common::String &animName, int v0) {
+ if (_activeAnimation)
+ error("Multiple active animations are not allowed");
+
+ MadsAnimation *anim = new MadsAnimation(_vm, this);
+ anim->load(animName.c_str(), 0);
+ _activeAnimation = anim;
+}
+
/*--------------------------------------------------------------------------*/
MadsAction::MadsAction() {
@@ -612,97 +628,531 @@ void MadsAction::set() {
/*--------------------------------------------------------------------------*/
-void MadsSceneResources::load(int sId) {
- const char *sceneInfoStr = MADSResourceManager::getResourceName(RESPREFIX_RM, sId, ".DAT");
- Common::SeekableReadStream *rawStream = _vm->_resourceManager->get(sceneInfoStr);
+void MadsSceneResources::load(int sceneNumber, const char *resName, int v0, M4Surface *depthSurface, M4Surface *surface) {
+ char buffer1[80];
+ const char *sceneName;
+
+ // TODO: Initialise spriteSet / xp_list
+
+ if (sceneNumber > 0) {
+ sceneName = MADSResourceManager::getResourceName(RESPREFIX_RM, sceneNumber, ".DAT");
+ } else {
+ strcat(buffer1, "*");
+ strcat(buffer1, resName);
+ sceneName = buffer1; // TODO: Check whether this needs to be converted to 'HAG form'
+ }
+
+ Common::SeekableReadStream *rawStream = _vm->_resourceManager->get(sceneName);
MadsPack sceneInfo(rawStream);
+ // Chunk 0:
// Basic scene info
Common::SeekableReadStream *stream = sceneInfo.getItemStream(0);
int resSceneId = stream->readUint16LE();
- assert(resSceneId == sId);
-
+ assert(resSceneId == sceneNumber);
artFileNum = stream->readUint16LE();
- field_4 = stream->readUint16LE();
+ drawStyle = stream->readUint16LE();
width = stream->readUint16LE();
height = stream->readUint16LE();
assert((width == 320) && (height == 156));
stream->skip(24);
- objectCount = stream->readUint16LE();
+ int objectCount = stream->readUint16LE();
stream->skip(40);
+ // Load in any scene objects
for (int i = 0; i < objectCount; ++i) {
- objects[i].load(stream);
+ MadsObject rec;
+ rec.load(stream);
+ objects.push_back(rec);
+ }
+ for (int i = 0; i < 20 - objectCount; ++i)
+ stream->skip(48);
+
+ int setCount = stream->readUint16LE();
+ stream->readUint16LE();
+ for (int i = 0; i < setCount; ++i) {
+ char buffer2[64];
+ Common::String s(buffer2, 64);
+ setNames.push_back(s);
+ }
+
+ // Initialise a copy of the surfaces if they weren't provided
+ bool dsFlag = false, ssFlag = false;
+ int gfxSize = width * height;
+ if (!surface) {
+ surface = new M4Surface(width, height);
+ ssFlag = true;
+ }
+ int walkSize = gfxSize;
+ if (drawStyle == 2) {
+ width >>= 2;
+ walkSize = width * height;
+ }
+ if (!depthSurface) {
+ depthSurface = new M4Surface(width, height);
+ dsFlag = true;
}
// For Rex Nebular, read in the scene's compressed walk surface information
if (_vm->getGameType() == GType_RexNebular) {
- delete walkData;
-
+ assert(depthSurface);
stream = sceneInfo.getItemStream(1);
- walkData = (byte *)malloc(stream->size());
+ byte *walkData = (byte *)malloc(stream->size());
stream->read(walkData, stream->size());
+
+ // For Rex Nebular, the walk areas are part of the scene info
+ byte *destP = depthSurface->getBasePtr(0, 0);
+ const byte *srcP = walkData;
+ byte runLength;
+ while ((runLength = *srcP++) != 0) {
+ Common::set_to(destP, destP + runLength, *srcP++);
+ destP += runLength;
+ }
+
+ delete walkData;
+ delete stream;
}
- _vm->_resourceManager->toss(sceneInfoStr);
+ _vm->_resourceManager->toss(sceneName);
+
+ // Load the surface artwork
+ surface->loadBackground(sceneNumber);
+
+ // Final cleanup
+ if (ssFlag)
+ delete surface;
+ if (dsFlag)
+ delete depthSurface;
}
+
/*--------------------------------------------------------------------------*/
-/**
- * Adds a new entry to the timed on-screen text display list
+/*--------------------------------------------------------------------------
+ * MadsInterfaceView handles the user interface section at the bottom of
+ * game screens in MADS games
+ *--------------------------------------------------------------------------
*/
-/*
-void MadsScreenText::draw(M4Surface *surface) {
+
+MadsInterfaceView::MadsInterfaceView(MadsM4Engine *vm): GameInterfaceView(vm,
+ Common::Rect(0, MADS_SURFACE_HEIGHT, vm->_screen->width(), vm->_screen->height())) {
+ _screenType = VIEWID_INTERFACE;
+ _highlightedElement = -1;
+ _topIndex = 0;
+ _selectedObject = -1;
+ _cheatKeyCtr = 0;
+
+ _objectSprites = NULL;
+ _objectPalData = NULL;
+
+ /* Set up the rect list for screen elements */
+ // Actions
+ for (int i = 0; i < 10; ++i)
+ _screenObjects.addRect((i / 5) * 32 + 1, (i % 5) * 8 + MADS_SURFACE_HEIGHT + 2,
+ ((i / 5) + 1) * 32 + 3, ((i % 5) + 1) * 8 + MADS_SURFACE_HEIGHT + 2);
+
+ // Scroller elements (up arrow, scroller, down arrow)
+ _screenObjects.addRect(73, 160, 82, 167);
+ _screenObjects.addRect(73, 168, 82, 190);
+ _screenObjects.addRect(73, 191, 82, 198);
+
+ // Inventory object names
+ for (int i = 0; i < 5; ++i)
+ _screenObjects.addRect(89, 158 + i * 8, 160, 166 + i * 8);
+
+ // Full rectangle area for all vocab actions
+ for (int i = 0; i < 5; ++i)
+ _screenObjects.addRect(239, 158 + i * 8, 320, 166 + i * 8);
+}
+
+MadsInterfaceView::~MadsInterfaceView() {
+ delete _objectSprites;
}
-void MadsScreenText::timedDisplay() {
- for (int idx = 0; !_abortTimedText && (idx < OLD_TEXT_DISPLAY_SIZE); ++idx) {
- if (((_timedText[idx].flags & TEXTFLAG_ACTIVE) != 0) &&
- (_timedText[idx].frameTimer <= g_system->getMillis()))
- // Add the specified entry
- addTimedText(&_timedText[idx]);
+void MadsInterfaceView::setFontMode(InterfaceFontMode newMode) {
+ switch (newMode) {
+ case ITEM_NORMAL:
+ _vm->_font->current()->setColours(4, 4, 0xff);
+ break;
+ case ITEM_HIGHLIGHTED:
+ _vm->_font->current()->setColours(5, 5, 0xff);
+ break;
+ case ITEM_SELECTED:
+ _vm->_font->current()->setColours(6, 6, 0xff);
+ break;
}
}
-void MadsScreenText::addTimedText(TimedText *entry) {
- if ((entry->flags & TEXTFLAG_40) != 0) {
- this->setActive2(entry->textDisplayIndex);
- entry->flags &= 0x7F;
+void MadsInterfaceView::initialise() {
+ // Build up the inventory list
+ _inventoryList.clear();
+
+ for (uint i = 0; i < _madsVm->globals()->getObjectsSize(); ++i) {
+ MadsObject *obj = _madsVm->globals()->getObject(i);
+ if (obj->roomNumber == PLAYER_INVENTORY)
+ _inventoryList.push_back(i);
+ }
+
+ // If the inventory has at least one object, select it
+ if (_inventoryList.size() > 0)
+ setSelectedObject(_inventoryList[0]);
+}
+
+void MadsInterfaceView::setSelectedObject(int objectNumber) {
+ char resName[80];
+
+ // Load inventory resource
+ if (_objectSprites) {
+ _vm->_palette->deleteRange(_objectPalData);
+ delete _objectSprites;
+ }
+
+ // Check to make sure the object is in the inventory, and also visible on-screen
+ int idx = _inventoryList.indexOf(objectNumber);
+ if (idx == -1) {
+ // Object wasn't found, so return
+ _selectedObject = -1;
return;
}
- if ((entry->flags & TEXTFLAG_8) == 0)
- // FIXME: Adjust timeouts for ScumVM's milli counter
- entry->timeout -= 3;
+ // Found the object
+ if (idx < _topIndex)
+ _topIndex = idx;
+ else if (idx >= (_topIndex + 5))
+ _topIndex = MAX(0, idx - 4);
- if ((entry->flags & TEXTFLAG_4) != 0) {
- Text4A &rec = _text4A[entry->unk4AIndex];
- if ((rec.field25 != 0) || (rec.active == 0))
- entry->timeout = 0;
+ _selectedObject = objectNumber;
+ sprintf(resName, "*OB%.3dI.SS", objectNumber);
+
+ Common::SeekableReadStream *data = _vm->res()->get(resName);
+ _objectSprites = new SpriteAsset(_vm, data, data->size(), resName);
+ _vm->res()->toss(resName);
+
+ // Slot it into available palette space
+ _objectPalData = _objectSprites->getRgbList();
+ _vm->_palette->addRange(_objectPalData);
+ _objectSprites->translate(_objectPalData, true);
+
+ _objectFrameNumber = 0;
+}
+
+void MadsInterfaceView::addObjectToInventory(int objectNumber) {
+ if (_inventoryList.indexOf(objectNumber) == -1) {
+ _madsVm->globals()->getObject(objectNumber)->roomNumber = PLAYER_INVENTORY;
+ _inventoryList.push_back(objectNumber);
}
- if ((entry->timeout == 0) && !_abortTimedText) {
- entry->flags |= TEXTFLAG_40;
+ setSelectedObject(objectNumber);
+}
- if (entry->field_1C) {
- _abortTimedText = entry->field_1C;
- //word_84208 = entry->field_1D;
-
- if (entry->field_1D != 1) {
- // Restore the action list
- for (int i = 0; i < 3; ++i)
- _madsVm->scene()->actionNouns[i] = entry->actionNouns[i];
+void MadsInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) {
+ _vm->_font->setFont(FONT_INTERFACE_MADS);
+ char buffer[100];
+
+ // Check to see if any dialog is currently active
+ bool dialogVisible = _vm->_viewManager->getView(LAYER_DIALOG) != NULL;
+
+ // Highlighting logic for action list
+ int actionIndex = 0;
+ for (int x = 0; x < 2; ++x) {
+ for (int y = 0; y < 5; ++y, ++actionIndex) {
+ // Determine the font colour depending on whether an item is selected. Note that the first action,
+ // 'Look', is always 'selected', even when another action is clicked on
+ setFontMode((_highlightedElement == actionIndex) ? ITEM_HIGHLIGHTED :
+ ((actionIndex == 0) ? ITEM_SELECTED : ITEM_NORMAL));
+
+ // Get the verb action and capitalise it
+ const char *verbStr = _madsVm->globals()->getVocab(kVerbLook + actionIndex);
+ strcpy(buffer, verbStr);
+ if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
+
+ // Display the verb
+ const Common::Rect r(_screenObjects[actionIndex]);
+ _vm->_font->current()->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
+ }
+ }
+
+ // Check for highlighting of the scrollbar controls
+ if ((_highlightedElement == SCROLL_UP) || (_highlightedElement == SCROLL_SCROLLER) || (_highlightedElement == SCROLL_DOWN)) {
+ // Highlight the control's borders
+ const Common::Rect r(_screenObjects[_highlightedElement]);
+ destSurface->frameRect(r, 5);
+ }
+
+ // Draw the horizontal line in the scroller representing the current top selected
+ const Common::Rect scroller(_screenObjects[SCROLL_SCROLLER]);
+ int yP = (_inventoryList.size() < 2) ? 0 : (scroller.height() - 5) * _topIndex / (_inventoryList.size() - 1);
+ destSurface->setColor(4);
+ destSurface->hLine(scroller.left + 2, scroller.right - 3, scroller.top + 2 + yP);
+
+ // List inventory items
+ for (uint i = 0; i < 5; ++i) {
+ if ((_topIndex + i) >= _inventoryList.size())
+ break;
+
+ const char *descStr = _madsVm->globals()->getVocab(_madsVm->globals()->getObject(
+ _inventoryList[_topIndex + i])->descId);
+ strcpy(buffer, descStr);
+ if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
+
+ const Common::Rect r(_screenObjects[INVLIST_START + i]);
+
+ // Set the highlighting of the inventory item
+ if (_highlightedElement == (int)(INVLIST_START + i)) setFontMode(ITEM_HIGHLIGHTED);
+ else if (_selectedObject == _inventoryList[_topIndex + i]) setFontMode(ITEM_SELECTED);
+ else setFontMode(ITEM_NORMAL);
+
+ // Write out it's description
+ _vm->_font->current()->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
+ }
+
+ // Handle the display of any currently selected object
+ if (_objectSprites) {
+ // Display object sprite. Note that the frame number isn't used directly, because it would result
+ // in too fast an animation
+ M4Sprite *spr = _objectSprites->getFrame(_objectFrameNumber / INV_ANIM_FRAME_SPEED);
+ spr->copyTo(destSurface, INVENTORY_X, INVENTORY_Y, 0);
+
+ if (!_madsVm->globals()->_config.invObjectsStill && !dialogVisible) {
+ // If objects need to be animated, move to the next frame
+ if (++_objectFrameNumber >= (_objectSprites->getCount() * INV_ANIM_FRAME_SPEED))
+ _objectFrameNumber = 0;
+ }
+
+ // List the vocab actions for the currently selected object
+ MadsObject *obj = _madsVm->globals()->getObject(_selectedObject);
+ int yIndex = MIN(_highlightedElement - VOCAB_START, obj->vocabCount - 1);
+
+ for (int i = 0; i < obj->vocabCount; ++i) {
+ const Common::Rect r(_screenObjects[VOCAB_START + i]);
+
+ // Get the vocab description and capitalise it
+ const char *descStr = _madsVm->globals()->getVocab(obj->vocabList[i].vocabId);
+ strcpy(buffer, descStr);
+ if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
+
+ // Set the highlighting and display the entry
+ setFontMode((i == yIndex) ? ITEM_HIGHLIGHTED : ITEM_NORMAL);
+ _vm->_font->current()->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
+ }
+ }
+}
+
+bool MadsInterfaceView::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
+ MadsAction &act = _madsVm->scene()->getAction();
+
+ // If the mouse isn't being held down, then reset the repeated scroll timer
+ if (eventType != MEVENT_LEFT_HOLD)
+ _nextScrollerTicks = 0;
+
+ // Handle various event types
+ switch (eventType) {
+ case MEVENT_MOVE:
+ // If the cursor isn't in "wait mode", don't do any processing
+ if (_vm->_mouse->getCursorNum() == CURSOR_WAIT)
+ return true;
+
+ // Ensure the cursor is the standard arrow
+ _vm->_mouse->setCursorNum(CURSOR_ARROW);
+
+ // Check if any interface element is currently highlighted
+ _highlightedElement = _screenObjects.find(Common::Point(x, y));
+
+ return true;
+
+ case MEVENT_LEFT_CLICK:
+ // Left mouse click
+ {
+ // Check if an inventory object was selected
+ if ((_highlightedElement >= INVLIST_START) && (_highlightedElement < (INVLIST_START + 5))) {
+ // Ensure there is an inventory item listed in that cell
+ uint idx = _highlightedElement - INVLIST_START;
+ if ((_topIndex + idx) < _inventoryList.size()) {
+ // Set the selected object
+ setSelectedObject(_inventoryList[_topIndex + idx]);
+ }
+ } else if ((_highlightedElement >= ACTIONS_START) && (_highlightedElement < (ACTIONS_START + 10))) {
+ // A standard action was selected
+ int verbId = kVerbLook + (_highlightedElement - ACTIONS_START);
+ warning("Selected action #%d", verbId);
+
+ } else if ((_highlightedElement >= VOCAB_START) && (_highlightedElement < (VOCAB_START + 5))) {
+ // A vocab action was selected
+ MadsObject *obj = _madsVm->globals()->getObject(_selectedObject);
+ int vocabIndex = MIN(_highlightedElement - VOCAB_START, obj->vocabCount - 1);
+ if (vocabIndex >= 0) {
+ act._actionMode = ACTMODE_OBJECT;
+ act._actionMode2 = ACTMODE2_2;
+ act._flags1 = obj->vocabList[1].flags1;
+ act._flags2 = obj->vocabList[1].flags2;
+
+ act._currentHotspot = _selectedObject;
+ act._articleNumber = act._flags2;
+ }
+ }
+ }
+ return true;
+
+ case MEVENT_LEFT_HOLD:
+ // Left mouse hold
+ // Handle the scroller - the up/down buttons allow for multiple actions whilst the mouse is held down
+ if ((_highlightedElement == SCROLL_UP) || (_highlightedElement == SCROLL_DOWN)) {
+ if ((_nextScrollerTicks == 0) || (g_system->getMillis() >= _nextScrollerTicks)) {
+ // Handle scroll up/down action
+ _nextScrollerTicks = g_system->getMillis() + SCROLLER_DELAY;
+
+ if ((_highlightedElement == SCROLL_UP) && (_topIndex > 0))
+ --_topIndex;
+ if ((_highlightedElement == SCROLL_DOWN) && (_topIndex < (int)(_inventoryList.size() - 1)))
+ ++_topIndex;
}
}
+ return true;
+
+ case MEVENT_LEFT_DRAG:
+ // Left mouse drag
+ // Handle the the the scroller area that can be dragged to adjust the top displayed index
+ if (_highlightedElement == SCROLL_SCROLLER) {
+ // Calculate the new top index based on the Y position
+ const Common::Rect r(_screenObjects[SCROLL_SCROLLER]);
+ _topIndex = CLIP((int)(_inventoryList.size() - 1) * (y - r.top - 2) / (r.height() - 5),
+ 0, (int)_inventoryList.size() - 1);
+ }
+ return true;
+
+ case KEVENT_KEY:
+ if (_cheatKeyCtr == CHEAT_SEQUENCE_MAX)
+ handleCheatKey(param1);
+ handleKeypress(param1);
+ return true;
+
+ default:
+ break;
}
- // TODO: code from 'loc_244ec' onwards
+ return false;
+}
+
+bool MadsInterfaceView::handleCheatKey(int32 keycode) {
+ switch (keycode) {
+ case Common::KEYCODE_SPACE:
+ // TODO: Move player to current destination
+ return true;
+
+ case Common::KEYCODE_t | (Common::KEYCODE_LALT):
+ case Common::KEYCODE_t | (Common::KEYCODE_RALT):
+ {
+ // Teleport to room
+ //Scene *sceneView = (Scene *)vm->_viewManager->getView(VIEWID_SCENE);
+
+
+ return true;
+ }
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+const char *CHEAT_SEQUENCE = "widepipe";
+
+bool MadsInterfaceView::handleKeypress(int32 keycode) {
+ int flags = keycode >> 24;
+ int kc = keycode & 0xffff;
+
+ // Capitalise the letter if necessary
+ if (_cheatKeyCtr < CHEAT_SEQUENCE_MAX) {
+ if ((flags & Common::KBD_CTRL) && (kc == CHEAT_SEQUENCE[_cheatKeyCtr])) {
+ ++_cheatKeyCtr;
+ if (_cheatKeyCtr == CHEAT_SEQUENCE_MAX)
+ Dialog::display(_vm, 22, cheatingEnabledDesc);
+ return true;
+ } else {
+ _cheatKeyCtr = 0;
+ }
+ }
+
+ // Handle the various keys
+ if ((keycode == Common::KEYCODE_ESCAPE) || (keycode == Common::KEYCODE_F1)) {
+ // Game menu
+ _madsVm->globals()->dialogType = DIALOG_GAME_MENU;
+ leaveScene();
+ return false;
+ } else if (flags & Common::KBD_CTRL) {
+ // Handling of the different control key combinations
+ switch (kc) {
+ case Common::KEYCODE_i:
+ // Mouse to inventory
+ warning("TODO: Mouse to inventory");
+ break;
+
+ case Common::KEYCODE_k:
+ // Toggle hotspots
+ warning("TODO: Toggle hotspots");
+ break;
+
+ case Common::KEYCODE_p:
+ // Player stats
+ warning("TODO: Player stats");
+ break;
+
+ case Common::KEYCODE_q:
+ // Quit game
+ break;
+
+ case Common::KEYCODE_s:
+ // Activate sound
+ warning("TODO: Activate sound");
+ break;
+
+ case Common::KEYCODE_u:
+ // Rotate player
+ warning("TODO: Rotate player");
+ break;
+
+ case Common::KEYCODE_v: {
+ // Release version
+ Dialog *dlg = new Dialog(_vm, GameReleaseInfoStr, GameReleaseTitleStr);
+ _vm->_viewManager->addView(dlg);
+ _vm->_viewManager->moveToFront(dlg);
+ return false;
+ }
+
+ default:
+ break;
+ }
+ } else if ((flags & Common::KBD_ALT) && (kc == Common::KEYCODE_q)) {
+ // Quit Game
+
+ } else {
+ // Standard keypresses
+ switch (kc) {
+ case Common::KEYCODE_F2:
+ // Save game
+ _madsVm->globals()->dialogType = DIALOG_SAVE;
+ leaveScene();
+ break;
+ case Common::KEYCODE_F3:
+ // Restore game
+ _madsVm->globals()->dialogType = DIALOG_RESTORE;
+ leaveScene();
+ break;
+ }
+ }
+//DIALOG_OPTIONS
+ return false;
+}
+
+void MadsInterfaceView::leaveScene() {
+ // Close the scene
+ View *view = _madsVm->_viewManager->getView(VIEWID_SCENE);
+ _madsVm->_viewManager->deleteView(view);
}
-*/
} // End of namespace M4
diff --git a/engines/m4/mads_scene.h b/engines/m4/mads_scene.h
index c8a0da3aea..0269de75c8 100644
--- a/engines/m4/mads_scene.h
+++ b/engines/m4/mads_scene.h
@@ -33,27 +33,24 @@
namespace M4 {
#define INTERFACE_HEIGHT 106
-
+class MadsInterfaceView;
class MadsSceneResources: public SceneResources {
public:
int sceneId;
int artFileNum;
- int field_4;
+ int drawStyle;
int width;
int height;
-
- int objectCount;
- MadsObject objects[32];
+ Common::Array<MadsObject> objects;
+ Common::Array<Common::String> setNames;
- int walkSize;
- byte *walkData;
Common::Point playerPos;
int playerDir;
- MadsSceneResources() { walkSize = 0; walkData = NULL; playerDir = 0; }
- ~MadsSceneResources() { delete walkData; }
- void load(int sceneId);
+ MadsSceneResources() { playerDir = 0; }
+ ~MadsSceneResources() {}
+ void load(int sceneId, const char *resName, int v0, M4Surface *depthSurface, M4Surface *surface);
};
enum MadsActionMode {ACTMODE_NONE = 0, ACTMODE_VERB = 1, ACTMODE_OBJECT = 3, ACTMODE_TALK = 6};
@@ -96,6 +93,7 @@ private:
MadsEngine *_vm;
MadsSceneResources _sceneResources;
MadsAction _action;
+ Animation *_activeAnimation;
MadsSceneLogic _sceneLogic;
SpriteAsset *_playerSprites;
@@ -130,6 +128,7 @@ public:
int loadSceneSpriteSet(const char *setName);
void loadPlayerSprites(const char *prefix);
void showMADSV2TextBox(char *text, int x, int y, char *faceName);
+ void loadAnimation(const Common::String &animName, int v0);
MadsInterfaceView *getInterface() { return (MadsInterfaceView *)_interfaceSurface; }
MadsSceneResources &getSceneResources() { return _sceneResources; }
@@ -137,6 +136,56 @@ public:
void setStatusText(const char *text) {}//***DEPRECATED***
};
+#define CHEAT_SEQUENCE_MAX 8
+
+class IntegerList : public Common::Array<int> {
+public:
+ int indexOf(int v) {
+ for (uint i = 0; i < size(); ++i)
+ if (operator [](i) == v)
+ return i;
+ return -1;
+ }
+};
+
+enum InterfaceFontMode {ITEM_NORMAL, ITEM_HIGHLIGHTED, ITEM_SELECTED};
+
+enum InterfaceObjects {ACTIONS_START = 0, SCROLL_UP = 10, SCROLL_SCROLLER = 11, SCROLL_DOWN = 12,
+ INVLIST_START = 13, VOCAB_START = 18};
+
+class MadsInterfaceView : public GameInterfaceView {
+private:
+ IntegerList _inventoryList;
+ RectList _screenObjects;
+ int _highlightedElement;
+ int _topIndex;
+ uint32 _nextScrollerTicks;
+ int _cheatKeyCtr;
+
+ // Object display fields
+ int _selectedObject;
+ SpriteAsset *_objectSprites;
+ RGBList *_objectPalData;
+ int _objectFrameNumber;
+
+ void setFontMode(InterfaceFontMode newMode);
+ bool handleCheatKey(int32 keycode);
+ bool handleKeypress(int32 keycode);
+ void leaveScene();
+public:
+ MadsInterfaceView(MadsM4Engine *vm);
+ ~MadsInterfaceView();
+
+ virtual void initialise();
+ virtual void setSelectedObject(int objectNumber);
+ virtual void addObjectToInventory(int objectNumber);
+ int getSelectedObject() { return _selectedObject; }
+ int getInventoryObject(int objectIndex) { return _inventoryList[objectIndex]; }
+
+ void onRefresh(RectList *rects, M4Surface *destSurface);
+ bool onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents);
+};
+
} // End of namespace M4
#endif
diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp
index e82a9976a5..c7b4f76a00 100644
--- a/engines/m4/mads_views.cpp
+++ b/engines/m4/mads_views.cpp
@@ -24,6 +24,7 @@
*/
#include "m4/m4_views.h"
+#include "m4/animation.h"
#include "m4/dialogs.h"
#include "m4/events.h"
#include "m4/font.h"
@@ -36,10 +37,19 @@
namespace M4 {
-static const int INV_ANIM_FRAME_SPEED = 2;
-static const int INVENTORY_X = 160;
-static const int INVENTORY_Y = 159;
-static const int SCROLLER_DELAY = 200;
+bool MadsSpriteSlot::operator==(const SpriteSlotSubset &other) const {
+ return (spriteListIndex == other.spriteListIndex) && (frameNumber == other.frameNumber) &&
+ (xp == other.xp) && (yp == other.yp) && (depth == other.depth) && (scale == other.scale);
+}
+
+void MadsSpriteSlot::copy(const SpriteSlotSubset &other) {
+ spriteListIndex = other.spriteListIndex;
+ frameNumber = other.frameNumber;
+ xp = other.xp;
+ yp = other.yp;
+ depth = other.depth;
+ scale = other.scale;
+}
//--------------------------------------------------------------------------
@@ -52,14 +62,21 @@ MadsSpriteSlots::MadsSpriteSlots(MadsView &owner): _owner(owner) {
startIndex = 0;
}
+MadsSpriteSlots::~MadsSpriteSlots() {
+ for (uint i = 0; i < _sprites.size(); ++i)
+ delete _sprites[i];
+}
+
void MadsSpriteSlots::clear() {
_owner._textDisplay.clear();
+ for (uint i = 0; i < _sprites.size(); ++i)
+ delete _sprites[i];
_sprites.clear();
// Reset the sprite slots list back to a single entry for a full screen refresh
startIndex = 1;
_entries[0].spriteType = FULL_SCREEN_REFRESH;
- _entries[0].timerIndex = -1;
+ _entries[0].seqIndex = -1;
}
int MadsSpriteSlots::getIndex() {
@@ -74,20 +91,31 @@ int MadsSpriteSlots::addSprites(const char *resName) {
Common::SeekableReadStream *data = _vm->res()->get(resName);
SpriteAsset *spriteSet = new SpriteAsset(_vm, data, data->size(), resName);
spriteSet->translate(_madsVm->_palette);
+ assert(spriteSet != NULL);
- _sprites.push_back(SpriteList::value_type(spriteSet));
+ _sprites.push_back(spriteSet);
_vm->res()->toss(resName);
return _sprites.size() - 1;
}
+void MadsSpriteSlots::deleteSprites(int listIndex) {
+ if (listIndex < 0)
+ return;
+
+ delete _sprites[listIndex];
+ _sprites[listIndex] = NULL;
+ if (listIndex == ((int)_sprites.size() - 1))
+ _sprites.remove_at(listIndex);
+}
+
/*
* Deletes the sprite slot with the given timer entry
*/
-void MadsSpriteSlots::deleteTimer(int timerIndex) {
+void MadsSpriteSlots::deleteTimer(int seqIndex) {
for (int idx = 0; idx < startIndex; ++idx) {
- if (_entries[idx].timerIndex == timerIndex)
- _entries[idx].spriteType = -1;
+ if (_entries[idx].seqIndex == seqIndex)
+ _entries[idx].spriteType = EXPIRED_SPRITE;
}
}
@@ -128,10 +156,10 @@ void MadsSpriteSlots::drawBackground() {
if (_entries[i].depth <= 1) {
// No depth, so simply copy the frame onto the background
- frame->copyTo(_owner._bgSurface, xp, yp);
+ frame->copyTo(_owner._bgSurface, xp, yp, 0);
} else {
// Depth was specified, so draw frame using scene's depth information
- frame->copyTo(_owner._bgSurface, xp, yp, _entries[i].depth, _owner._depthSurface, 100);
+ frame->copyTo(_owner._bgSurface, xp, yp, _entries[i].depth, _owner._depthSurface, 100, 0);
}
}
}
@@ -142,7 +170,7 @@ void MadsSpriteSlots::drawBackground() {
_owner._dirtyAreas[i].active = false;
}
-void MadsSpriteSlots::drawForeground(View *view) {
+void MadsSpriteSlots::drawForeground(View *view, int yOffset) {
DepthList depthList;
// Get a list of sprite object depths for active objects
@@ -162,13 +190,13 @@ void MadsSpriteSlots::drawForeground(View *view) {
DepthEntry &de = *i;
MadsSpriteSlot &slot = _entries[de.index];
assert(slot.spriteListIndex < (int)_sprites.size());
- SpriteAsset &spriteSet = *_sprites[slot.spriteListIndex].get();
+ SpriteAsset &spriteSet = *_sprites[slot.spriteListIndex];
if (slot.scale < 100) {
// Minimalised drawing
assert(slot.spriteListIndex < (int)_sprites.size());
- M4Sprite *spr = spriteSet.getFrame(slot.frameNumber - 1);
- spr->copyTo(view, slot.xp, slot.yp, slot.depth, _owner._depthSurface, slot.scale, 0);
+ M4Sprite *spr = spriteSet.getFrame((slot.frameNumber & 0x7fff) - 1);
+ spr->copyTo(view, slot.xp, slot.yp + yOffset, slot.depth, _owner._depthSurface, slot.scale, 0);
} else {
int xp, yp;
M4Sprite *spr = spriteSet.getFrame(slot.frameNumber - 1);
@@ -183,10 +211,10 @@ void MadsSpriteSlots::drawForeground(View *view) {
if (slot.depth > 1) {
// Draw the frame with depth processing
- spr->copyTo(view, xp, yp, slot.depth, _owner._depthSurface, 100, 0);
+ spr->copyTo(view, xp, yp + yOffset, slot.depth, _owner._depthSurface, 100, 0);
} else {
// No depth, so simply draw the image
- spr->copyTo(view, xp, yp, 0);
+ spr->copyTo(view, xp, yp + yOffset, 0);
}
}
}
@@ -204,6 +232,16 @@ void MadsSpriteSlots::setDirtyAreas() {
}
/**
+ * Flags the entire screen to be redrawn during the next drawing cycle
+ */
+void MadsSpriteSlots::fullRefresh() {
+ int idx = getIndex();
+
+ _entries[idx].spriteType = FULL_SCREEN_REFRESH;
+ _entries[idx].seqIndex = -1;
+}
+
+/**
* Removes any sprite slots that are no longer needed
*/
void MadsSpriteSlots::cleanUp() {
@@ -288,13 +326,12 @@ void MadsTextDisplay::setDirtyAreas2() {
}
}
-void MadsTextDisplay::draw(View *view) {
+void MadsTextDisplay::draw(View *view, int yOffset) {
for (uint idx = 0; idx < _entries.size(); ++idx) {
if (_entries[idx].active && (_entries[idx].expire >= 0)) {
- _entries[idx].font->setColours(_entries[idx].colour1,
- (_entries[idx].colour2 == 0) ? _entries[idx].colour1 : _entries[idx].colour2, 0xff);
+ _entries[idx].font->setColours(_entries[idx].colour1, _entries[idx].colour2, 0);
_entries[idx].font->writeString(view, _entries[idx].msg,
- _entries[idx].bounds.left, _entries[idx].bounds.top, _entries[idx].bounds.width(),
+ _entries[idx].bounds.left, _entries[idx].bounds.top + yOffset, _entries[idx].bounds.width(),
_entries[idx].spacing);
}
}
@@ -324,12 +361,13 @@ void MadsTextDisplay::cleanUp() {
MadsKernelMessageList::MadsKernelMessageList(MadsView &owner): _owner(owner) {
for (int i = 0; i < TIMED_TEXT_SIZE; ++i) {
- MadsKernelMessageListEntry rec;
+ MadsKernelMessageEntry rec;
_entries.push_back(rec);
}
_owner._textSpacing = -1;
_talkFont = _vm->_font->getFont(FONT_CONVERSATION_MADS);
+ word_8469E = 0;
}
void MadsKernelMessageList::clear() {
@@ -340,20 +378,20 @@ void MadsKernelMessageList::clear() {
_talkFont = _vm->_font->getFont(FONT_CONVERSATION_MADS);
}
-int MadsKernelMessageList::add(const Common::Point &pt, uint fontColour, uint8 flags, uint8 v2, uint32 timeout, const char *msg) {
+int MadsKernelMessageList::add(const Common::Point &pt, uint fontColour, uint8 flags, uint8 abortTimers, uint32 timeout, const char *msg) {
// Find a free slot
uint idx = 0;
while ((idx < _entries.size()) && ((_entries[idx].flags & KMSG_ACTIVE) != 0))
++idx;
if (idx == _entries.size()) {
- if (v2 == 0)
+ if (abortTimers == 0)
return -1;
error("MadsKernelList overflow");
}
- MadsKernelMessageListEntry &rec = _entries[idx];
- rec.msg = msg;
+ MadsKernelMessageEntry &rec = _entries[idx];
+ strcpy(rec.msg, msg);
rec.flags = flags | KMSG_ACTIVE;
rec.colour1 = fontColour & 0xff;
rec.colour2 = fontColour >> 8;
@@ -361,37 +399,37 @@ int MadsKernelMessageList::add(const Common::Point &pt, uint fontColour, uint8 f
rec.textDisplayIndex = -1;
rec.timeout = timeout;
rec.frameTimer = _madsVm->_currentTimer;
- rec.field_1C = v2;
+ rec.abortTimers = abortTimers;
rec.abortMode = _owner._abortTimersMode2;
for (int i = 0; i < 3; ++i)
rec.actionNouns[i] = _madsVm->scene()->actionNouns[i];
- if (flags & KMSG_2)
+ if (flags & KMSG_OWNER_TIMEOUT)
rec.frameTimer = _owner._ticksAmount + _owner._newTimeout;
return idx;
}
-int MadsKernelMessageList::addQuote(int quoteId, int v2, uint32 timeout) {
+int MadsKernelMessageList::addQuote(int quoteId, int abortTimers, uint32 timeout) {
const char *quoteStr = _madsVm->globals()->getQuote(quoteId);
- return add(Common::Point(0, 0), 0x1110, KMSG_2 | KMSG_20, v2, timeout, quoteStr);
+ return add(Common::Point(0, 0), 0x1110, KMSG_OWNER_TIMEOUT | KMSG_CENTER_ALIGN, abortTimers, timeout, quoteStr);
}
-void MadsKernelMessageList::unk1(int msgIndex, int v1, int v2) {
+void MadsKernelMessageList::scrollMessage(int msgIndex, int numTicks, bool quoted) {
if (msgIndex < 0)
return;
- _entries[msgIndex].flags |= (v2 == 0) ? KMSG_8 : (KMSG_8 | KMSG_1);
+ _entries[msgIndex].flags |= quoted ? (KMSG_SCROLL | KMSG_QUOTED) : KMSG_SCROLL;
_entries[msgIndex].msgOffset = 0;
- _entries[msgIndex].field_E = v1;
+ _entries[msgIndex].numTicks = numTicks;
_entries[msgIndex].frameTimer2 = _madsVm->_currentTimer;
const char *msgP = _entries[msgIndex].msg;
_entries[msgIndex].asciiChar = *msgP;
_entries[msgIndex].asciiChar2 = *(msgP + 1);
- if (_entries[msgIndex].flags & KMSG_2)
+ if (_entries[msgIndex].flags & KMSG_OWNER_TIMEOUT)
_entries[msgIndex].frameTimer2 = _owner._ticksAmount + _owner._newTimeout;
_entries[msgIndex].frameTimer = _entries[msgIndex].frameTimer2;
@@ -399,18 +437,18 @@ void MadsKernelMessageList::unk1(int msgIndex, int v1, int v2) {
void MadsKernelMessageList::setSeqIndex(int msgIndex, int seqIndex) {
if (msgIndex >= 0) {
- _entries[msgIndex].flags |= KMSG_4;
+ _entries[msgIndex].flags |= KMSG_SEQ_ENTRY;
_entries[msgIndex].sequenceIndex = seqIndex;
}
}
void MadsKernelMessageList::remove(int msgIndex) {
- MadsKernelMessageListEntry &rec = _entries[msgIndex];
+ MadsKernelMessageEntry &rec = _entries[msgIndex];
if (rec.flags & KMSG_ACTIVE) {
- if (rec.flags & KMSG_8) {
- //*(rec.msg + rec.msgOffset) = rec.asciiChar;
- //*(rec.msg + rec.msgOffset + 1) = rec.asciiChar2;
+ if (rec.flags & KMSG_SCROLL) {
+ *(rec.msg + rec.msgOffset) = rec.asciiChar;
+ *(rec.msg + rec.msgOffset + 1) = rec.asciiChar2;
}
if (rec.textDisplayIndex >= 0)
@@ -427,6 +465,136 @@ void MadsKernelMessageList::reset() {
// sub_20454
}
+void MadsKernelMessageList::update() {
+ uint32 currentTimer = _madsVm->_currentTimer;
+
+ for (uint i = 0; i < _entries.size(); ++i) {
+ if (((_entries[i].flags & KMSG_ACTIVE) != 0) && (currentTimer >= _entries[i].frameTimer))
+ processText(i);
+ }
+}
+
+void MadsKernelMessageList::processText(int msgIndex) {
+ MadsKernelMessageEntry &msg = _entries[msgIndex];
+ uint32 currentTimer = _madsVm->_currentTimer;
+ bool flag = false;
+
+ if ((msg.flags & KMSG_EXPIRE) != 0) {
+ _owner._textDisplay.expire(msg.textDisplayIndex);
+ msg.flags &= !KMSG_ACTIVE;
+ return;
+ }
+
+ if ((msg.flags & KMSG_SCROLL) == 0) {
+ msg.timeout -= 3;
+ }
+
+ if (msg.flags & KMSG_SEQ_ENTRY) {
+ MadsSequenceEntry &seqEntry = _owner._sequenceList[msg.sequenceIndex];
+ if (seqEntry.doneFlag || !seqEntry.active)
+ msg.timeout = 0;
+ }
+
+ if ((msg.timeout <= 0) && (_owner._abortTimers == 0)) {
+ msg.flags |= KMSG_EXPIRE;
+ if (msg.abortTimers != 0) {
+ _owner._abortTimers = msg.abortTimers;
+ _owner._abortTimersMode = msg.abortMode;
+
+ if (_owner._abortTimersMode != ABORTMODE_1) {
+ for (int i = 0; i < 3; ++i)
+ _madsVm->scene()->actionNouns[i] = msg.actionNouns[i];
+ }
+ }
+ }
+
+ msg.frameTimer = currentTimer + 3;
+ int x1 = 0, y1 = 0;
+
+ if (msg.flags & KMSG_SEQ_ENTRY) {
+ MadsSequenceEntry &seqEntry = _owner._sequenceList[msg.sequenceIndex];
+ if (!seqEntry.nonFixed) {
+ SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(seqEntry.spriteListIndex);
+ M4Sprite *frame = spriteSet.getFrame(seqEntry.frameIndex - 1);
+ x1 = frame->bounds().left;
+ y1 = frame->bounds().top;
+ } else {
+ x1 = seqEntry.msgPos.x;
+ y1 = seqEntry.msgPos.y;
+ }
+ }
+
+ if (msg.flags & KMSG_OWNER_TIMEOUT) {
+ if (word_8469E != 0) {
+ // TODO: Figure out various flags
+ } else {
+ x1 = 160;
+ y1 = 78;
+ }
+ }
+
+ x1 += msg.position.x;
+ y1 += msg.position.y;
+
+ if ((msg.flags & KMSG_SCROLL) && (msg.frameTimer >= currentTimer)) {
+ msg.msg[msg.msgOffset] = msg.asciiChar;
+ char *msgP = &msg.msg[++msg.msgOffset];
+ *msgP = msg.asciiChar2;
+
+ msg.asciiChar = *msgP;
+ msg.asciiChar2 = *(msgP + 1);
+
+ if (!msg.asciiChar) {
+ // End of message
+ *msgP = '\0';
+ msg.flags &= ~KMSG_SCROLL;
+ } else if (msg.flags & KMSG_QUOTED) {
+ *msgP = '"';
+ *(msgP + 1) = '\0';
+ }
+
+ msg.frameTimer = msg.frameTimer2 = currentTimer + msg.numTicks;
+ flag = true;
+ }
+
+ int strWidth = _talkFont->getWidth(msg.msg, _owner._textSpacing);
+
+ if (msg.flags & (KMSG_RIGHT_ALIGN | KMSG_CENTER_ALIGN)) {
+ x1 -= (msg.flags & KMSG_CENTER_ALIGN) ? strWidth / 2 : strWidth;
+ }
+
+ // Make sure text appears entirely on-screen
+ int x2 = x1 + strWidth;
+ if (x2 > MADS_SURFACE_WIDTH)
+ x1 -= x2 - MADS_SURFACE_WIDTH;
+ if (x1 > (MADS_SURFACE_WIDTH - 1))
+ x1 = MADS_SURFACE_WIDTH - 1;
+ if (x1 < 0)
+ x1 = 0;
+
+ if (y1 > (MADS_SURFACE_HEIGHT - 1))
+ y1 = MADS_SURFACE_HEIGHT - 1;
+ if (y1 < 0)
+ y1 = 0;
+
+ if (msg.textDisplayIndex >= 0) {
+ MadsTextDisplayEntry textEntry = _owner._textDisplay[msg.textDisplayIndex];
+
+ if (flag || (textEntry.bounds.left != x1) || (textEntry.bounds.top != y1)) {
+ // Mark the associated text entry as deleted, so it can be re-created
+ _owner._textDisplay.expire(msg.textDisplayIndex);
+ msg.textDisplayIndex = -1;
+ }
+ }
+
+ if (msg.textDisplayIndex < 0) {
+ // Need to create a new text display entry for this message
+ int idx = _owner._textDisplay.add(x1, y1, msg.colour1 | (msg.colour2 << 8), _owner._textSpacing, msg.msg, _talkFont);
+ if (idx >= 0)
+ msg.textDisplayIndex = idx;
+ }
+}
+
//--------------------------------------------------------------------------
/**
@@ -687,10 +855,10 @@ void MadsDirtyAreas::mergeAreas(int idx1, int idx2) {
da1.textActive = true;
}
-void MadsDirtyAreas::copy(M4Surface *dest, M4Surface *src) {
+void MadsDirtyAreas::copy(M4Surface *dest, M4Surface *src, int yOffset) {
for (uint i = 0; i < _entries.size(); ++i) {
if (_entries[i].active && _entries[i].bounds.isValidRect())
- src->copyTo(dest, _entries[i].bounds, _entries[i].bounds.left, _entries[i].bounds.top);
+ src->copyTo(dest, _entries[i].bounds, _entries[i].bounds.left, _entries[i].bounds.top + yOffset);
}
}
@@ -725,14 +893,14 @@ bool MadsSequenceList::addSubEntry(int index, SequenceSubEntryMode mode, int fra
}
int MadsSequenceList::add(int spriteListIndex, int v0, int frameIndex, int triggerCountdown, int delayTicks, int extraTicks, int numTicks,
- int height, int width, char field_12, char scale, uint8 depth, int frameInc, SpriteAnimType animType, int numSprites,
+ int msgX, int msgY, bool nonFixed, char scale, uint8 depth, int frameInc, SpriteAnimType animType, int numSprites,
int frameStart) {
// Find a free slot
- uint timerIndex = 0;
- while ((timerIndex < _entries.size()) && (_entries[timerIndex].active))
- ++timerIndex;
- if (timerIndex == _entries.size())
+ uint seqIndex = 0;
+ while ((seqIndex < _entries.size()) && (_entries[seqIndex].active))
+ ++seqIndex;
+ if (seqIndex == _entries.size())
error("TimerList full");
if (frameStart <= 0)
@@ -743,76 +911,76 @@ int MadsSequenceList::add(int spriteListIndex, int v0, int frameIndex, int trigg
frameInc = 0;
// Set the list entry fields
- _entries[timerIndex].active = true;
- _entries[timerIndex].spriteListIndex = spriteListIndex;
- _entries[timerIndex].field_2 = v0;
- _entries[timerIndex].frameIndex = frameIndex;
- _entries[timerIndex].frameStart = frameStart;
- _entries[timerIndex].numSprites = numSprites;
- _entries[timerIndex].animType = animType;
- _entries[timerIndex].frameInc = frameInc;
- _entries[timerIndex].depth = depth;
- _entries[timerIndex].scale = scale;
- _entries[timerIndex].field_12 = field_12;
- _entries[timerIndex].width = width;
- _entries[timerIndex].height = height;
- _entries[timerIndex].numTicks = numTicks;
- _entries[timerIndex].extraTicks = extraTicks;
-
- _entries[timerIndex].timeout = _madsVm->_currentTimer + delayTicks;
-
- _entries[timerIndex].triggerCountdown = triggerCountdown;
- _entries[timerIndex].doneFlag = false;
- _entries[timerIndex].field_13 = 0;
- _entries[timerIndex].dynamicHotspotIndex = -1;
- _entries[timerIndex].entries.count = 0;
- _entries[timerIndex].abortMode = _owner._abortTimersMode2;
+ _entries[seqIndex].active = true;
+ _entries[seqIndex].spriteListIndex = spriteListIndex;
+ _entries[seqIndex].field_2 = v0;
+ _entries[seqIndex].frameIndex = frameIndex;
+ _entries[seqIndex].frameStart = frameStart;
+ _entries[seqIndex].numSprites = numSprites;
+ _entries[seqIndex].animType = animType;
+ _entries[seqIndex].frameInc = frameInc;
+ _entries[seqIndex].depth = depth;
+ _entries[seqIndex].scale = scale;
+ _entries[seqIndex].nonFixed = nonFixed;
+ _entries[seqIndex].msgPos.x = msgX;
+ _entries[seqIndex].msgPos.y = msgY;
+ _entries[seqIndex].numTicks = numTicks;
+ _entries[seqIndex].extraTicks = extraTicks;
+
+ _entries[seqIndex].timeout = _madsVm->_currentTimer + delayTicks;
+
+ _entries[seqIndex].triggerCountdown = triggerCountdown;
+ _entries[seqIndex].doneFlag = false;
+ _entries[seqIndex].field_13 = 0;
+ _entries[seqIndex].dynamicHotspotIndex = -1;
+ _entries[seqIndex].entries.count = 0;
+ _entries[seqIndex].abortMode = _owner._abortTimersMode2;
for (int i = 0; i < 3; ++i)
- _entries[timerIndex].actionNouns[i] = _madsVm->scene()->actionNouns[i];
+ _entries[seqIndex].actionNouns[i] = _madsVm->scene()->actionNouns[i];
- return timerIndex;
+ return seqIndex;
}
-void MadsSequenceList::remove(int timerIndex) {
- if (_entries[timerIndex].active) {
- if (_entries[timerIndex].dynamicHotspotIndex >= 0)
- _owner._dynamicHotspots.remove(_entries[timerIndex].dynamicHotspotIndex);
+void MadsSequenceList::remove(int seqIndex) {
+ if (_entries[seqIndex].active) {
+ if (_entries[seqIndex].dynamicHotspotIndex >= 0)
+ _owner._dynamicHotspots.remove(_entries[seqIndex].dynamicHotspotIndex);
}
- _entries[timerIndex].active = false;
- _owner._spriteSlots.deleteTimer(timerIndex);
+ _entries[seqIndex].active = false;
+ _owner._spriteSlots.deleteTimer(seqIndex);
}
-void MadsSequenceList::setSpriteSlot(int timerIndex, MadsSpriteSlot &spriteSlot) {
- MadsSequenceEntry &timerEntry = _entries[timerIndex];
- SpriteAsset &sprite = _owner._spriteSlots.getSprite(timerEntry.spriteListIndex);
+void MadsSequenceList::setSpriteSlot(int seqIndex, MadsSpriteSlot &spriteSlot) {
+ MadsSequenceEntry &timerEntry = _entries[seqIndex];
+ SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(timerEntry.spriteListIndex);
- spriteSlot.spriteType = sprite.getAssetType() == 1 ? BACKGROUND_SPRITE : FOREGROUND_SPRITE;
- spriteSlot.timerIndex = timerIndex;
+ spriteSlot.spriteType = spriteSet.isBackground() ? BACKGROUND_SPRITE : FOREGROUND_SPRITE;
+ spriteSlot.seqIndex = seqIndex;
spriteSlot.spriteListIndex = timerEntry.spriteListIndex;
spriteSlot.frameNumber = ((timerEntry.field_2 == 1) ? 0x8000 : 0) | timerEntry.frameIndex;
spriteSlot.depth = timerEntry.depth;
spriteSlot.scale = timerEntry.scale;
- if (timerEntry.field_12 == 0) {
- spriteSlot.xp = timerEntry.width;
- spriteSlot.yp = timerEntry.height;
+ if (!timerEntry.nonFixed) {
+ spriteSlot.xp = timerEntry.msgPos.x;
+ spriteSlot.yp = timerEntry.msgPos.y;
} else {
- spriteSlot.xp = sprite.getFrame(timerEntry.frameIndex - 1)->x;
- spriteSlot.yp = sprite.getFrame(timerEntry.frameIndex - 1)->y;
+ spriteSlot.xp = spriteSet.getFrame(timerEntry.frameIndex - 1)->x;
+ spriteSlot.yp = spriteSet.getFrame(timerEntry.frameIndex - 1)->y;
}
}
-bool MadsSequenceList::loadSprites(int timerIndex) {
- MadsSequenceEntry &seqEntry = _entries[timerIndex];
+bool MadsSequenceList::loadSprites(int seqIndex) {
+ MadsSequenceEntry &seqEntry = _entries[seqIndex];
int slotIndex;
bool result = false;
int idx = -1;
- _owner._spriteSlots.deleteTimer(timerIndex);
+ _owner._spriteSlots.deleteTimer(seqIndex);
if (seqEntry.doneFlag) {
- remove(timerIndex);
+ remove(seqIndex);
return false;
}
@@ -821,7 +989,7 @@ bool MadsSequenceList::loadSprites(int timerIndex) {
seqEntry.doneFlag = true;
} else if ((slotIndex = _owner._spriteSlots.getIndex()) >= 0) {
MadsSpriteSlot &spriteSlot = _owner._spriteSlots[slotIndex];
- setSpriteSlot(timerIndex, spriteSlot);
+ setSpriteSlot(seqIndex, spriteSlot);
int x2 = 0, y2 = 0;
@@ -949,8 +1117,8 @@ void MadsSequenceList::delay(uint32 v1, uint32 v2) {
}
}
-void MadsSequenceList::setAnimRange(int timerIndex, int startVal, int endVal) {
- MadsSequenceEntry &seqEntry = _entries[timerIndex];
+void MadsSequenceList::setAnimRange(int seqIndex, int startVal, int endVal) {
+ MadsSequenceEntry &seqEntry = _entries[seqIndex];
SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(seqEntry.spriteListIndex);
int numSprites = spriteSet.getCount();
int tempStart = startVal, tempEnd = endVal;
@@ -983,10 +1151,28 @@ void MadsSequenceList::setAnimRange(int timerIndex, int startVal, int endVal) {
seqEntry.frameIndex = (seqEntry.frameInc < 0) ? tempStart : tempEnd;
}
+void MadsSequenceList::scan() {
+ for (uint i = 0; i < _entries.size(); ++i) {
+ if (!_entries[i].active && (_entries[i].spriteListIndex != -1)) {
+ int idx = _owner._spriteSlots.getIndex();
+ setSpriteSlot(i, _owner._spriteSlots[idx]);
+ }
+ }
+}
+
+//--------------------------------------------------------------------------
+
+Animation::Animation(MadsM4Engine *vm): _vm(vm) {
+}
+
+Animation::~Animation() {
+}
+
//--------------------------------------------------------------------------
MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceList(*this),
_kernelMessages(*this), _spriteSlots(*this), _dirtyAreas(*this), _textDisplay(*this) {
+
_textSpacing = -1;
_ticksAmount = 3;
_newTimeout = 0;
@@ -994,9 +1180,15 @@ MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceL
_abortTimers2 = 0;
_abortTimersMode = ABORTMODE_0;
_abortTimersMode2 = ABORTMODE_0;
-
+
+ _yOffset = 0;
_depthSurface = NULL;
_bgSurface = NULL;
+ _sceneAnimation = new MadsAnimation(_vm, this);
+}
+
+MadsView::~MadsView() {
+ delete _sceneAnimation;
}
void MadsView::refresh() {
@@ -1010,7 +1202,7 @@ void MadsView::refresh() {
_dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
// Copy dirty areas to the main display surface
- _dirtyAreas.copy(_view, _bgSurface);
+ _dirtyAreas.copy(_view, _bgSurface, _yOffset);
// Handle dirty areas for foreground objects
_spriteSlots.setDirtyAreas();
@@ -1018,10 +1210,10 @@ void MadsView::refresh() {
_dirtyAreas.merge(1, DIRTY_AREAS_SIZE);
// Draw foreground sprites
- _spriteSlots.drawForeground(_view);
+ _spriteSlots.drawForeground(_view, _yOffset);
// Draw text elements onto the view
- _textDisplay.draw(_view);
+ _textDisplay.draw(_view, _yOffset);
// Remove any sprite slots that are no longer needed
_spriteSlots.cleanUp();
@@ -1030,427 +1222,4 @@ void MadsView::refresh() {
_textDisplay.cleanUp();
}
-/*--------------------------------------------------------------------------
- * MadsInterfaceView handles the user interface section at the bottom of
- * game screens in MADS games
- *--------------------------------------------------------------------------
- */
-
-MadsInterfaceView::MadsInterfaceView(MadsM4Engine *vm): GameInterfaceView(vm,
- Common::Rect(0, MADS_SURFACE_HEIGHT, vm->_screen->width(), vm->_screen->height())) {
- _screenType = VIEWID_INTERFACE;
- _highlightedElement = -1;
- _topIndex = 0;
- _selectedObject = -1;
- _cheatKeyCtr = 0;
-
- _objectSprites = NULL;
- _objectPalData = NULL;
-
- /* Set up the rect list for screen elements */
- // Actions
- for (int i = 0; i < 10; ++i)
- _screenObjects.addRect((i / 5) * 32 + 1, (i % 5) * 8 + MADS_SURFACE_HEIGHT + 2,
- ((i / 5) + 1) * 32 + 3, ((i % 5) + 1) * 8 + MADS_SURFACE_HEIGHT + 2);
-
- // Scroller elements (up arrow, scroller, down arrow)
- _screenObjects.addRect(73, 160, 82, 167);
- _screenObjects.addRect(73, 168, 82, 190);
- _screenObjects.addRect(73, 191, 82, 198);
-
- // Inventory object names
- for (int i = 0; i < 5; ++i)
- _screenObjects.addRect(89, 158 + i * 8, 160, 166 + i * 8);
-
- // Full rectangle area for all vocab actions
- for (int i = 0; i < 5; ++i)
- _screenObjects.addRect(239, 158 + i * 8, 320, 166 + i * 8);
-}
-
-MadsInterfaceView::~MadsInterfaceView() {
- delete _objectSprites;
-}
-
-void MadsInterfaceView::setFontMode(InterfaceFontMode newMode) {
- switch (newMode) {
- case ITEM_NORMAL:
- _vm->_font->setColors(4, 4, 0xff);
- break;
- case ITEM_HIGHLIGHTED:
- _vm->_font->setColors(5, 5, 0xff);
- break;
- case ITEM_SELECTED:
- _vm->_font->setColors(6, 6, 0xff);
- break;
- }
-}
-
-void MadsInterfaceView::initialise() {
- // Build up the inventory list
- _inventoryList.clear();
-
- for (uint i = 0; i < _madsVm->globals()->getObjectsSize(); ++i) {
- MadsObject *obj = _madsVm->globals()->getObject(i);
- if (obj->roomNumber == PLAYER_INVENTORY)
- _inventoryList.push_back(i);
- }
-
- // If the inventory has at least one object, select it
- if (_inventoryList.size() > 0)
- setSelectedObject(_inventoryList[0]);
-}
-
-void MadsInterfaceView::setSelectedObject(int objectNumber) {
- char resName[80];
-
- // Load inventory resource
- if (_objectSprites) {
- _vm->_palette->deleteRange(_objectPalData);
- delete _objectSprites;
- }
-
- // Check to make sure the object is in the inventory, and also visible on-screen
- int idx = _inventoryList.indexOf(objectNumber);
- if (idx == -1) {
- // Object wasn't found, so return
- _selectedObject = -1;
- return;
- }
-
- // Found the object
- if (idx < _topIndex)
- _topIndex = idx;
- else if (idx >= (_topIndex + 5))
- _topIndex = MAX(0, idx - 4);
-
- _selectedObject = objectNumber;
- sprintf(resName, "*OB%.3dI.SS", objectNumber);
-
- Common::SeekableReadStream *data = _vm->res()->get(resName);
- _objectSprites = new SpriteAsset(_vm, data, data->size(), resName);
- _vm->res()->toss(resName);
-
- // Slot it into available palette space
- _objectPalData = _objectSprites->getRgbList();
- _vm->_palette->addRange(_objectPalData);
- _objectSprites->translate(_objectPalData, true);
-
- _objectFrameNumber = 0;
-}
-
-void MadsInterfaceView::addObjectToInventory(int objectNumber) {
- if (_inventoryList.indexOf(objectNumber) == -1) {
- _madsVm->globals()->getObject(objectNumber)->roomNumber = PLAYER_INVENTORY;
- _inventoryList.push_back(objectNumber);
- }
-
- setSelectedObject(objectNumber);
-}
-
-void MadsInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) {
- _vm->_font->setFont(FONT_INTERFACE_MADS);
- char buffer[100];
-
- // Check to see if any dialog is currently active
- bool dialogVisible = _vm->_viewManager->getView(LAYER_DIALOG) != NULL;
-
- // Highlighting logic for action list
- int actionIndex = 0;
- for (int x = 0; x < 2; ++x) {
- for (int y = 0; y < 5; ++y, ++actionIndex) {
- // Determine the font colour depending on whether an item is selected. Note that the first action,
- // 'Look', is always 'selected', even when another action is clicked on
- setFontMode((_highlightedElement == actionIndex) ? ITEM_HIGHLIGHTED :
- ((actionIndex == 0) ? ITEM_SELECTED : ITEM_NORMAL));
-
- // Get the verb action and capitalise it
- const char *verbStr = _madsVm->globals()->getVocab(kVerbLook + actionIndex);
- strcpy(buffer, verbStr);
- if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
-
- // Display the verb
- const Common::Rect r(_screenObjects[actionIndex]);
- _vm->_font->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
- }
- }
-
- // Check for highlighting of the scrollbar controls
- if ((_highlightedElement == SCROLL_UP) || (_highlightedElement == SCROLL_SCROLLER) || (_highlightedElement == SCROLL_DOWN)) {
- // Highlight the control's borders
- const Common::Rect r(_screenObjects[_highlightedElement]);
- destSurface->frameRect(r, 5);
- }
-
- // Draw the horizontal line in the scroller representing the current top selected
- const Common::Rect scroller(_screenObjects[SCROLL_SCROLLER]);
- int yP = (_inventoryList.size() < 2) ? 0 : (scroller.height() - 5) * _topIndex / (_inventoryList.size() - 1);
- destSurface->setColor(4);
- destSurface->hLine(scroller.left + 2, scroller.right - 3, scroller.top + 2 + yP);
-
- // List inventory items
- for (uint i = 0; i < 5; ++i) {
- if ((_topIndex + i) >= _inventoryList.size())
- break;
-
- const char *descStr = _madsVm->globals()->getVocab(_madsVm->globals()->getObject(
- _inventoryList[_topIndex + i])->descId);
- strcpy(buffer, descStr);
- if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
-
- const Common::Rect r(_screenObjects[INVLIST_START + i]);
-
- // Set the highlighting of the inventory item
- if (_highlightedElement == (int)(INVLIST_START + i)) setFontMode(ITEM_HIGHLIGHTED);
- else if (_selectedObject == _inventoryList[_topIndex + i]) setFontMode(ITEM_SELECTED);
- else setFontMode(ITEM_NORMAL);
-
- // Write out it's description
- _vm->_font->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
- }
-
- // Handle the display of any currently selected object
- if (_objectSprites) {
- // Display object sprite. Note that the frame number isn't used directly, because it would result
- // in too fast an animation
- M4Sprite *spr = _objectSprites->getFrame(_objectFrameNumber / INV_ANIM_FRAME_SPEED);
- spr->copyTo(destSurface, INVENTORY_X, INVENTORY_Y, 0);
-
- if (!_madsVm->globals()->_config.invObjectsStill && !dialogVisible) {
- // If objects need to be animated, move to the next frame
- if (++_objectFrameNumber >= (_objectSprites->getCount() * INV_ANIM_FRAME_SPEED))
- _objectFrameNumber = 0;
- }
-
- // List the vocab actions for the currently selected object
- MadsObject *obj = _madsVm->globals()->getObject(_selectedObject);
- int yIndex = MIN(_highlightedElement - VOCAB_START, obj->vocabCount - 1);
-
- for (int i = 0; i < obj->vocabCount; ++i) {
- const Common::Rect r(_screenObjects[VOCAB_START + i]);
-
- // Get the vocab description and capitalise it
- const char *descStr = _madsVm->globals()->getVocab(obj->vocabList[i].vocabId);
- strcpy(buffer, descStr);
- if ((buffer[0] >= 'a') && (buffer[0] <= 'z')) buffer[0] -= 'a' - 'A';
-
- // Set the highlighting and display the entry
- setFontMode((i == yIndex) ? ITEM_HIGHLIGHTED : ITEM_NORMAL);
- _vm->_font->writeString(destSurface, buffer, r.left, r.top, r.width(), 0);
- }
- }
-}
-
-bool MadsInterfaceView::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
- MadsAction &act = _madsVm->scene()->getAction();
-
- // If the mouse isn't being held down, then reset the repeated scroll timer
- if (eventType != MEVENT_LEFT_HOLD)
- _nextScrollerTicks = 0;
-
- // Handle various event types
- switch (eventType) {
- case MEVENT_MOVE:
- // If the cursor isn't in "wait mode", don't do any processing
- if (_vm->_mouse->getCursorNum() == CURSOR_WAIT)
- return true;
-
- // Ensure the cursor is the standard arrow
- _vm->_mouse->setCursorNum(CURSOR_ARROW);
-
- // Check if any interface element is currently highlighted
- _highlightedElement = _screenObjects.find(Common::Point(x, y));
-
- return true;
-
- case MEVENT_LEFT_CLICK:
- // Left mouse click
- {
- // Check if an inventory object was selected
- if ((_highlightedElement >= INVLIST_START) && (_highlightedElement < (INVLIST_START + 5))) {
- // Ensure there is an inventory item listed in that cell
- uint idx = _highlightedElement - INVLIST_START;
- if ((_topIndex + idx) < _inventoryList.size()) {
- // Set the selected object
- setSelectedObject(_inventoryList[_topIndex + idx]);
- }
- } else if ((_highlightedElement >= ACTIONS_START) && (_highlightedElement < (ACTIONS_START + 10))) {
- // A standard action was selected
- int verbId = kVerbLook + (_highlightedElement - ACTIONS_START);
- warning("Selected action #%d", verbId);
-
- } else if ((_highlightedElement >= VOCAB_START) && (_highlightedElement < (VOCAB_START + 5))) {
- // A vocab action was selected
- MadsObject *obj = _madsVm->globals()->getObject(_selectedObject);
- int vocabIndex = MIN(_highlightedElement - VOCAB_START, obj->vocabCount - 1);
- if (vocabIndex >= 0) {
- act._actionMode = ACTMODE_OBJECT;
- act._actionMode2 = ACTMODE2_2;
- act._flags1 = obj->vocabList[1].flags1;
- act._flags2 = obj->vocabList[1].flags2;
-
- act._currentHotspot = _selectedObject;
- act._articleNumber = act._flags2;
- }
- }
- }
- return true;
-
- case MEVENT_LEFT_HOLD:
- // Left mouse hold
- // Handle the scroller - the up/down buttons allow for multiple actions whilst the mouse is held down
- if ((_highlightedElement == SCROLL_UP) || (_highlightedElement == SCROLL_DOWN)) {
- if ((_nextScrollerTicks == 0) || (g_system->getMillis() >= _nextScrollerTicks)) {
- // Handle scroll up/down action
- _nextScrollerTicks = g_system->getMillis() + SCROLLER_DELAY;
-
- if ((_highlightedElement == SCROLL_UP) && (_topIndex > 0))
- --_topIndex;
- if ((_highlightedElement == SCROLL_DOWN) && (_topIndex < (int)(_inventoryList.size() - 1)))
- ++_topIndex;
- }
- }
- return true;
-
- case MEVENT_LEFT_DRAG:
- // Left mouse drag
- // Handle the the the scroller area that can be dragged to adjust the top displayed index
- if (_highlightedElement == SCROLL_SCROLLER) {
- // Calculate the new top index based on the Y position
- const Common::Rect r(_screenObjects[SCROLL_SCROLLER]);
- _topIndex = CLIP((int)(_inventoryList.size() - 1) * (y - r.top - 2) / (r.height() - 5),
- 0, (int)_inventoryList.size() - 1);
- }
- return true;
-
- case KEVENT_KEY:
- if (_cheatKeyCtr == CHEAT_SEQUENCE_MAX)
- handleCheatKey(param1);
- handleKeypress(param1);
- return true;
-
- default:
- break;
- }
-
- return false;
-}
-
-bool MadsInterfaceView::handleCheatKey(int32 keycode) {
- switch (keycode) {
- case Common::KEYCODE_SPACE:
- // TODO: Move player to current destination
- return true;
-
- case Common::KEYCODE_t | (Common::KEYCODE_LALT):
- case Common::KEYCODE_t | (Common::KEYCODE_RALT):
- {
- // Teleport to room
- //Scene *sceneView = (Scene *)vm->_viewManager->getView(VIEWID_SCENE);
-
-
- return true;
- }
-
- default:
- break;
- }
-
- return false;
-}
-
-const char *CHEAT_SEQUENCE = "widepipe";
-
-bool MadsInterfaceView::handleKeypress(int32 keycode) {
- int flags = keycode >> 24;
- int kc = keycode & 0xffff;
-
- // Capitalise the letter if necessary
- if (_cheatKeyCtr < CHEAT_SEQUENCE_MAX) {
- if ((flags & Common::KBD_CTRL) && (kc == CHEAT_SEQUENCE[_cheatKeyCtr])) {
- ++_cheatKeyCtr;
- if (_cheatKeyCtr == CHEAT_SEQUENCE_MAX)
- Dialog::display(_vm, 22, cheatingEnabledDesc);
- return true;
- } else {
- _cheatKeyCtr = 0;
- }
- }
-
- // Handle the various keys
- if ((keycode == Common::KEYCODE_ESCAPE) || (keycode == Common::KEYCODE_F1)) {
- // Game menu
- _madsVm->globals()->dialogType = DIALOG_GAME_MENU;
- leaveScene();
- return false;
- } else if (flags & Common::KBD_CTRL) {
- // Handling of the different control key combinations
- switch (kc) {
- case Common::KEYCODE_i:
- // Mouse to inventory
- warning("TODO: Mouse to inventory");
- break;
-
- case Common::KEYCODE_k:
- // Toggle hotspots
- warning("TODO: Toggle hotspots");
- break;
-
- case Common::KEYCODE_p:
- // Player stats
- warning("TODO: Player stats");
- break;
-
- case Common::KEYCODE_q:
- // Quit game
- break;
-
- case Common::KEYCODE_s:
- // Activate sound
- warning("TODO: Activate sound");
- break;
-
- case Common::KEYCODE_u:
- // Rotate player
- warning("TODO: Rotate player");
- break;
-
- case Common::KEYCODE_v: {
- // Release version
- Dialog *dlg = new Dialog(_vm, GameReleaseInfoStr, GameReleaseTitleStr);
- _vm->_viewManager->addView(dlg);
- _vm->_viewManager->moveToFront(dlg);
- return false;
- }
-
- default:
- break;
- }
- } else if ((flags & Common::KBD_ALT) && (kc == Common::KEYCODE_q)) {
- // Quit Game
-
- } else {
- // Standard keypresses
- switch (kc) {
- case Common::KEYCODE_F2:
- // Save game
- _madsVm->globals()->dialogType = DIALOG_SAVE;
- leaveScene();
- break;
- case Common::KEYCODE_F3:
- // Restore game
- _madsVm->globals()->dialogType = DIALOG_RESTORE;
- leaveScene();
- break;
- }
- }
-//DIALOG_OPTIONS
- return false;
-}
-
-void MadsInterfaceView::leaveScene() {
- // Close the scene
- View *view = _madsVm->_viewManager->getView(VIEWID_SCENE);
- _madsVm->_viewManager->deleteView(view);
-}
-
} // End of namespace M4
diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h
index 3b64cc77f2..29adb7048a 100644
--- a/engines/m4/mads_views.h
+++ b/engines/m4/mads_views.h
@@ -34,19 +34,24 @@
namespace M4 {
-#define MADS_SURFACE_WIDTH 320
-#define MADS_SURFACE_HEIGHT 156
-#define MADS_SCREEN_HEIGHT 200
-#define MADS_Y_OFFSET ((MADS_SCREEN_HEIGHT - MADS_SURFACE_HEIGHT) / 2)
-
class MadsView;
enum AbortTimerMode {ABORTMODE_0 = 0, ABORTMODE_1 = 1, ABORTMODE_2 = 2};
+class SpriteSlotSubset {
+public:
+ int spriteListIndex;
+ int frameNumber;
+ int xp;
+ int yp;
+ int depth;
+ int scale;
+};
+
class MadsSpriteSlot {
public:
int spriteType;
- int timerIndex;
+ int seqIndex;
int spriteListIndex;
int frameNumber;
int xp;
@@ -55,25 +60,27 @@ public:
int scale;
MadsSpriteSlot() { }
+
+ bool operator==(const SpriteSlotSubset &other) const;
+ void copy(const SpriteSlotSubset &other);
};
#define SPRITE_SLOTS_SIZE 50
enum SpriteIdSpecial {
- BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, FOREGROUND_SPRITE = 1
+ BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, EXPIRED_SPRITE = -1, SPRITE_ZERO = 0, FOREGROUND_SPRITE = 1
};
-typedef Common::Array<Common::SharedPtr<SpriteAsset> > SpriteList;
-
class MadsSpriteSlots {
private:
MadsView &_owner;
Common::Array<MadsSpriteSlot> _entries;
- SpriteList _sprites;
+ Common::Array<SpriteAsset *> _sprites;
public:
int startIndex;
MadsSpriteSlots(MadsView &owner);
+ ~MadsSpriteSlots();
MadsSpriteSlot &operator[](int idx) {
assert(idx < SPRITE_SLOTS_SIZE);
@@ -81,17 +88,19 @@ public:
}
SpriteAsset &getSprite(int idx) {
assert(idx < (int)_sprites.size());
- return *_sprites[idx].get();
+ return *_sprites[idx];
}
int getIndex();
int addSprites(const char *resName);
+ void deleteSprites(int listIndex);
void clear();
- void deleteTimer(int timerIndex);
+ void deleteTimer(int seqIndex);
void drawBackground();
- void drawForeground(View *view);
+ void drawForeground(View *view, int yOffset);
void setDirtyAreas();
+ void fullRefresh();
void cleanUp();
};
@@ -130,18 +139,19 @@ public:
int add(int xp, int yp, uint fontColour, int charSpacing, const char *msg, Font *font);
void clear();
- void draw(View *view);
+ void draw(View *view, int yOffset);
void setDirtyAreas();
void setDirtyAreas2();
void cleanUp();
};
#define TIMED_TEXT_SIZE 10
-#define TEXT_4A_SIZE 30
+#define INDEFINITE_TIMEOUT 9999999
-enum KernelMessageFlags {KMSG_1 = 1, KMSG_2 = 2, KMSG_4 = 4, KMSG_8 = 8, KMSG_20 = 0x20, KMSG_40 = 0x40, KMSG_ACTIVE = 0x80};
+enum KernelMessageFlags {KMSG_QUOTED = 1, KMSG_OWNER_TIMEOUT = 2, KMSG_SEQ_ENTRY = 4, KMSG_SCROLL = 8, KMSG_RIGHT_ALIGN = 0x10,
+ KMSG_CENTER_ALIGN = 0x20, KMSG_EXPIRE = 0x40, KMSG_ACTIVE = 0x80};
-class MadsKernelMessageListEntry {
+class MadsKernelMessageEntry {
public:
uint8 flags;
int sequenceIndex;
@@ -152,31 +162,35 @@ public:
Common::Point position;
int textDisplayIndex;
int msgOffset;
- int field_E;
+ int numTicks;
uint32 frameTimer2;
uint32 frameTimer;
uint32 timeout;
- bool field_1C;
+ int abortTimers;
AbortTimerMode abortMode;
uint16 actionNouns[3];
- const char *msg;
+ char msg[100];
};
class MadsKernelMessageList {
private:
MadsView &_owner;
- Common::Array<MadsKernelMessageListEntry> _entries;
+ Common::Array<MadsKernelMessageEntry> _entries;
Font *_talkFont;
public:
+ int word_8469E;
+public:
MadsKernelMessageList(MadsView &owner);
void clear();
- int add(const Common::Point &pt, uint fontColour, uint8 flags, uint8 v2, uint32 timeout, const char *msg);
- int addQuote(int quoteId, int v2, uint32 timeout);
- void unk1(int msgIndex, int v1, int v2);
+ int add(const Common::Point &pt, uint fontColour, uint8 flags, uint8 abortTimers, uint32 timeout, const char *msg);
+ int addQuote(int quoteId, int abortTimers, uint32 timeout);
+ void scrollMessage(int msgIndex, int numTicks, bool quoted);
void setSeqIndex(int msgIndex, int seqIndex);
void remove(int msgIndex);
void reset();
+ void update();
+ void processText(int msgIndex);
};
class ScreenObjectEntry {
@@ -275,7 +289,7 @@ public:
void merge(int startIndex, int count);
bool intersects(int idx1, int idx2);
void mergeAreas(int idx1, int idx2);
- void copy(M4Surface *dest, M4Surface *src);
+ void copy(M4Surface *dest, M4Surface *src, int yOffset);
};
enum SpriteAnimType {ANIMTYPE_CYCLED = 1, ANIMTYPE_REVERSIBLE = 2};
@@ -308,12 +322,10 @@ struct MadsSequenceEntry {
int scale;
int dynamicHotspotIndex;
- int field_12;
+ bool nonFixed;
int field_13;
- int width;
- int height;
-
+ Common::Point msgPos;
int triggerCountdown;
bool doneFlag;
MadsSequenceSubEntries entries;
@@ -338,20 +350,35 @@ public:
void clear();
bool addSubEntry(int index, SequenceSubEntryMode mode, int frameIndex, int abortVal);
int add(int spriteListIndex, int v0, int v1, int triggerCountdown, int delayTicks, int extraTicks, int numTicks,
- int height, int width, char field_12, char scale, uint8 depth, int frameInc, SpriteAnimType animType,
+ int msgX, int msgY, bool nonFixed, char scale, uint8 depth, int frameInc, SpriteAnimType animType,
int numSprites, int frameStart);
- void remove(int timerIndex);
- void setSpriteSlot(int timerIndex, MadsSpriteSlot &spriteSlot);
- bool loadSprites(int timerIndex);
+ void remove(int seqIndex);
+ void setSpriteSlot(int seqIndex, MadsSpriteSlot &spriteSlot);
+ bool loadSprites(int seqIndex);
void tick();
void delay(uint32 v1, uint32 v2);
- void setAnimRange(int timerIndex, int startVal, int endVal);
+ void setAnimRange(int seqIndex, int startVal, int endVal);
+ void scan();
};
+class Animation {
+protected:
+ MadsM4Engine *_vm;
+public:
+ Animation(MadsM4Engine *vm);
+ virtual ~Animation();
+ virtual void initialise(const Common::String &filename, uint16 flags, M4Surface *walkSurface, M4Surface *sceneSurface) = 0;
+ virtual void load(const Common::String &filename, int v0) = 0;
+ virtual void update() = 0;
+ virtual void setCurrentFrame(int frameNumber) = 0;
+};
+
+
class MadsView {
private:
View *_view;
public:
+ Animation *_sceneAnimation;
MadsSpriteSlots _spriteSlots;
MadsTextDisplay _textDisplay;
MadsKernelMessageList _kernelMessages;
@@ -371,62 +398,14 @@ public:
M4Surface *_depthSurface;
M4Surface *_bgSurface;
+ int _yOffset;
public:
MadsView(View *view);
+ ~MadsView();
void refresh();
};
-#define CHEAT_SEQUENCE_MAX 8
-
-class IntegerList : public Common::Array<int> {
-public:
- int indexOf(int v) {
- for (uint i = 0; i < size(); ++i)
- if (operator [](i) == v)
- return i;
- return -1;
- }
-};
-
-enum InterfaceFontMode {ITEM_NORMAL, ITEM_HIGHLIGHTED, ITEM_SELECTED};
-
-enum InterfaceObjects {ACTIONS_START = 0, SCROLL_UP = 10, SCROLL_SCROLLER = 11, SCROLL_DOWN = 12,
- INVLIST_START = 13, VOCAB_START = 18};
-
-class MadsInterfaceView : public GameInterfaceView {
-private:
- IntegerList _inventoryList;
- RectList _screenObjects;
- int _highlightedElement;
- int _topIndex;
- uint32 _nextScrollerTicks;
- int _cheatKeyCtr;
-
- // Object display fields
- int _selectedObject;
- SpriteAsset *_objectSprites;
- RGBList *_objectPalData;
- int _objectFrameNumber;
-
- void setFontMode(InterfaceFontMode newMode);
- bool handleCheatKey(int32 keycode);
- bool handleKeypress(int32 keycode);
- void leaveScene();
-public:
- MadsInterfaceView(MadsM4Engine *vm);
- ~MadsInterfaceView();
-
- virtual void initialise();
- virtual void setSelectedObject(int objectNumber);
- virtual void addObjectToInventory(int objectNumber);
- int getSelectedObject() { return _selectedObject; }
- int getInventoryObject(int objectIndex) { return _inventoryList[objectIndex]; }
-
- void onRefresh(RectList *rects, M4Surface *destSurface);
- bool onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents);
-};
-
}
#endif
diff --git a/engines/m4/viewmgr.h b/engines/m4/viewmgr.h
index 16c3d6ecc3..211e6087f4 100644
--- a/engines/m4/viewmgr.h
+++ b/engines/m4/viewmgr.h
@@ -42,6 +42,19 @@ namespace M4 {
class View;
class ViewManager;
+enum SceneTransition {
+ kTransitionNone = 0,
+ kTransitionFadeIn = 1,
+ kTransitionFadeIn2 = 2,
+ kTransitionBoxInBottomLeft = 3,
+ kTransitionBoxInBottomRight = 4,
+ kTransitionBoxInTopLeft = 5,
+ kTransitionBoxInTopRight = 6,
+ kTransitionPanLeftToRight = 7,
+ kTransitionPanRightToLeft = 8,
+ kTransitionCircleIn = 9
+};
+
enum {SCREEN_DIALOG, SCREEN_BUFFER, SCREEN_TEXT, SCREEN_TRANSPARENT};
enum ScreenEventType {SCREVENT_NONE = 0, SCREVENT_KEY = 1, SCREVENT_MOUSE = 2, SCREVENT_ALL = 3};
enum ScreenLayers {
diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp
index 389665db39..149b6b6eba 100644
--- a/engines/mohawk/console.cpp
+++ b/engines/mohawk/console.cpp
@@ -30,7 +30,7 @@
#include "mohawk/riven.h"
#include "mohawk/livingbooks.h"
#include "mohawk/sound.h"
-#include "mohawk/video/video.h"
+#include "mohawk/video.h"
namespace Mohawk {
diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp
index a7b1fe7fae..7f2e0cb312 100644
--- a/engines/mohawk/detection.cpp
+++ b/engines/mohawk/detection.cpp
@@ -341,6 +341,24 @@ static const MohawkGameDescription gameDescriptions[] = {
0,
},
+ // Myst Masterpiece Edition
+ // French Windows
+ // From gamin (Included in "Myst: La Trilogie")
+ {
+ {
+ "myst",
+ "Masterpiece Edition",
+ AD_ENTRY1("MYST.DAT", "aea81633b2d2ae498f09072fb87263b6"),
+ Common::FR_FRA,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+ GType_MYST,
+ GF_ME,
+ 0,
+ },
+
// Riven: The Sequel to Myst
// Version 1.0 (5CD)
// From clone2727
@@ -432,6 +450,24 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
+ // Version ? (DVD, From "Myst: La Trilogie")
+ // From gamin
+ {
+ {
+ "riven",
+ "",
+ AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"),
+ Common::FR_FRA,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ Common::GUIO_NONE
+ },
+ GType_RIVEN,
+ GF_DVD,
+ 0,
+ },
+
+ // Riven: The Sequel to Myst
// Version ? (Demo, From "Prince of Persia Collector's Edition")
// From Clone2727
{
diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp
index 35691c36aa..2ddfb47575 100644
--- a/engines/mohawk/graphics.cpp
+++ b/engines/mohawk/graphics.cpp
@@ -78,9 +78,8 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : _vm(vm) {
error("Myst requires greater than 256 colors to run");
if (_vm->getFeatures() & GF_ME) {
- // We want to delete our own JPEG surfaces, so don't free after use.
- _jpegDecoder = new JPEGDecoder(false);
- _pictDecoder = new MystPICT(_jpegDecoder);
+ _jpegDecoder = new Graphics::JPEGDecoder();
+ _pictDecoder = new Graphics::PictDecoder(_pixelFormat);
} else {
_jpegDecoder = NULL;
_pictDecoder = NULL;
@@ -152,9 +151,10 @@ void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Comm
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 == image) {
- if (_pictureFile.entries[i].type == 0)
- surface = _jpegDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size));
- else if (_pictureFile.entries[i].type == 1)
+ if (_pictureFile.entries[i].type == 0) {
+ Graphics::Surface *jpegSurface = _jpegDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size));
+ surface->copyFrom(*jpegSurface);
+ } else if (_pictureFile.entries[i].type == 1)
surface = _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);
diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h
index 8d28e1ff4b..dd1764e6d6 100644
--- a/engines/mohawk/graphics.h
+++ b/engines/mohawk/graphics.h
@@ -27,11 +27,11 @@
#define MOHAWK_GRAPHICS_H
#include "mohawk/bitmap.h"
-#include "mohawk/jpeg.h"
#include "mohawk/livingbooks.h"
-#include "mohawk/myst_pict.h"
#include "common/file.h"
+#include "graphics/pict.h"
+#include "graphics/video/codecs/mjpeg.h"
namespace Mohawk {
@@ -96,16 +96,16 @@ public:
void loadExternalPictureFile(uint16 stack);
void copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest);
void copyImageToScreen(uint16 image, Common::Rect dest);
- void showCursor(void);
- void hideCursor(void);
+ void showCursor();
+ void hideCursor();
void changeCursor(uint16);
void drawRect(Common::Rect rect, bool active);
private:
MohawkEngine_Myst *_vm;
MystBitmap *_bmpDecoder;
- MystPICT *_pictDecoder;
- JPEGDecoder *_jpegDecoder;
+ Graphics::PictDecoder *_pictDecoder;
+ Graphics::JPEGDecoder *_jpegDecoder;
Graphics::PixelFormat _pixelFormat;
struct PictureFile {
diff --git a/engines/mohawk/jpeg.cpp b/engines/mohawk/jpeg.cpp
deleted file mode 100644
index 07ec54dfea..0000000000
--- a/engines/mohawk/jpeg.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "common/system.h"
-#include "graphics/conversion.h" // For YUV2RGB
-
-#include "mohawk/jpeg.h"
-
-namespace Mohawk {
-
-JPEGDecoder::JPEGDecoder(bool freeSurfaceAfterUse) : Graphics::Codec(), _freeSurfaceAfterUse(freeSurfaceAfterUse) {
- _jpeg = new Graphics::JPEG();
- _pixelFormat = g_system->getScreenFormat();
- _surface = NULL;
-}
-
-JPEGDecoder::~JPEGDecoder() {
- delete _jpeg;
-
- if (_surface) {
- _surface->free();
- delete _surface;
- }
-}
-
-Graphics::Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream* stream) {
- _jpeg->read(stream);
- Graphics::Surface *ySurface = _jpeg->getComponent(1);
- Graphics::Surface *uSurface = _jpeg->getComponent(2);
- Graphics::Surface *vSurface = _jpeg->getComponent(3);
-
- Graphics::Surface *destSurface = NULL;
-
- // If we should free the surface after use, use the internal _surface storage
- // (this should be used when using as a Codec, as the Codecs should free their
- // surfaces when deleting the Codec object). Otherwise, create a new Surface
- // as the destination.
- if (_freeSurfaceAfterUse) {
- if (!_surface) {
- _surface = new Graphics::Surface();
- _surface->create(ySurface->w, ySurface->h, _pixelFormat.bytesPerPixel);
- }
- destSurface = _surface;
- } else {
- destSurface = new Graphics::Surface();
- destSurface->create(ySurface->w, ySurface->h, _pixelFormat.bytesPerPixel);
- }
-
- assert(destSurface);
-
- for (uint16 i = 0; i < destSurface->h; i++) {
- for (uint16 j = 0; j < destSurface->w; j++) {
- byte r = 0, g = 0, b = 0;
- Graphics::YUV2RGB(*((byte *)ySurface->getBasePtr(j, i)), *((byte *)uSurface->getBasePtr(j, i)), *((byte *)vSurface->getBasePtr(j, i)), r, g, b);
- if (_pixelFormat.bytesPerPixel == 2)
- *((uint16 *)destSurface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
- else
- *((uint32 *)destSurface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
- }
- }
-
- return destSurface;
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/jpeg.h b/engines/mohawk/jpeg.h
deleted file mode 100644
index ec87b1e7af..0000000000
--- a/engines/mohawk/jpeg.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_JPEG_H
-#define MOHAWK_JPEG_H
-
-#include "common/scummsys.h"
-#include "common/stream.h"
-
-#include "graphics/video/codecs/codec.h"
-#include "graphics/jpeg.h"
-#include "graphics/pixelformat.h"
-
-namespace Mohawk {
-
-// Mohawk's JPEG Decoder
-// Basically a wrapper around JPEG which converts to RGB and also functions
-// as a Codec.
-
-class JPEGDecoder : public Graphics::Codec {
-public:
- JPEGDecoder(bool freeSurfaceAfterUse);
- ~JPEGDecoder();
-
- Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
- Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
-
-private:
- Graphics::PixelFormat _pixelFormat;
- Graphics::JPEG *_jpeg;
- Graphics::Surface *_surface;
- bool _freeSurfaceAfterUse;
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk
index b224a8b143..bb79d4abac 100644
--- a/engines/mohawk/module.mk
+++ b/engines/mohawk/module.mk
@@ -6,11 +6,9 @@ MODULE_OBJS = \
detection.o \
dialogs.o \
graphics.o \
- jpeg.o \
livingbooks.o \
mohawk.o \
myst.o \
- myst_pict.o \
myst_vars.o \
myst_saveload.o \
myst_scripts.o \
@@ -22,13 +20,7 @@ MODULE_OBJS = \
riven_scripts.o \
riven_vars.o \
sound.o \
- video/cinepak.o \
- video/qdm2.o \
- video/qtrle.o \
- video/qt_player.o \
- video/rpza.o \
- video/smc.o \
- video/video.o
+ video.o
# This module can be built as a plugin
diff --git a/engines/mohawk/mohawk.cpp b/engines/mohawk/mohawk.cpp
index 5bde6bbeec..6b4d8bb2d2 100644
--- a/engines/mohawk/mohawk.cpp
+++ b/engines/mohawk/mohawk.cpp
@@ -35,7 +35,7 @@
#include "mohawk/mohawk.h"
#include "mohawk/dialogs.h"
#include "mohawk/sound.h"
-#include "mohawk/video/video.h"
+#include "mohawk/video.h"
#include "sound/mixer.h"
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index d1ef3b2137..9ff301c129 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -33,7 +33,7 @@
#include "mohawk/dialogs.h"
#include "mohawk/resource.h"
#include "mohawk/resource_cache.h"
-#include "mohawk/video/video.h"
+#include "mohawk/video.h"
namespace Mohawk {
diff --git a/engines/mohawk/myst_pict.cpp b/engines/mohawk/myst_pict.cpp
deleted file mode 100644
index 794ec9b87f..0000000000
--- a/engines/mohawk/myst_pict.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "common/system.h"
-
-#include "mohawk/myst_pict.h"
-
-namespace Mohawk {
-
-// The PICT code is based off of the QuickDraw specs:
-// http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-461.html
-
-MystPICT::MystPICT(JPEGDecoder *jpegDecoder) {
- _jpegDecoder = jpegDecoder;
- _pixelFormat = g_system->getScreenFormat();
-}
-
-Graphics::Surface *MystPICT::decodeImage(Common::SeekableReadStream *stream) {
- // Skip initial 512 bytes (all 0's)
- stream->seek(512, SEEK_CUR);
-
- // Read in the first part of the header
- /* uint16 fileSize = */ stream->readUint16BE();
-
- _imageRect.top = stream->readUint16BE();
- _imageRect.left = stream->readUint16BE();
- _imageRect.bottom = stream->readUint16BE();
- _imageRect.right = stream->readUint16BE();
- _imageRect.debugPrint(0, "PICT Rect:");
-
- Graphics::Surface *image = new Graphics::Surface();
- image->create(_imageRect.width(), _imageRect.height(), _pixelFormat.bytesPerPixel);
-
- // NOTE: This is only a subset of the full PICT format.
- // - Only V2 Images Supported
- // - JPEG Chunks are Supported
- // - DirectBitsRect Chunks are Supported
- for (uint32 opNum = 0; !stream->eos() && !stream->err() && stream->pos() < stream->size(); opNum++) {
- uint16 opcode = stream->readUint16BE();
- debug(2, "Found PICT opcode %04x", opcode);
-
- if (opNum == 0 && opcode != 0x0011)
- error ("Cannot find PICT version opcode");
- else if (opNum == 1 && opcode != 0x0C00)
- error ("Cannot find PICT header opcode");
-
- if (opcode == 0x0000) { // Nop
- stream->readUint16BE(); // Unknown
- } else if (opcode == 0x0001) { // Clip
- // Ignore
- uint16 clipSize = stream->readUint16BE();
- stream->seek(clipSize - 2, SEEK_CUR);
- } else if (opcode == 0x0007) { // PnSize
- // Ignore
- stream->readUint16BE();
- stream->readUint16BE();
- } else if (opcode == 0x0011) { // VersionOp
- uint16 version = stream->readUint16BE();
- if (version != 0x02FF)
- error ("Unknown PICT version");
- } else if (opcode == 0x001E) { // DefHilite
- // Ignore, Contains no Data
- } else if (opcode == 0x009A) { // DirectBitsRect
- decodeDirectBitsRect(stream, image);
- } else if (opcode == 0x00A1) { // LongComment
- stream->readUint16BE();
- uint16 dataSize = stream->readUint16BE();
- stream->seek(dataSize, SEEK_CUR);
- } else if (opcode == 0x00FF) { // OpEndPic
- stream->readUint16BE();
- break;
- } else if (opcode == 0x0C00) { // HeaderOp
- /* uint16 version = */ stream->readUint16BE();
- stream->readUint16BE(); // Reserved
- /* uint32 hRes = */ stream->readUint32BE();
- /* uint32 vRes = */ stream->readUint32BE();
- Common::Rect origResRect;
- origResRect.top = stream->readUint16BE();
- origResRect.left = stream->readUint16BE();
- origResRect.bottom = stream->readUint16BE();
- origResRect.right = stream->readUint16BE();
- stream->readUint32BE(); // Reserved
- } else if (opcode == 0x8200) { // CompressedQuickTime
- decodeCompressedQuickTime(stream, image);
- break;
- } else {
- error ("Unknown PICT opcode %04x", opcode);
- }
- }
-
- return image;
-}
-
-struct DirectBitsRectData {
- // PixMap
- struct {
- uint32 baseAddr;
- uint16 rowBytes;
- Common::Rect bounds;
- uint16 pmVersion;
- uint16 packType;
- uint32 packSize;
- uint32 hRes;
- uint32 vRes;
- uint16 pixelType;
- uint16 pixelSize;
- uint16 cmpCount;
- uint16 cmpSize;
- uint32 planeBytes;
- uint32 pmTable;
- uint32 pmReserved;
- } pixMap;
- Common::Rect srcRect;
- Common::Rect dstRect;
- uint16 mode;
-};
-
-void MystPICT::decodeDirectBitsRect(Common::SeekableReadStream *stream, Graphics::Surface *image) {
- static const Graphics::PixelFormat directBitsFormat16 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
-
- DirectBitsRectData directBitsData;
- directBitsData.pixMap.baseAddr = stream->readUint32BE();
- directBitsData.pixMap.rowBytes = stream->readUint16BE() & 0x3fff;
- directBitsData.pixMap.bounds.top = stream->readUint16BE();
- directBitsData.pixMap.bounds.left = stream->readUint16BE();
- directBitsData.pixMap.bounds.bottom = stream->readUint16BE();
- directBitsData.pixMap.bounds.right = stream->readUint16BE();
- directBitsData.pixMap.pmVersion = stream->readUint16BE();
- directBitsData.pixMap.packType = stream->readUint16BE();
- directBitsData.pixMap.packSize = stream->readUint32BE();
- directBitsData.pixMap.hRes = stream->readUint32BE();
- directBitsData.pixMap.vRes = stream->readUint32BE();
- directBitsData.pixMap.pixelType = stream->readUint16BE();
- directBitsData.pixMap.pixelSize = stream->readUint16BE();
- directBitsData.pixMap.cmpCount = stream->readUint16BE();
- directBitsData.pixMap.cmpSize = stream->readUint16BE();
- directBitsData.pixMap.planeBytes = stream->readUint32BE();
- directBitsData.pixMap.pmTable = stream->readUint32BE();
- directBitsData.pixMap.pmReserved = stream->readUint32BE();
- directBitsData.srcRect.top = stream->readUint16BE();
- directBitsData.srcRect.left = stream->readUint16BE();
- directBitsData.srcRect.bottom = stream->readUint16BE();
- directBitsData.srcRect.right = stream->readUint16BE();
- directBitsData.dstRect.top = stream->readUint16BE();
- directBitsData.dstRect.left = stream->readUint16BE();
- directBitsData.dstRect.bottom = stream->readUint16BE();
- directBitsData.dstRect.right = stream->readUint16BE();
- directBitsData.mode = stream->readUint16BE();
-
- if (directBitsData.pixMap.pixelSize != 16 && directBitsData.pixMap.pixelSize != 32)
- error("Unhandled directBitsRect bitsPerPixel %d", directBitsData.pixMap.pixelSize);
-
- byte bytesPerPixel = (directBitsData.pixMap.pixelSize == 16) ? 2 : 3;
- byte *buffer = new byte[image->w * image->h * bytesPerPixel];
-
- // Read in amount of data per row
- for (uint16 i = 0; i < directBitsData.pixMap.bounds.height(); i++) {
- if (directBitsData.pixMap.packType == 1 || directBitsData.pixMap.rowBytes < 8) { // Unpacked, Pad-Byte
- error("Pack Type = %d, Row Bytes = %d", directBitsData.pixMap.packType, directBitsData.pixMap.rowBytes);
- // TODO
- } else if (directBitsData.pixMap.packType == 2) { // Unpacked, No Pad-Byte
- error("Pack Type = 2");
- // TODO
- } else if (directBitsData.pixMap.packType > 2) { // Packed
- uint16 byteCount = (directBitsData.pixMap.rowBytes > 250) ? stream->readUint16BE() : stream->readByte();
- decodeDirectBitsLine(buffer + i * image->w * bytesPerPixel, directBitsData.pixMap.rowBytes, stream->readStream(byteCount), bytesPerPixel);
- }
- }
-
- if (bytesPerPixel == 2) {
- // Convert from 16-bit to whatever surface we need
- for (uint16 y = 0; y < image->h; y++) {
- for (uint16 x = 0; x < image->w; x++) {
- byte r = 0, g = 0, b = 0;
- uint32 color = READ_BE_UINT16(buffer + (y * image->w + x) * bytesPerPixel);
- directBitsFormat16.colorToRGB(color, r, g, b);
- *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
- }
- }
- } else {
- // Convert from 24-bit (planar!) to whatever surface we need
- for (uint16 y = 0; y < image->h; y++) {
- for (uint16 x = 0; x < image->w; x++) {
- byte r = *(buffer + y * image->w * 3 + x);
- byte g = *(buffer + y * image->w * 3 + image->w + x);
- byte b = *(buffer + y * image->w * 3 + image->w * 2 + x);
- *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
- }
- }
- }
-
- delete[] buffer;
-}
-
-void MystPICT::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel) {
- uint32 dataDecoded = 0;
- byte bytesPerDecode = (bytesPerPixel == 2) ? 2 : 1;
-
- while (data->pos() < data->size() && dataDecoded < length) {
- byte op = data->readByte();
-
- if (op & 0x80) {
- uint32 runSize = (op ^ 255) + 2;
- uint16 value = (bytesPerDecode == 2) ? data->readUint16BE() : data->readByte();
-
- for (uint32 i = 0; i < runSize; i++) {
- if (bytesPerDecode == 2) {
- WRITE_BE_UINT16(out, value);
- out += 2;
- } else
- *out++ = value;
- }
- dataDecoded += runSize * bytesPerDecode;
- } else {
- uint32 runSize = (op + 1) * bytesPerDecode;
- for (uint32 i = 0; i < runSize; i++)
- *out++ = data->readByte();
- dataDecoded += runSize;
- }
- }
-
- // HACK: rowBytes is in 32-bit, but the data is 24-bit...
- if (bytesPerPixel == 3)
- dataDecoded += length / 4;
-
- if (length != dataDecoded)
- warning("Mismatched DirectBits read (%d/%d)", dataDecoded, length);
-
- delete data;
-}
-
-// Compressed QuickTime details can be found here:
-// http://developer.apple.com/documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/B-Chapter/2TheImageCompression.html
-// http://developer.apple.com/documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/F-Chapter/6WorkingwiththeImage.html
-// I'm just ignoring that because Myst ME uses none of that extra stuff. The offset is always the same.
-
-void MystPICT::decodeCompressedQuickTime(Common::SeekableReadStream *stream, Graphics::Surface *image) {
- uint32 dataSize = stream->readUint32BE();
- uint32 startPos = stream->pos();
-
- Graphics::Surface *jpegImage = _jpegDecoder->decodeImage(new Common::SeekableSubReadStream(stream, stream->pos() + 156, stream->pos() + dataSize));
- stream->seek(startPos + dataSize);
-
- image->copyFrom(*jpegImage);
-
- jpegImage->free();
- delete jpegImage;
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/myst_pict.h b/engines/mohawk/myst_pict.h
deleted file mode 100644
index 0684e3352a..0000000000
--- a/engines/mohawk/myst_pict.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MYST_PICT_H
-#define MYST_PICT_H
-
-#include "common/rect.h"
-#include "common/scummsys.h"
-#include "common/stream.h"
-#include "graphics/pixelformat.h"
-#include "graphics/surface.h"
-
-#include "mohawk/jpeg.h"
-
-namespace Mohawk {
-
-class MystPICT {
-public:
- MystPICT(JPEGDecoder *jpegDecoder);
- ~MystPICT() {}
- Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
-
-private:
- JPEGDecoder *_jpegDecoder;
- Common::Rect _imageRect;
- Graphics::PixelFormat _pixelFormat;
-
- void decodeDirectBitsRect(Common::SeekableReadStream *stream, Graphics::Surface *image);
- void decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel);
- void decodeCompressedQuickTime(Common::SeekableReadStream *stream, Graphics::Surface *image);
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp
index a453bb0985..2f6d178da8 100644
--- a/engines/mohawk/myst_scripts.cpp
+++ b/engines/mohawk/myst_scripts.cpp
@@ -27,7 +27,7 @@
#include "mohawk/graphics.h"
#include "mohawk/myst_scripts.h"
#include "mohawk/sound.h"
-#include "mohawk/video/video.h"
+#include "mohawk/video.h"
#include "gui/message.h"
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 0412144034..c646855bc7 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -33,7 +33,7 @@
#include "mohawk/riven_external.h"
#include "mohawk/riven_saveload.h"
#include "mohawk/dialogs.h"
-#include "mohawk/video/video.h"
+#include "mohawk/video.h"
namespace Mohawk {
@@ -47,6 +47,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio
_cardData.hasData = false;
_gameOver = false;
_activatedSLST = false;
+ _ignoreNextMouseUp = false;
_extrasFile = NULL;
// Attempt to let game run from the CDs
@@ -147,10 +148,15 @@ Common::Error MohawkEngine_Riven::run() {
runHotspotScript(_curHotspot, kMouseDownScript);
break;
case Common::EVENT_LBUTTONUP:
- if (_curHotspot >= 0)
- runHotspotScript(_curHotspot, kMouseUpScript);
- else
- checkInventoryClick();
+ // See RivenScript::switchCard() for more information on why we sometimes
+ // disable the next up event.
+ if (!_ignoreNextMouseUp) {
+ if (_curHotspot >= 0)
+ runHotspotScript(_curHotspot, kMouseUpScript);
+ else
+ checkInventoryClick();
+ }
+ _ignoreNextMouseUp = false;
break;
case Common::EVENT_KEYDOWN:
switch (event.kbd.keycode) {
@@ -233,6 +239,7 @@ void MohawkEngine_Riven::changeToStack(uint16 n) {
// Stop any videos playing
_video->stopVideos();
+ _video->clearMLST();
// Clear the old stack files out
for (uint32 i = 0; i < _mhk.size(); i++)
@@ -310,7 +317,6 @@ void MohawkEngine_Riven::refreshCard() {
_gfx->clearWaterEffects();
_gfx->_activatedPLSTs.clear();
_video->stopVideos();
- _video->_mlstRecords.clear();
_gfx->drawPLST(1);
_activatedSLST = false;
diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h
index f014b76fb8..11c3a4c0cb 100644
--- a/engines/mohawk/riven.h
+++ b/engines/mohawk/riven.h
@@ -113,7 +113,6 @@ public:
Common::RandomSource *_rnd;
Card _cardData;
- bool _gameOver;
GUI::Debugger *getDebugger();
@@ -147,6 +146,10 @@ private:
uint32 *_vars;
uint32 _varCount;
+ // Miscellaneous
+ bool _gameOver;
+ bool _ignoreNextMouseUp;
+
public:
Common::SeekableReadStream *getExtrasResource(uint32 tag, uint16 id);
bool _activatedSLST;
@@ -180,6 +183,9 @@ public:
uint32 *getLocalVar(uint32 index);
uint32 *matchVarToString(Common::String varName);
uint32 *matchVarToString(const char *varName);
+
+ void setGameOver() { _gameOver = true; }
+ void ignoreNextMouseUp() { _ignoreNextMouseUp = true; }
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp
index 99afacc5ce..4e6bba1c2a 100644
--- a/engines/mohawk/riven_external.cpp
+++ b/engines/mohawk/riven_external.cpp
@@ -27,7 +27,7 @@
#include "mohawk/riven.h"
#include "mohawk/riven_external.h"
#include "mohawk/sound.h"
-#include "mohawk/video/video.h"
+#include "mohawk/video.h"
#include "gui/message.h"
#include "common/events.h"
@@ -210,7 +210,28 @@ void RivenExternal::runEndGame(uint16 video) {
_vm->_video->playMovieBlocking(video);
// TODO: Play until the last frame and then run the credits
- _vm->_gameOver = true;
+ _vm->setGameOver();
+}
+
+void RivenExternal::runDomeButtonMovie() {
+ // This command just plays the video of the button moving down and up.
+ _vm->_video->playMovieBlocking(2);
+}
+
+void RivenExternal::runDomeCheck() {
+ // Check if we clicked while the golden frame was showing
+
+ VideoHandle video = _vm->_video->findVideoHandle(1);
+ assert(video != NULL_VID_HANDLE);
+
+ int32 curFrame = _vm->_video->getCurFrame(video);
+ int32 frameCount = _vm->_video->getFrameCount(video);
+
+ // The final frame of the video is the 'golden' frame (double meaning: the
+ // frame that is the magic one is the one with the golden symbol) but we
+ // give a 3 frame leeway in either direction.
+ if (frameCount - curFrame < 3 || curFrame < 3)
+ *_vm->matchVarToString("domecheck") = 1;
}
// ------------------------------------------------------------------------------------
@@ -218,11 +239,13 @@ void RivenExternal::runEndGame(uint16 video) {
// ------------------------------------------------------------------------------------
void RivenExternal::xastartupbtnhide(uint16 argc, uint16 *argv) {
- // The original game hides the start/setup buttons depending on an ini entry. It's safe to ignore this command.
+ // The original game hides the start/setup buttons depending on an ini entry.
+ // It's safe to ignore this command.
}
void RivenExternal::xasetupcomplete(uint16 argc, uint16 *argv) {
- // The original game sets an ini entry to disable the setup button and use the start button only. It's safe to ignore this part of the command.
+ // The original game sets an ini entry to disable the setup button and use the
+ // start button only. It's safe to ignore this part of the command.
_vm->_sound->stopSound();
_vm->changeToCard(1);
}
@@ -514,13 +537,14 @@ void RivenExternal::xbupdateboiler(uint16 argc, uint16 *argv) {
if (heat) {
if (platform == 0) {
_vm->_video->activateMLST(7, _vm->getCurCard());
- // TODO: Play video (non-blocking)
+ _vm->_video->playMovie(7);
} else {
_vm->_video->activateMLST(8, _vm->getCurCard());
- // TODO: Play video (non-blocking)
+ _vm->_video->playMovie(8);
}
} else {
- // TODO: Stop MLST's 7 and 8
+ _vm->_video->stopMovie(7);
+ _vm->_video->stopMovie(8);
}
_vm->refreshCard();
@@ -627,11 +651,11 @@ void RivenExternal::xbisland190_slidermw(uint16 argc, uint16 *argv) {
}
void RivenExternal::xbscpbtn(uint16 argc, uint16 *argv) {
- // TODO: Dome related
+ runDomeButtonMovie();
}
void RivenExternal::xbisland_domecheck(uint16 argc, uint16 *argv) {
- // TODO: Dome related
+ runDomeCheck();
}
void RivenExternal::xvalvecontrol(uint16 argc, uint16 *argv) {
@@ -723,11 +747,11 @@ void RivenExternal::xgisland25_slidermw(uint16 argc, uint16 *argv) {
}
void RivenExternal::xgscpbtn(uint16 argc, uint16 *argv) {
- // TODO: Dome related
+ runDomeButtonMovie();
}
void RivenExternal::xgisland1490_domecheck(uint16 argc, uint16 *argv) {
- // TODO: Dome related
+ runDomeCheck();
}
void RivenExternal::xgplateau3160_dopools(uint16 argc, uint16 *argv) {
@@ -978,11 +1002,11 @@ void RivenExternal::xjdome25_slidermw(uint16 argc, uint16 *argv) {
}
void RivenExternal::xjscpbtn(uint16 argc, uint16 *argv) {
- // TODO: Dome related
+ runDomeButtonMovie();
}
void RivenExternal::xjisland3500_domecheck(uint16 argc, uint16 *argv) {
- // TODO: Dome related
+ runDomeCheck();
}
int RivenExternal::jspitElevatorLoop() {
@@ -1258,11 +1282,11 @@ void RivenExternal::xpisland990_elevcombo(uint16 argc, uint16 *argv) {
}
void RivenExternal::xpscpbtn(uint16 argc, uint16 *argv) {
- // TODO: Dome related
+ runDomeButtonMovie();
}
void RivenExternal::xpisland290_domecheck(uint16 argc, uint16 *argv) {
- // TODO: Dome related
+ runDomeCheck();
}
void RivenExternal::xpisland25_opencard(uint16 argc, uint16 *argv) {
@@ -1457,11 +1481,11 @@ void RivenExternal::xtakeit(uint16 argc, uint16 *argv) {
}
void RivenExternal::xtscpbtn(uint16 argc, uint16 *argv) {
- // TODO: Dome related
+ runDomeButtonMovie();
}
void RivenExternal::xtisland4990_domecheck(uint16 argc, uint16 *argv) {
- // TODO: Dome related
+ runDomeCheck();
}
void RivenExternal::xtisland5056_opencard(uint16 argc, uint16 *argv) {
diff --git a/engines/mohawk/riven_external.h b/engines/mohawk/riven_external.h
index 8270a00854..14bb51340c 100644
--- a/engines/mohawk/riven_external.h
+++ b/engines/mohawk/riven_external.h
@@ -57,6 +57,8 @@ private:
int jspitElevatorLoop();
void runDemoBoundaryDialog();
void runEndGame(uint16 video);
+ void runDomeCheck();
+ void runDomeButtonMovie();
// -----------------------------------------------------
// aspit (Main Menu, Books, Setup) external commands
diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp
index e809ad9642..d574a455c6 100644
--- a/engines/mohawk/riven_scripts.cpp
+++ b/engines/mohawk/riven_scripts.cpp
@@ -28,7 +28,7 @@
#include "mohawk/riven_external.h"
#include "mohawk/riven_scripts.h"
#include "mohawk/sound.h"
-#include "mohawk/video/video.h"
+#include "mohawk/video.h"
#include "common/stream.h"
#include "graphics/cursorman.h"
@@ -298,13 +298,10 @@ void RivenScript::processCommands(bool runCommands) {
// Command 1: draw tBMP resource (tbmp_id, left, top, right, bottom, u0, u1, u2, u3)
void RivenScript::drawBitmap(uint16 op, uint16 argc, uint16 *argv) {
- if (argc < 5) {
- // Copy the image to the whole screen, ignoring the rest of the parameters
+ if (argc < 5) // Copy the image to the whole screen, ignoring the rest of the parameters
_vm->_gfx->copyImageToScreen(argv[0], 0, 0, 608, 392);
- } else {
- // Copy the image to a certain part of the screen
+ else // Copy the image to a certain part of the screen
_vm->_gfx->copyImageToScreen(argv[0], argv[1], argv[2], argv[3], argv[4]);
- }
// Now, update the screen
_vm->_gfx->updateScreen();
@@ -313,6 +310,12 @@ void RivenScript::drawBitmap(uint16 op, uint16 argc, uint16 *argv) {
// Command 2: go to card (card id)
void RivenScript::switchCard(uint16 op, uint16 argc, uint16 *argv) {
_vm->changeToCard(argv[0]);
+
+ // WORKAROUND: If we changed card on a mouse down event,
+ // we want to ignore the next mouse up event so we don't
+ // change card when lifting the mouse on the next card.
+ if (_scriptType == kMouseDownScript)
+ _vm->ignoreNextMouseUp();
}
// Command 3: play an SLST from the script
@@ -547,9 +550,8 @@ void RivenScript::activateSLST(uint16 op, uint16 argc, uint16 *argv) {
// Command 41: activate MLST record and play
void RivenScript::activateMLSTAndPlay(uint16 op, uint16 argc, uint16 *argv) {
- _vm->_video->enableMovie(argv[0] - 1);
_vm->_video->activateMLST(argv[0], _vm->getCurCard());
- // TODO: Play movie (blocking?)
+ _vm->_video->playMovie(argv[0]);
}
// Command 43: activate BLST record (card hotspot enabling lists)
diff --git a/engines/mohawk/video/video.cpp b/engines/mohawk/video.cpp
index 86ecd4dedf..a45a4294c8 100644
--- a/engines/mohawk/video/video.cpp
+++ b/engines/mohawk/video.cpp
@@ -24,10 +24,10 @@
*/
#include "mohawk/resource.h"
-#include "mohawk/video/video.h"
-#include "mohawk/video/qt_player.h"
+#include "mohawk/video.h"
#include "common/events.h"
+#include "graphics/video/qt_decoder.h"
namespace Mohawk {
@@ -35,18 +35,19 @@ VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) {
}
VideoManager::~VideoManager() {
- _mlstRecords.clear();
stopVideos();
}
void VideoManager::pauseVideos() {
for (uint16 i = 0; i < _videoStreams.size(); i++)
- _videoStreams[i]->pauseVideo(true);
+ if (_videoStreams[i].video)
+ _videoStreams[i]->pauseVideo(true);
}
void VideoManager::resumeVideos() {
for (uint16 i = 0; i < _videoStreams.size(); i++)
- _videoStreams[i]->pauseVideo(false);
+ if (_videoStreams[i].video)
+ _videoStreams[i]->pauseVideo(false);
}
void VideoManager::stopVideos() {
@@ -89,7 +90,7 @@ void VideoManager::playMovieCentered(Common::String filename, bool clearScreen)
void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) {
bool continuePlaying = true;
- while (!_videoStreams[videoHandle]->endOfVideo() && !_vm->shouldQuit() && continuePlaying) {
+ while (_videoStreams[videoHandle].video && !_videoStreams[videoHandle]->endOfVideo() && !_vm->shouldQuit() && continuePlaying) {
if (updateBackgroundMovies())
_vm->_system->updateScreen();
@@ -120,8 +121,10 @@ void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) {
_vm->_system->delayMillis(10);
}
- _videoStreams[videoHandle]->close();
- _videoStreams.clear();
+ delete _videoStreams[videoHandle].video;
+ _videoStreams[videoHandle].video = 0;
+ _videoStreams[videoHandle].id = 0;
+ _videoStreams[videoHandle].filename.clear();
}
void VideoManager::playBackgroundMovie(Common::String filename, int16 x, int16 y, bool loop) {
@@ -152,8 +155,9 @@ bool VideoManager::updateBackgroundMovies() {
_videoStreams[i]->rewind();
} else {
delete _videoStreams[i].video;
- memset(&_videoStreams[i], 0, sizeof(VideoEntry));
- _videoStreams[i].video = NULL;
+ _videoStreams[i].video = 0;
+ _videoStreams[i].id = 0;
+ _videoStreams[i].filename.clear();
continue;
}
}
@@ -240,7 +244,15 @@ void VideoManager::activateMLST(uint16 mlstId, uint16 card) {
if (mlstRecord.u1 != 1)
warning("mlstRecord.u1 not 1");
+ // We've found a match, add it
if (mlstRecord.index == mlstId) {
+ // Make sure we don't have any duplicates
+ for (uint32 j = 0; j < _mlstRecords.size(); j++)
+ if (_mlstRecords[j].index == mlstRecord.index || _mlstRecords[j].code == mlstRecord.code) {
+ _mlstRecords.remove_at(j);
+ j--;
+ }
+
_mlstRecords.push_back(mlstRecord);
break;
}
@@ -249,6 +261,10 @@ void VideoManager::activateMLST(uint16 mlstId, uint16 card) {
delete mlstStream;
}
+void VideoManager::clearMLST() {
+ _mlstRecords.clear();
+}
+
void VideoManager::playMovie(uint16 id) {
for (uint16 i = 0; i < _mlstRecords.size(); i++)
if (_mlstRecords[i].code == id) {
@@ -274,8 +290,10 @@ void VideoManager::stopMovie(uint16 id) {
if (_mlstRecords[i].code == id)
for (uint16 j = 0; j < _videoStreams.size(); j++)
if (_mlstRecords[i].movieID == _videoStreams[j].id) {
- delete _videoStreams[i].video;
- memset(&_videoStreams[i].video, 0, sizeof(VideoEntry));
+ delete _videoStreams[j].video;
+ _videoStreams[j].video = 0;
+ _videoStreams[j].id = 0;
+ _videoStreams[j].filename.clear();
return;
}
}
@@ -316,7 +334,7 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool
// Otherwise, create a new entry
VideoEntry entry;
- entry.video = new QTPlayer();
+ entry.video = new Graphics::QuickTimeDecoder();
entry.x = x;
entry.y = y;
entry.filename = "";
@@ -346,7 +364,7 @@ VideoHandle VideoManager::createVideoHandle(Common::String filename, uint16 x, u
// Otherwise, create a new entry
VideoEntry entry;
- entry.video = new QTPlayer();
+ entry.video = new Graphics::QuickTimeDecoder();
entry.x = x;
entry.y = y;
entry.filename = filename;
@@ -374,4 +392,24 @@ VideoHandle VideoManager::createVideoHandle(Common::String filename, uint16 x, u
return _videoStreams.size() - 1;
}
+VideoHandle VideoManager::findVideoHandle(uint16 id) {
+ for (uint16 i = 0; i < _mlstRecords.size(); i++)
+ if (_mlstRecords[i].code == id)
+ for (uint16 j = 0; j < _videoStreams.size(); j++)
+ if (_videoStreams[j].video && _mlstRecords[i].movieID == _videoStreams[j].id)
+ return j;
+
+ return NULL_VID_HANDLE;
+}
+
+int32 VideoManager::getCurFrame(const VideoHandle &handle) {
+ assert(handle != NULL_VID_HANDLE);
+ return _videoStreams[handle]->getCurFrame();
+}
+
+uint32 VideoManager::getFrameCount(const VideoHandle &handle) {
+ assert(handle != NULL_VID_HANDLE);
+ return _videoStreams[handle]->getFrameCount();
+}
+
} // End of namespace Mohawk
diff --git a/engines/mohawk/video/video.h b/engines/mohawk/video.h
index a5d2bde65d..6aa553e26b 100644
--- a/engines/mohawk/video/video.h
+++ b/engines/mohawk/video.h
@@ -28,6 +28,10 @@
#include "graphics/pixelformat.h"
+namespace Graphics {
+ class QuickTimeDecoder;
+}
+
namespace Mohawk {
class MohawkEngine;
@@ -44,10 +48,8 @@ struct MLSTRecord {
uint16 u1;
};
-class QTPlayer;
-
struct VideoEntry {
- QTPlayer *video;
+ Graphics::QuickTimeDecoder *video;
uint16 x;
uint16 y;
bool loop;
@@ -55,7 +57,7 @@ struct VideoEntry {
uint16 id; // Riven only
bool enabled;
- QTPlayer *operator->() const { assert(video); return video; }
+ Graphics::QuickTimeDecoder *operator->() const { assert(video); return video; }
};
typedef int32 VideoHandle;
@@ -80,6 +82,7 @@ public:
// Riven-related functions
void activateMLST(uint16 mlstId, uint16 card);
+ void clearMLST();
void enableMovie(uint16 id);
void disableMovie(uint16 id);
void disableAllMovies();
@@ -87,19 +90,23 @@ public:
void stopMovie(uint16 id);
void playMovieBlocking(uint16 id);
- // Riven-related variables
- Common::Array<MLSTRecord> _mlstRecords;
+ // Handle functions
+ VideoHandle findVideoHandle(uint16 id);
+ int32 getCurFrame(const VideoHandle &handle);
+ uint32 getFrameCount(const VideoHandle &handle);
private:
MohawkEngine *_vm;
- void waitUntilMovieEnds(VideoHandle videoHandle);
+ // Riven-related variables
+ Common::Array<MLSTRecord> _mlstRecords;
// Keep tabs on any videos playing
Common::Array<VideoEntry> _videoStreams;
VideoHandle createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop);
VideoHandle createVideoHandle(Common::String filename, uint16 x, uint16 y, bool loop);
+ void waitUntilMovieEnds(VideoHandle videoHandle);
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/video/cinepak.cpp b/engines/mohawk/video/cinepak.cpp
deleted file mode 100644
index 2ffe6869ae..0000000000
--- a/engines/mohawk/video/cinepak.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "mohawk/video/cinepak.h"
-
-#include "common/system.h"
-#include "graphics/conversion.h" // For YUV2RGB
-
-// Code here partially based off of ffmpeg ;)
-
-namespace Mohawk {
-
-#define PUT_PIXEL(offset, lum, u, v) \
- Graphics::CPYUV2RGB(lum, u, v, r, g, b); \
- if (_pixelFormat.bytesPerPixel == 2) \
- *((uint16 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b); \
- else \
- *((uint32 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b)
-
-CinepakDecoder::CinepakDecoder() : Graphics::Codec() {
- _curFrame.surface = NULL;
- _curFrame.strips = NULL;
- _y = 0;
- _pixelFormat = g_system->getScreenFormat();
-
- // We're going to have to dither if we're running in 8bpp.
- // We'll take RGBA8888 for best color performance in this case.
- if (_pixelFormat.bytesPerPixel == 1)
- _pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
-}
-
-CinepakDecoder::~CinepakDecoder() {
- if (_curFrame.surface)
- _curFrame.surface->free();
- delete[] _curFrame.strips;
-}
-
-Graphics::Surface *CinepakDecoder::decodeImage(Common::SeekableReadStream *stream) {
- _curFrame.flags = stream->readByte();
- _curFrame.length = (stream->readByte() << 16) + stream->readUint16BE();
- _curFrame.width = stream->readUint16BE();
- _curFrame.height = stream->readUint16BE();
- _curFrame.stripCount = stream->readUint16BE();
-
- if (_curFrame.strips == NULL)
- _curFrame.strips = new CinepakStrip[_curFrame.stripCount];
-
- debug (4, "Cinepak Frame: Width = %d, Height = %d, Strip Count = %d", _curFrame.width, _curFrame.height, _curFrame.stripCount);
-
-#if 0
- // Borrowed from FFMPEG. This should cut out the extra data Cinepak for Sega has (which is useless).
- // The theory behind this is that this is here to confuse standard Cinepak decoders. But, we won't let that happen! ;)
- if (_curFrame.length != (uint32)stream->size()) {
- if (stream->readUint16BE() == 0xFE00)
- stream->readUint32BE();
- }
-#endif
-
- if (!_curFrame.surface) {
- _curFrame.surface = new Graphics::Surface();
- _curFrame.surface->create(_curFrame.width, _curFrame.height, _pixelFormat.bytesPerPixel);
- }
-
- // Reset the y variable.
- _y = 0;
-
- for (uint16 i = 0; i < _curFrame.stripCount; i++) {
- if (i > 0 && !(_curFrame.flags & 1)) { // Use codebooks from last strip
- for (uint16 j = 0; j < 256; j++) {
- _curFrame.strips[i].v1_codebook[j] = _curFrame.strips[i - 1].v1_codebook[j];
- _curFrame.strips[i].v4_codebook[j] = _curFrame.strips[i - 1].v4_codebook[j];
- }
- }
-
- _curFrame.strips[i].id = stream->readUint16BE();
- _curFrame.strips[i].length = stream->readUint16BE() - 12; // Subtract the 12 byte header
- _curFrame.strips[i].rect.top = _y; stream->readUint16BE(); // Ignore, substitute with our own.
- _curFrame.strips[i].rect.left = 0; stream->readUint16BE(); // Ignore, substitute with our own
- _curFrame.strips[i].rect.bottom = _y + stream->readUint16BE();
- _curFrame.strips[i].rect.right = _curFrame.width; stream->readUint16BE(); // Ignore, substitute with our own
-
- //printf ("Left = %d, Top = %d, Right = %d, Bottom = %d\n", _curFrame.strips[i].rect.left, _curFrame.strips[i].rect.top, _curFrame.strips[i].rect.right, _curFrame.strips[i].rect.bottom);
-
- // Sanity check. Because Cinepak is based on 4x4 blocks, the width and height of each strip needs to be divisible by 4.
- assert(!(_curFrame.strips[i].rect.width() % 4) && !(_curFrame.strips[i].rect.height() % 4));
-
- uint32 pos = stream->pos();
-
- while ((uint32)stream->pos() < (pos + _curFrame.strips[i].length) && !stream->eos()) {
- byte chunkID = stream->readByte();
-
- if (stream->eos())
- break;
-
- // Chunk Size is 24-bit, ignore the first 4 bytes
- uint32 chunkSize = stream->readByte() << 16;
- chunkSize += stream->readUint16BE() - 4;
-
- int32 startPos = stream->pos();
-
- switch (chunkID) {
- case 0x20:
- case 0x21:
- case 0x24:
- case 0x25:
- loadCodebook(stream, i, 4, chunkID, chunkSize);
- break;
- case 0x22:
- case 0x23:
- case 0x26:
- case 0x27:
- loadCodebook(stream, i, 1, chunkID, chunkSize);
- break;
- case 0x30:
- case 0x31:
- case 0x32:
- decodeVectors(stream, i, chunkID, chunkSize);
- break;
- default:
- warning("Unknown Cinepak chunk ID %02x", chunkID);
- return _curFrame.surface;
- }
-
- if (stream->pos() != startPos + (int32)chunkSize)
- stream->seek(startPos + chunkSize);
- }
-
- _y = _curFrame.strips[i].rect.bottom;
- }
-
- return _curFrame.surface;
-}
-
-void CinepakDecoder::loadCodebook(Common::SeekableReadStream *stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize) {
- CinepakCodebook *codebook = (codebookType == 1) ? _curFrame.strips[strip].v1_codebook : _curFrame.strips[strip].v4_codebook;
-
- int32 startPos = stream->pos();
- uint32 flag = 0, mask = 0;
-
- for (uint16 i = 0; i < 256; i++) {
- if ((chunkID & 0x01) && !(mask >>= 1)) {
- if ((stream->pos() - startPos + 4) > (int32)chunkSize)
- break;
-
- flag = stream->readUint32BE();
- mask = 0x80000000;
- }
-
- if (!(chunkID & 0x01) || (flag & mask)) {
- byte n = (chunkID & 0x04) ? 4 : 6;
- if ((stream->pos() - startPos + n) > (int32)chunkSize)
- break;
-
- for (byte j = 0; j < 4; j++)
- codebook[i].y[j] = stream->readByte();
-
- if (n == 6) {
- codebook[i].u = stream->readByte() + 128;
- codebook[i].v = stream->readByte() + 128;
- } else {
- /* this codebook type indicates either greyscale or
- * palettized video; if palettized, U & V components will
- * not be used so it is safe to set them to 128 for the
- * benefit of greyscale rendering in YUV420P */
- codebook[i].u = 128;
- codebook[i].v = 128;
- }
- }
- }
-}
-
-void CinepakDecoder::decodeVectors(Common::SeekableReadStream *stream, uint16 strip, byte chunkID, uint32 chunkSize) {
- uint32 flag = 0, mask = 0;
- uint32 iy[4];
- int32 startPos = stream->pos();
- byte r = 0, g = 0, b = 0;
-
- for (uint16 y = _curFrame.strips[strip].rect.top; y < _curFrame.strips[strip].rect.bottom; y += 4) {
- iy[0] = _curFrame.strips[strip].rect.left + y * _curFrame.width;
- iy[1] = iy[0] + _curFrame.width;
- iy[2] = iy[1] + _curFrame.width;
- iy[3] = iy[2] + _curFrame.width;
-
- for (uint16 x = _curFrame.strips[strip].rect.left; x < _curFrame.strips[strip].rect.right; x += 4) {
- if ((chunkID & 0x01) && !(mask >>= 1)) {
- if ((stream->pos() - startPos + 4) > (int32)chunkSize)
- return;
-
- flag = stream->readUint32BE();
- mask = 0x80000000;
- }
-
- if (!(chunkID & 0x01) || (flag & mask)) {
- if (!(chunkID & 0x02) && !(mask >>= 1)) {
- if ((stream->pos() - startPos + 4) > (int32)chunkSize)
- return;
-
- flag = stream->readUint32BE();
- mask = 0x80000000;
- }
-
- if ((chunkID & 0x02) || (~flag & mask)) {
- if ((stream->pos() - startPos + 1) > (int32)chunkSize)
- return;
-
- // Get the codebook
- CinepakCodebook codebook = _curFrame.strips[strip].v1_codebook[stream->readByte()];
-
- PUT_PIXEL(iy[0] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 1, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 1, codebook.y[0], codebook.u, codebook.v);
-
- PUT_PIXEL(iy[0] + 2, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 3, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 2, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 3, codebook.y[1], codebook.u, codebook.v);
-
- PUT_PIXEL(iy[2] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 1, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 1, codebook.y[2], codebook.u, codebook.v);
-
- PUT_PIXEL(iy[2] + 2, codebook.y[3], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 3, codebook.y[3], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 2, codebook.y[3], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 3, codebook.y[3], codebook.u, codebook.v);
- } else if (flag & mask) {
- if ((stream->pos() - startPos + 4) > (int32)chunkSize)
- return;
-
- CinepakCodebook codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
- PUT_PIXEL(iy[0] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 1, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 1, codebook.y[3], codebook.u, codebook.v);
-
- codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
- PUT_PIXEL(iy[0] + 2, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 3, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 2, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 3, codebook.y[3], codebook.u, codebook.v);
-
- codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
- PUT_PIXEL(iy[2] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 1, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 1, codebook.y[3], codebook.u, codebook.v);
-
- codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
- PUT_PIXEL(iy[2] + 2, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 3, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 2, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 3, codebook.y[3], codebook.u, codebook.v);
- }
- }
-
- for (byte i = 0; i < 4; i++)
- iy[i] += 4;
- }
- }
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/cinepak.h b/engines/mohawk/video/cinepak.h
deleted file mode 100644
index 3f4cbba17c..0000000000
--- a/engines/mohawk/video/cinepak.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef CINEPAK_H
-#define CINEPAK_H
-
-#include "common/scummsys.h"
-#include "common/stream.h"
-#include "common/rect.h"
-#include "graphics/surface.h"
-#include "graphics/pixelformat.h"
-
-#include "graphics/video/codecs/codec.h"
-
-namespace Mohawk {
-
-struct CinepakCodebook {
- byte y[4];
- byte u, v;
-};
-
-struct CinepakStrip {
- uint16 id;
- uint16 length;
- Common::Rect rect;
- CinepakCodebook v1_codebook[256], v4_codebook[256];
-};
-
-struct CinepakFrame {
- byte flags;
- uint32 length;
- uint16 width;
- uint16 height;
- uint16 stripCount;
- CinepakStrip *strips;
-
- Graphics::Surface *surface;
-};
-
-class CinepakDecoder : public Graphics::Codec {
-public:
- CinepakDecoder();
- ~CinepakDecoder();
-
- Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
- Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
-
-private:
- CinepakFrame _curFrame;
- int32 _y;
- Graphics::PixelFormat _pixelFormat;
-
- void loadCodebook(Common::SeekableReadStream *stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize);
- void decodeVectors(Common::SeekableReadStream *stream, uint16 strip, byte chunkID, uint32 chunkSize);
-};
-
-}
-
-#endif
diff --git a/engines/mohawk/video/qdm2.cpp b/engines/mohawk/video/qdm2.cpp
deleted file mode 100644
index b91440f00d..0000000000
--- a/engines/mohawk/video/qdm2.cpp
+++ /dev/null
@@ -1,3063 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-// Based off ffmpeg's QDM2 decoder
-
-#include "mohawk/video/qdm2.h"
-#include "mohawk/video/qdm2data.h"
-
-#include "common/system.h"
-
-namespace Mohawk {
-
-// Fix compilation for non C99-compliant compilers, like MSVC
-#ifndef int64_t
-typedef signed long long int int64_t;
-#endif
-
-// Integer log2 function. This is much faster than invoking
-// double precision C99 log2 math functions or equivalent, since
-// this is only used to determine maximum number of bits needed
-// i.e. only non-fractional part is needed. Also, the double
-// version is incorrect for exact cases due to floating point
-// rounding errors.
-static inline int scummvm_log2(int n) {
- int ret = -1;
- while(n != 0) {
- n /= 2;
- ret++;
- }
- return ret;
-}
-
-#define QDM2_LIST_ADD(list, size, packet) \
- do { \
- if (size > 0) \
- list[size - 1].next = &list[size]; \
- list[size].packet = packet; \
- list[size].next = NULL; \
- size++; \
- } while(0)
-
-// Result is 8, 16 or 30
-#define QDM2_SB_USED(subSampling) (((subSampling) >= 2) ? 30 : 8 << (subSampling))
-
-#define FIX_NOISE_IDX(noiseIdx) \
- if ((noiseIdx) >= 3840) \
- (noiseIdx) -= 3840 \
-
-#define SB_DITHERING_NOISE(sb, noiseIdx) (_noiseTable[(noiseIdx)++] * sb_noise_attenuation[(sb)])
-
-static inline void initGetBits(GetBitContext *s, const uint8 *buffer, int bitSize) {
- int bufferSize = (bitSize + 7) >> 3;
-
- debug(1, "void initGetBits(GetBitContext *s, const uint8 *buffer, int bitSize)");
-
- if (bufferSize < 0 || bitSize < 0) {
- bufferSize = bitSize = 0;
- buffer = NULL;
- }
-
- s->buffer = buffer;
- s->sizeInBits = bitSize;
- s->bufferEnd = buffer + bufferSize;
- s->index = 0;
-}
-
-static inline int getBitsCount(GetBitContext *s) {
- debug(1, "int getBitsCount(GetBitContext *s)");
- return s->index;
-}
-
-static inline unsigned int getBits1(GetBitContext *s) {
- int index;
- uint8 result;
-
- debug(1, "unsigned int getBits1(GetBitContext *s)");
-
- index = s->index;
- result = s->buffer[index >> 3];
-
- debug(1, "index : %d", index);
-
- result >>= (index & 0x07);
- result &= 1;
- index++;
- s->index = index;
-
- return result;
-}
-
-static inline unsigned int getBits(GetBitContext *s, int n) {
- int tmp, reCache, reIndex;
-
- debug(1, "unsigned int getBits(GetBitContext *s, int n)");
-
- reIndex = s->index;
-
- debug(1, "reIndex : %d", reIndex);
-
- reCache = READ_LE_UINT32((const uint8 *)s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
-
- tmp = (reCache) & ((uint32)0xffffffff >> (32 - n));
-
- s->index = reIndex + n;
-
- return tmp;
-}
-
-static inline void skipBits(GetBitContext *s, int n) {
- int reIndex, reCache;
-
- debug(1, "void skipBits(GetBitContext *s, int n)");
-
- reIndex = s->index;
- reCache = 0;
-
- debug(1, "reIndex : %d", reIndex);
-
- reCache = READ_LE_UINT32((const uint8 *)s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
- s->index = reIndex + n;
-}
-
-#define BITS_LEFT(length, gb) ((length) - getBitsCount((gb)))
-
-static int splitRadixPermutation(int i, int n, int inverse) {
- if (n <= 2)
- return i & 1;
-
- int m = n >> 1;
-
- if(!(i & m))
- return splitRadixPermutation(i, m, inverse) * 2;
-
- m >>= 1;
-
- if (inverse == !(i & m))
- return splitRadixPermutation(i, m, inverse) * 4 + 1;
-
- return splitRadixPermutation(i, m, inverse) * 4 - 1;
-}
-
-// sin(2*pi*x/n) for 0<=x<n/4, followed by n/2<=x<3n/4
-float ff_sin_16[8];
-float ff_sin_32[16];
-float ff_sin_64[32];
-float ff_sin_128[64];
-float ff_sin_256[128];
-float ff_sin_512[256];
-float ff_sin_1024[512];
-float ff_sin_2048[1024];
-float ff_sin_4096[2048];
-float ff_sin_8192[4096];
-float ff_sin_16384[8192];
-float ff_sin_32768[16384];
-float ff_sin_65536[32768];
-
-float *ff_sin_tabs[] = {
- NULL, NULL, NULL, NULL,
- ff_sin_16, ff_sin_32, ff_sin_64, ff_sin_128, ff_sin_256, ff_sin_512, ff_sin_1024,
- ff_sin_2048, ff_sin_4096, ff_sin_8192, ff_sin_16384, ff_sin_32768, ff_sin_65536,
-};
-
-// cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse
-float ff_cos_16[8];
-float ff_cos_32[16];
-float ff_cos_64[32];
-float ff_cos_128[64];
-float ff_cos_256[128];
-float ff_cos_512[256];
-float ff_cos_1024[512];
-float ff_cos_2048[1024];
-float ff_cos_4096[2048];
-float ff_cos_8192[4096];
-float ff_cos_16384[8192];
-float ff_cos_32768[16384];
-float ff_cos_65536[32768];
-
-float *ff_cos_tabs[] = {
- NULL, NULL, NULL, NULL,
- ff_cos_16, ff_cos_32, ff_cos_64, ff_cos_128, ff_cos_256, ff_cos_512, ff_cos_1024,
- ff_cos_2048, ff_cos_4096, ff_cos_8192, ff_cos_16384, ff_cos_32768, ff_cos_65536,
-};
-
-void initCosineTables(int index) {
- int m = 1 << index;
- double freq = 2 * PI / m;
- float *tab = ff_cos_tabs[index];
-
- for (int i = 0; i <= m / 4; i++)
- tab[i] = cos(i * freq);
-
- for (int i = 1; i < m / 4; i++)
- tab[m / 2 - i] = tab[i];
-}
-
-void fftPermute(FFTContext *s, FFTComplex *z) {
- const uint16 *revtab = s->revtab;
- int np = 1 << s->nbits;
-
- if (s->tmpBuf) {
- // TODO: handle split-radix permute in a more optimal way, probably in-place
- for (int j = 0; j < np; j++)
- s->tmpBuf[revtab[j]] = z[j];
- memcpy(z, s->tmpBuf, np * sizeof(FFTComplex));
- return;
- }
-
- // reverse
- for (int j = 0; j < np; j++) {
- int k = revtab[j];
- if (k < j) {
- FFTComplex tmp = z[k];
- z[k] = z[j];
- z[j] = tmp;
- }
- }
-}
-
-#define DECL_FFT(n,n2,n4) \
-static void fft##n(FFTComplex *z) { \
- fft##n2(z); \
- fft##n4(z + n4 * 2); \
- fft##n4(z + n4 * 3); \
- pass(z, ff_cos_##n, n4 / 2); \
-}
-
-#ifndef M_SQRT1_2
-#define M_SQRT1_2 7.0710678118654752440E-1
-#endif
-
-#define sqrthalf (float)M_SQRT1_2
-
-#define BF(x,y,a,b) { \
- x = a - b; \
- y = a + b; \
-}
-
-#define BUTTERFLIES(a0, a1, a2, a3) { \
- BF(t3, t5, t5, t1); \
- BF(a2.re, a0.re, a0.re, t5); \
- BF(a3.im, a1.im, a1.im, t3); \
- BF(t4, t6, t2, t6); \
- BF(a3.re, a1.re, a1.re, t4); \
- BF(a2.im, a0.im, a0.im, t6); \
-}
-
-// force loading all the inputs before storing any.
-// this is slightly slower for small data, but avoids store->load aliasing
-// for addresses separated by large powers of 2.
-#define BUTTERFLIES_BIG(a0, a1, a2, a3) { \
- float r0 = a0.re, i0 = a0.im, r1 = a1.re, i1 = a1.im; \
- BF(t3, t5, t5, t1); \
- BF(a2.re, a0.re, r0, t5); \
- BF(a3.im, a1.im, i1, t3); \
- BF(t4, t6, t2, t6); \
- BF(a3.re, a1.re, r1, t4); \
- BF(a2.im, a0.im, i0, t6); \
-}
-
-#define TRANSFORM(a0, a1, a2, a3, wre, wim) { \
- t1 = a2.re * wre + a2.im * wim; \
- t2 = a2.im * wre - a2.re * wim; \
- t5 = a3.re * wre - a3.im * wim; \
- t6 = a3.im * wre + a3.re * wim; \
- BUTTERFLIES(a0, a1, a2, a3) \
-}
-
-#define TRANSFORM_ZERO(a0, a1, a2, a3) { \
- t1 = a2.re; \
- t2 = a2.im; \
- t5 = a3.re; \
- t6 = a3.im; \
- BUTTERFLIES(a0, a1, a2, a3) \
-}
-
-// z[0...8n-1], w[1...2n-1]
-#define PASS(name) \
-static void name(FFTComplex *z, const float *wre, unsigned int n) { \
- float t1, t2, t3, t4, t5, t6; \
- int o1 = 2 * n; \
- int o2 = 4 * n; \
- int o3 = 6 * n; \
- const float *wim = wre + o1; \
- n--; \
- \
- TRANSFORM_ZERO(z[0], z[o1], z[o2], z[o3]); \
- TRANSFORM(z[1], z[o1 + 1], z[o2 + 1], z[o3 + 1], wre[1], wim[-1]); \
- \
- do { \
- z += 2; \
- wre += 2; \
- wim -= 2; \
- TRANSFORM(z[0], z[o1], z[o2], z[o3], wre[0], wim[0]); \
- TRANSFORM(z[1], z[o1 + 1],z[o2 + 1], z[o3 + 1], wre[1], wim[-1]); \
- } while(--n); \
-}
-
-PASS(pass)
-#undef BUTTERFLIES
-#define BUTTERFLIES BUTTERFLIES_BIG
-PASS(pass_big)
-
-static void fft4(FFTComplex *z) {
- float t1, t2, t3, t4, t5, t6, t7, t8;
-
- BF(t3, t1, z[0].re, z[1].re);
- BF(t8, t6, z[3].re, z[2].re);
- BF(z[2].re, z[0].re, t1, t6);
- BF(t4, t2, z[0].im, z[1].im);
- BF(t7, t5, z[2].im, z[3].im);
- BF(z[3].im, z[1].im, t4, t8);
- BF(z[3].re, z[1].re, t3, t7);
- BF(z[2].im, z[0].im, t2, t5);
-}
-
-static void fft8(FFTComplex *z) {
- float t1, t2, t3, t4, t5, t6, t7, t8;
-
- fft4(z);
-
- BF(t1, z[5].re, z[4].re, -z[5].re);
- BF(t2, z[5].im, z[4].im, -z[5].im);
- BF(t3, z[7].re, z[6].re, -z[7].re);
- BF(t4, z[7].im, z[6].im, -z[7].im);
- BF(t8, t1, t3, t1);
- BF(t7, t2, t2, t4);
- BF(z[4].re, z[0].re, z[0].re, t1);
- BF(z[4].im, z[0].im, z[0].im, t2);
- BF(z[6].re, z[2].re, z[2].re, t7);
- BF(z[6].im, z[2].im, z[2].im, t8);
-
- TRANSFORM(z[1], z[3], z[5], z[7], sqrthalf, sqrthalf);
-}
-
-#undef BF
-
-DECL_FFT(16,8,4)
-DECL_FFT(32,16,8)
-DECL_FFT(64,32,16)
-DECL_FFT(128,64,32)
-DECL_FFT(256,128,64)
-DECL_FFT(512,256,128)
-#define pass pass_big
-DECL_FFT(1024,512,256)
-DECL_FFT(2048,1024,512)
-DECL_FFT(4096,2048,1024)
-DECL_FFT(8192,4096,2048)
-DECL_FFT(16384,8192,4096)
-DECL_FFT(32768,16384,8192)
-DECL_FFT(65536,32768,16384)
-
-void fftCalc(FFTContext *s, FFTComplex *z) {
- static void (* const fftDispatch[])(FFTComplex*) = {
- fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024,
- fft2048, fft4096, fft8192, fft16384, fft32768, fft65536,
- };
-
- fftDispatch[s->nbits - 2](z);
-}
-
-// complex multiplication: p = a * b
-#define CMUL(pre, pim, are, aim, bre, bim) \
-{\
- float _are = (are); \
- float _aim = (aim); \
- float _bre = (bre); \
- float _bim = (bim); \
- (pre) = _are * _bre - _aim * _bim; \
- (pim) = _are * _bim + _aim * _bre; \
-}
-
-/**
- * Compute the middle half of the inverse MDCT of size N = 2^nbits,
- * thus excluding the parts that can be derived by symmetry
- * @param output N/2 samples
- * @param input N/2 samples
- */
-void imdctHalfC(FFTContext *s, float *output, const float *input) {
- const uint16 *revtab = s->revtab;
- const float *tcos = s->tcos;
- const float *tsin = s->tsin;
- FFTComplex *z = (FFTComplex *)output;
-
- int n = 1 << s->mdctBits;
- int n2 = n >> 1;
- int n4 = n >> 2;
- int n8 = n >> 3;
-
- // pre rotation
- const float *in1 = input;
- const float *in2 = input + n2 - 1;
- for (int k = 0; k < n4; k++) {
- int j = revtab[k];
- CMUL(z[j].re, z[j].im, *in2, *in1, tcos[k], tsin[k]);
- in1 += 2;
- in2 -= 2;
- }
-
- fftCalc(s, z);
-
- // post rotation + reordering
- for (int k = 0; k < n8; k++) {
- float r0, i0, r1, i1;
- CMUL(r0, i1, z[n8 - k - 1].im, z[n8 - k - 1].re, tsin[n8 - k - 1], tcos[n8 - k - 1]);
- CMUL(r1, i0, z[n8 + k].im, z[n8 + k].re, tsin[n8 + k], tcos[n8 + k]);
- z[n8 - k - 1].re = r0;
- z[n8 - k - 1].im = i0;
- z[n8 + k].re = r1;
- z[n8 + k].im = i1;
- }
-}
-
-/**
- * Compute inverse MDCT of size N = 2^nbits
- * @param output N samples
- * @param input N/2 samples
- */
-void imdctCalcC(FFTContext *s, float *output, const float *input) {
- int n = 1 << s->mdctBits;
- int n2 = n >> 1;
- int n4 = n >> 2;
-
- imdctHalfC(s, output + n4, input);
-
- for (int k = 0; k < n4; k++) {
- output[k] = -output[n2 - k - 1];
- output[n - k - 1] = output[n2 + k];
- }
-}
-
-/**
- * Compute MDCT of size N = 2^nbits
- * @param input N samples
- * @param out N/2 samples
- */
-void mdctCalcC(FFTContext *s, float *out, const float *input) {
- const uint16 *revtab = s->revtab;
- const float *tcos = s->tcos;
- const float *tsin = s->tsin;
- FFTComplex *x = (FFTComplex *)out;
-
- int n = 1 << s->mdctBits;
- int n2 = n >> 1;
- int n4 = n >> 2;
- int n8 = n >> 3;
- int n3 = 3 * n4;
-
- // pre rotation
- for (int i = 0; i < n8; i++) {
- float re = -input[2 * i + 3 * n4] - input[n3 - 1 - 2 * i];
- float im = -input[n4 + 2 * i] + input[n4 - 1 - 2 * i];
- int j = revtab[i];
- CMUL(x[j].re, x[j].im, re, im, -tcos[i], tsin[i]);
-
- re = input[2 * i] - input[n2 - 1 - 2 * i];
- im = -(input[n2 + 2 * i] + input[n - 1 - 2 * i]);
- j = revtab[n8 + i];
- CMUL(x[j].re, x[j].im, re, im, -tcos[n8 + i], tsin[n8 + i]);
- }
-
- fftCalc(s, x);
-
- // post rotation
- for (int i = 0; i < n8; i++) {
- float r0, i0, r1, i1;
- CMUL(i1, r0, x[n8 - i - 1].re, x[n8 - i - 1].im, -tsin[n8 - i - 1], -tcos[n8 - i - 1]);
- CMUL(i0, r1, x[n8 + i].re, x[n8 + i].im, -tsin[n8 + i], -tcos[n8 + i]);
- x[n8 - i - 1].re = r0;
- x[n8 - i - 1].im = i0;
- x[n8 + i].re = r1;
- x[n8 + i].im = i1;
- }
-}
-
-int fftInit(FFTContext *s, int nbits, int inverse) {
- int i, j, m, n;
- float alpha, c1, s1, s2;
-
- if (nbits < 2 || nbits > 16)
- goto fail;
-
- s->nbits = nbits;
- n = 1 << nbits;
- s->tmpBuf = NULL;
-
- s->exptab = (FFTComplex *)malloc((n / 2) * sizeof(FFTComplex));
- if (!s->exptab)
- goto fail;
-
- s->revtab = (uint16 *)malloc(n * sizeof(uint16));
- if (!s->revtab)
- goto fail;
- s->inverse = inverse;
-
- s2 = inverse ? 1.0 : -1.0;
-
- s->fftPermute = fftPermute;
- s->fftCalc = fftCalc;
- s->imdctCalc = imdctCalcC;
- s->imdctHalf = imdctHalfC;
- s->mdctCalc = mdctCalcC;
- s->splitRadix = 1;
-
- if (s->splitRadix) {
- for (j = 4; j <= nbits; j++)
- initCosineTables(j);
-
- for (i = 0; i < n; i++)
- s->revtab[-splitRadixPermutation(i, n, s->inverse) & (n - 1)] = i;
-
- s->tmpBuf = (FFTComplex *)malloc(n * sizeof(FFTComplex));
- } else {
- for (i = 0; i < n / 2; i++) {
- alpha = 2 * PI * (float)i / (float)n;
- c1 = cos(alpha);
- s1 = sin(alpha) * s2;
- s->exptab[i].re = c1;
- s->exptab[i].im = s1;
- }
-
- //int np = 1 << nbits;
- //int nblocks = np >> 3;
- //int np2 = np >> 1;
-
- // compute bit reverse table
- for (i = 0; i < n; i++) {
- m = 0;
-
- for (j = 0; j < nbits; j++)
- m |= ((i >> j) & 1) << (nbits - j - 1);
-
- s->revtab[i] = m;
- }
- }
-
- return 0;
-
- fail:
- free(&s->revtab);
- free(&s->exptab);
- free(&s->tmpBuf);
- return -1;
-}
-
-/**
- * Sets up a real FFT.
- * @param nbits log2 of the length of the input array
- * @param trans the type of transform
- */
-int rdftInit(RDFTContext *s, int nbits, RDFTransformType trans) {
- int n = 1 << nbits;
- const double theta = (trans == RDFT || trans == IRIDFT ? -1 : 1) * 2 * PI / n;
-
- s->nbits = nbits;
- s->inverse = trans == IRDFT || trans == IRIDFT;
- s->signConvention = trans == RIDFT || trans == IRIDFT ? 1 : -1;
-
- if (nbits < 4 || nbits > 16)
- return -1;
-
- if (fftInit(&s->fft, nbits - 1, trans == IRDFT || trans == RIDFT) < 0)
- return -1;
-
- initCosineTables(nbits);
- s->tcos = ff_cos_tabs[nbits];
- s->tsin = ff_sin_tabs[nbits] + (trans == RDFT || trans == IRIDFT) * (n >> 2);
-
- for (int i = 0; i < n >> 2; i++)
- s->tsin[i] = sin(i*theta);
-
- return 0;
-}
-
-/** Map one real FFT into two parallel real even and odd FFTs. Then interleave
- * the two real FFTs into one complex FFT. Unmangle the results.
- * ref: http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM
- */
-void rdftCalc(RDFTContext *s, float *data) {
- FFTComplex ev, od;
-
- const int n = 1 << s->nbits;
- const float k1 = 0.5;
- const float k2 = 0.5 - s->inverse;
- const float *tcos = s->tcos;
- const float *tsin = s->tsin;
-
- if (!s->inverse) {
- fftPermute(&s->fft, (FFTComplex *)data);
- fftCalc(&s->fft, (FFTComplex *)data);
- }
-
- // i=0 is a special case because of packing, the DC term is real, so we
- // are going to throw the N/2 term (also real) in with it.
- ev.re = data[0];
- data[0] = ev.re + data[1];
- data[1] = ev.re - data[1];
-
- int i;
-
- for (i = 1; i < n >> 2; i++) {
- int i1 = i * 2;
- int i2 = n - i1;
-
- // Separate even and odd FFTs
- ev.re = k1 * (data[i1] + data[i2]);
- od.im = -k2 * (data[i1] - data[i2]);
- ev.im = k1 * (data[i1 + 1] - data[i2 + 1]);
- od.re = k2 * (data[i1 + 1] + data[i2 + 1]);
-
- // Apply twiddle factors to the odd FFT and add to the even FFT
- data[i1] = ev.re + od.re * tcos[i] - od.im * tsin[i];
- data[i1 + 1] = ev.im + od.im * tcos[i] + od.re * tsin[i];
- data[i2] = ev.re - od.re * tcos[i] + od.im * tsin[i];
- data[i2 + 1] = -ev.im + od.im * tcos[i] + od.re * tsin[i];
- }
-
- data[i * 2 + 1] = s->signConvention * data[i * 2 + 1];
- if (s->inverse) {
- data[0] *= k1;
- data[1] *= k1;
- fftPermute(&s->fft, (FFTComplex*)data);
- fftCalc(&s->fft, (FFTComplex*)data);
- }
-}
-
-// half mpeg encoding window (full precision)
-const int32 ff_mpa_enwindow[257] = {
- 0, -1, -1, -1, -1, -1, -1, -2,
- -2, -2, -2, -3, -3, -4, -4, -5,
- -5, -6, -7, -7, -8, -9, -10, -11,
- -13, -14, -16, -17, -19, -21, -24, -26,
- -29, -31, -35, -38, -41, -45, -49, -53,
- -58, -63, -68, -73, -79, -85, -91, -97,
- -104, -111, -117, -125, -132, -139, -147, -154,
- -161, -169, -176, -183, -190, -196, -202, -208,
- 213, 218, 222, 225, 227, 228, 228, 227,
- 224, 221, 215, 208, 200, 189, 177, 163,
- 146, 127, 106, 83, 57, 29, -2, -36,
- -72, -111, -153, -197, -244, -294, -347, -401,
- -459, -519, -581, -645, -711, -779, -848, -919,
- -991, -1064, -1137, -1210, -1283, -1356, -1428, -1498,
- -1567, -1634, -1698, -1759, -1817, -1870, -1919, -1962,
- -2001, -2032, -2057, -2075, -2085, -2087, -2080, -2063,
- 2037, 2000, 1952, 1893, 1822, 1739, 1644, 1535,
- 1414, 1280, 1131, 970, 794, 605, 402, 185,
- -45, -288, -545, -814, -1095, -1388, -1692, -2006,
- -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788,
- -5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597,
- -7910, -8209, -8491, -8755, -8998, -9219, -9416, -9585,
- -9727, -9838, -9916, -9959, -9966, -9935, -9863, -9750,
- -9592, -9389, -9139, -8840, -8492, -8092, -7640, -7134,
- 6574, 5959, 5288, 4561, 3776, 2935, 2037, 1082,
- 70, -998, -2122, -3300, -4533, -5818, -7154, -8540,
- -9975,-11455,-12980,-14548,-16155,-17799,-19478,-21189,
--22929,-24694,-26482,-28289,-30112,-31947,-33791,-35640,
--37489,-39336,-41176,-43006,-44821,-46617,-48390,-50137,
--51853,-53534,-55178,-56778,-58333,-59838,-61289,-62684,
--64019,-65290,-66494,-67629,-68692,-69679,-70590,-71420,
--72169,-72835,-73415,-73908,-74313,-74630,-74856,-74992,
- 75038
-};
-
-void ff_mpa_synth_init(int16 *window) {
- int i;
- int32 v;
-
- // max = 18760, max sum over all 16 coefs : 44736
- for(i = 0; i < 257; i++) {
- v = ff_mpa_enwindow[i];
- v = (v + 2) >> 2;
- window[i] = v;
-
- if ((i & 63) != 0)
- v = -v;
-
- if (i != 0)
- window[512 - i] = v;
- }
-}
-
-static inline uint16 round_sample(int *sum) {
- int sum1;
- sum1 = (*sum) >> 14;
- *sum &= (1 << 14)-1;
- if (sum1 < (-0x7fff - 1))
- sum1 = (-0x7fff - 1);
- if (sum1 > 0x7fff)
- sum1 = 0x7fff;
- return sum1;
-}
-
-static inline int MULH(int a, int b) {
- return ((int64_t)(a) * (int64_t)(b))>>32;
-}
-
-// signed 16x16 -> 32 multiply add accumulate
-#define MACS(rt, ra, rb) rt += (ra) * (rb)
-
-#define MLSS(rt, ra, rb) ((rt) -= (ra) * (rb))
-
-#define SUM8(op, sum, w, p)\
-{\
- op(sum, (w)[0 * 64], (p)[0 * 64]);\
- op(sum, (w)[1 * 64], (p)[1 * 64]);\
- op(sum, (w)[2 * 64], (p)[2 * 64]);\
- op(sum, (w)[3 * 64], (p)[3 * 64]);\
- op(sum, (w)[4 * 64], (p)[4 * 64]);\
- op(sum, (w)[5 * 64], (p)[5 * 64]);\
- op(sum, (w)[6 * 64], (p)[6 * 64]);\
- op(sum, (w)[7 * 64], (p)[7 * 64]);\
-}
-
-#define SUM8P2(sum1, op1, sum2, op2, w1, w2, p) \
-{\
- tmp_s = p[0 * 64];\
- op1(sum1, (w1)[0 * 64], tmp_s);\
- op2(sum2, (w2)[0 * 64], tmp_s);\
- tmp_s = p[1 * 64];\
- op1(sum1, (w1)[1 * 64], tmp_s);\
- op2(sum2, (w2)[1 * 64], tmp_s);\
- tmp_s = p[2 * 64];\
- op1(sum1, (w1)[2 * 64], tmp_s);\
- op2(sum2, (w2)[2 * 64], tmp_s);\
- tmp_s = p[3 * 64];\
- op1(sum1, (w1)[3 * 64], tmp_s);\
- op2(sum2, (w2)[3 * 64], tmp_s);\
- tmp_s = p[4 * 64];\
- op1(sum1, (w1)[4 * 64], tmp_s);\
- op2(sum2, (w2)[4 * 64], tmp_s);\
- tmp_s = p[5 * 64];\
- op1(sum1, (w1)[5 * 64], tmp_s);\
- op2(sum2, (w2)[5 * 64], tmp_s);\
- tmp_s = p[6 * 64];\
- op1(sum1, (w1)[6 * 64], tmp_s);\
- op2(sum2, (w2)[6 * 64], tmp_s);\
- tmp_s = p[7 * 64];\
- op1(sum1, (w1)[7 * 64], tmp_s);\
- op2(sum2, (w2)[7 * 64], tmp_s);\
-}
-
-#define FIXHR(a) ((int)((a) * (1LL<<32) + 0.5))
-
-// tab[i][j] = 1.0 / (2.0 * cos(pi*(2*k+1) / 2^(6 - j)))
-
-// cos(i*pi/64)
-
-#define COS0_0 FIXHR(0.50060299823519630134/2)
-#define COS0_1 FIXHR(0.50547095989754365998/2)
-#define COS0_2 FIXHR(0.51544730992262454697/2)
-#define COS0_3 FIXHR(0.53104259108978417447/2)
-#define COS0_4 FIXHR(0.55310389603444452782/2)
-#define COS0_5 FIXHR(0.58293496820613387367/2)
-#define COS0_6 FIXHR(0.62250412303566481615/2)
-#define COS0_7 FIXHR(0.67480834145500574602/2)
-#define COS0_8 FIXHR(0.74453627100229844977/2)
-#define COS0_9 FIXHR(0.83934964541552703873/2)
-#define COS0_10 FIXHR(0.97256823786196069369/2)
-#define COS0_11 FIXHR(1.16943993343288495515/4)
-#define COS0_12 FIXHR(1.48416461631416627724/4)
-#define COS0_13 FIXHR(2.05778100995341155085/8)
-#define COS0_14 FIXHR(3.40760841846871878570/8)
-#define COS0_15 FIXHR(10.19000812354805681150/32)
-
-#define COS1_0 FIXHR(0.50241928618815570551/2)
-#define COS1_1 FIXHR(0.52249861493968888062/2)
-#define COS1_2 FIXHR(0.56694403481635770368/2)
-#define COS1_3 FIXHR(0.64682178335999012954/2)
-#define COS1_4 FIXHR(0.78815462345125022473/2)
-#define COS1_5 FIXHR(1.06067768599034747134/4)
-#define COS1_6 FIXHR(1.72244709823833392782/4)
-#define COS1_7 FIXHR(5.10114861868916385802/16)
-
-#define COS2_0 FIXHR(0.50979557910415916894/2)
-#define COS2_1 FIXHR(0.60134488693504528054/2)
-#define COS2_2 FIXHR(0.89997622313641570463/2)
-#define COS2_3 FIXHR(2.56291544774150617881/8)
-
-#define COS3_0 FIXHR(0.54119610014619698439/2)
-#define COS3_1 FIXHR(1.30656296487637652785/4)
-
-#define COS4_0 FIXHR(0.70710678118654752439/2)
-
-/* butterfly operator */
-#define BF(a, b, c, s)\
-{\
- tmp0 = tab[a] + tab[b];\
- tmp1 = tab[a] - tab[b];\
- tab[a] = tmp0;\
- tab[b] = MULH(tmp1<<(s), c);\
-}
-
-#define BF1(a, b, c, d)\
-{\
- BF(a, b, COS4_0, 1);\
- BF(c, d,-COS4_0, 1);\
- tab[c] += tab[d];\
-}
-
-#define BF2(a, b, c, d)\
-{\
- BF(a, b, COS4_0, 1);\
- BF(c, d,-COS4_0, 1);\
- tab[c] += tab[d];\
- tab[a] += tab[c];\
- tab[c] += tab[b];\
- tab[b] += tab[d];\
-}
-
-#define ADD(a, b) tab[a] += tab[b]
-
-// DCT32 without 1/sqrt(2) coef zero scaling.
-static void dct32(int32 *out, int32 *tab) {
- int tmp0, tmp1;
-
- // pass 1
- BF( 0, 31, COS0_0 , 1);
- BF(15, 16, COS0_15, 5);
- // pass 2
- BF( 0, 15, COS1_0 , 1);
- BF(16, 31,-COS1_0 , 1);
- // pass 1
- BF( 7, 24, COS0_7 , 1);
- BF( 8, 23, COS0_8 , 1);
- // pass 2
- BF( 7, 8, COS1_7 , 4);
- BF(23, 24,-COS1_7 , 4);
- // pass 3
- BF( 0, 7, COS2_0 , 1);
- BF( 8, 15,-COS2_0 , 1);
- BF(16, 23, COS2_0 , 1);
- BF(24, 31,-COS2_0 , 1);
- // pass 1
- BF( 3, 28, COS0_3 , 1);
- BF(12, 19, COS0_12, 2);
- // pass 2
- BF( 3, 12, COS1_3 , 1);
- BF(19, 28,-COS1_3 , 1);
- // pass 1
- BF( 4, 27, COS0_4 , 1);
- BF(11, 20, COS0_11, 2);
- // pass 2
- BF( 4, 11, COS1_4 , 1);
- BF(20, 27,-COS1_4 , 1);
- // pass 3
- BF( 3, 4, COS2_3 , 3);
- BF(11, 12,-COS2_3 , 3);
- BF(19, 20, COS2_3 , 3);
- BF(27, 28,-COS2_3 , 3);
- // pass 4
- BF( 0, 3, COS3_0 , 1);
- BF( 4, 7,-COS3_0 , 1);
- BF( 8, 11, COS3_0 , 1);
- BF(12, 15,-COS3_0 , 1);
- BF(16, 19, COS3_0 , 1);
- BF(20, 23,-COS3_0 , 1);
- BF(24, 27, COS3_0 , 1);
- BF(28, 31,-COS3_0 , 1);
-
- // pass 1
- BF( 1, 30, COS0_1 , 1);
- BF(14, 17, COS0_14, 3);
- // pass 2
- BF( 1, 14, COS1_1 , 1);
- BF(17, 30,-COS1_1 , 1);
- // pass 1
- BF( 6, 25, COS0_6 , 1);
- BF( 9, 22, COS0_9 , 1);
- // pass 2
- BF( 6, 9, COS1_6 , 2);
- BF(22, 25,-COS1_6 , 2);
- // pass 3
- BF( 1, 6, COS2_1 , 1);
- BF( 9, 14,-COS2_1 , 1);
- BF(17, 22, COS2_1 , 1);
- BF(25, 30,-COS2_1 , 1);
-
- // pass 1
- BF( 2, 29, COS0_2 , 1);
- BF(13, 18, COS0_13, 3);
- // pass 2
- BF( 2, 13, COS1_2 , 1);
- BF(18, 29,-COS1_2 , 1);
- // pass 1
- BF( 5, 26, COS0_5 , 1);
- BF(10, 21, COS0_10, 1);
- // pass 2
- BF( 5, 10, COS1_5 , 2);
- BF(21, 26,-COS1_5 , 2);
- // pass 3
- BF( 2, 5, COS2_2 , 1);
- BF(10, 13,-COS2_2 , 1);
- BF(18, 21, COS2_2 , 1);
- BF(26, 29,-COS2_2 , 1);
- // pass 4
- BF( 1, 2, COS3_1 , 2);
- BF( 5, 6,-COS3_1 , 2);
- BF( 9, 10, COS3_1 , 2);
- BF(13, 14,-COS3_1 , 2);
- BF(17, 18, COS3_1 , 2);
- BF(21, 22,-COS3_1 , 2);
- BF(25, 26, COS3_1 , 2);
- BF(29, 30,-COS3_1 , 2);
-
- // pass 5
- BF1( 0, 1, 2, 3);
- BF2( 4, 5, 6, 7);
- BF1( 8, 9, 10, 11);
- BF2(12, 13, 14, 15);
- BF1(16, 17, 18, 19);
- BF2(20, 21, 22, 23);
- BF1(24, 25, 26, 27);
- BF2(28, 29, 30, 31);
-
- // pass 6
- ADD( 8, 12);
- ADD(12, 10);
- ADD(10, 14);
- ADD(14, 9);
- ADD( 9, 13);
- ADD(13, 11);
- ADD(11, 15);
-
- out[ 0] = tab[0];
- out[16] = tab[1];
- out[ 8] = tab[2];
- out[24] = tab[3];
- out[ 4] = tab[4];
- out[20] = tab[5];
- out[12] = tab[6];
- out[28] = tab[7];
- out[ 2] = tab[8];
- out[18] = tab[9];
- out[10] = tab[10];
- out[26] = tab[11];
- out[ 6] = tab[12];
- out[22] = tab[13];
- out[14] = tab[14];
- out[30] = tab[15];
-
- ADD(24, 28);
- ADD(28, 26);
- ADD(26, 30);
- ADD(30, 25);
- ADD(25, 29);
- ADD(29, 27);
- ADD(27, 31);
-
- out[ 1] = tab[16] + tab[24];
- out[17] = tab[17] + tab[25];
- out[ 9] = tab[18] + tab[26];
- out[25] = tab[19] + tab[27];
- out[ 5] = tab[20] + tab[28];
- out[21] = tab[21] + tab[29];
- out[13] = tab[22] + tab[30];
- out[29] = tab[23] + tab[31];
- out[ 3] = tab[24] + tab[20];
- out[19] = tab[25] + tab[21];
- out[11] = tab[26] + tab[22];
- out[27] = tab[27] + tab[23];
- out[ 7] = tab[28] + tab[18];
- out[23] = tab[29] + tab[19];
- out[15] = tab[30] + tab[17];
- out[31] = tab[31];
-}
-
-// 32 sub band synthesis filter. Input: 32 sub band samples, Output:
-// 32 samples.
-// XXX: optimize by avoiding ring buffer usage
-void ff_mpa_synth_filter(int16 *synth_buf_ptr, int *synth_buf_offset,
- int16 *window, int *dither_state,
- int16 *samples, int incr,
- int32 sb_samples[32])
-{
- int16 *synth_buf;
- const int16 *w, *w2, *p;
- int j, offset;
- int16 *samples2;
- int32 tmp[32];
- int sum, sum2;
- int tmp_s;
-
- offset = *synth_buf_offset;
- synth_buf = synth_buf_ptr + offset;
-
- dct32(tmp, sb_samples);
- for(j = 0; j < 32; j++) {
- // NOTE: can cause a loss in precision if very high amplitude sound
- if (tmp[j] < (-0x7fff - 1))
- synth_buf[j] = (-0x7fff - 1);
- else if (tmp[j] > 0x7fff)
- synth_buf[j] = 0x7fff;
- else
- synth_buf[j] = tmp[j];
- }
-
- // copy to avoid wrap
- memcpy(synth_buf + 512, synth_buf, 32 * sizeof(int16));
-
- samples2 = samples + 31 * incr;
- w = window;
- w2 = window + 31;
-
- sum = *dither_state;
- p = synth_buf + 16;
- SUM8(MACS, sum, w, p);
- p = synth_buf + 48;
- SUM8(MLSS, sum, w + 32, p);
- *samples = round_sample(&sum);
- samples += incr;
- w++;
-
- // we calculate two samples at the same time to avoid one memory
- // access per two sample
- for(j = 1; j < 16; j++) {
- sum2 = 0;
- p = synth_buf + 16 + j;
- SUM8P2(sum, MACS, sum2, MLSS, w, w2, p);
- p = synth_buf + 48 - j;
- SUM8P2(sum, MLSS, sum2, MLSS, w + 32, w2 + 32, p);
-
- *samples = round_sample(&sum);
- samples += incr;
- sum += sum2;
- *samples2 = round_sample(&sum);
- samples2 -= incr;
- w++;
- w2--;
- }
-
- p = synth_buf + 32;
- SUM8(MLSS, sum, w + 32, p);
- *samples = round_sample(&sum);
- *dither_state= sum;
-
- offset = (offset - 32) & 511;
- *synth_buf_offset = offset;
-}
-
-/**
- * parses a vlc code, faster then get_vlc()
- * @param bits is the number of bits which will be read at once, must be
- * identical to nb_bits in init_vlc()
- * @param max_depth is the number of times bits bits must be read to completely
- * read the longest vlc code
- * = (max_vlc_length + bits - 1) / bits
- */
-static int getVlc2(GetBitContext *s, int16 (*table)[2], int bits, int maxDepth) {
- int reIndex;
- int reCache;
- int index;
- int code;
- int n;
-
- debug(1, "int getVlc2(GetBitContext *s, int16 (*table)[2], int bits, int maxDepth)");
-
- reIndex = s->index;
- reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
- index = reCache & (0xffffffff >> (32 - bits));
- code = table[index][0];
- n = table[index][1];
-
- debug(1, "reIndex : %d", reIndex);
- debug(1, "reCache : %d", reCache);
- debug(1, "index : %d", index);
- debug(1, "code : %d", code);
- debug(1, "n : %d", n);
-
- if (maxDepth > 1 && n < 0){
- reIndex += bits;
- reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
-
- int nbBits = -n;
-
- index = (reCache & (0xffffffff >> (32 - nbBits))) + code;
- code = table[index][0];
- n = table[index][1];
-
- if(maxDepth > 2 && n < 0) {
- reIndex += nbBits;
- reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
-
- nbBits = -n;
-
- index = (reCache & (0xffffffff >> (32 - nbBits))) + code;
- code = table[index][0];
- n = table[index][1];
- }
- }
-
- reCache >>= n;
- s->index = reIndex + n;
- return code;
-}
-
-static int allocTable(VLC *vlc, int size, int use_static) {
- int index;
- index = vlc->table_size;
- vlc->table_size += size;
- if (vlc->table_size > vlc->table_allocated) {
- if(use_static)
- error("QDM2 cant do anything, init_vlc() is used with too little memory");
- vlc->table_allocated += (1 << vlc->bits);
- vlc->table = (int16 (*)[2])realloc(vlc->table, sizeof(int16 *) * 2 * vlc->table_allocated);
- if (!vlc->table)
- return -1;
- }
- return index;
-}
-
-#define GET_DATA(v, table, i, wrap, size)\
-{\
- const uint8 *ptr = (const uint8 *)table + i * wrap;\
- switch(size) {\
- case 1:\
- v = *(const uint8 *)ptr;\
- break;\
- case 2:\
- v = *(const uint16 *)ptr;\
- break;\
- default:\
- v = *(const uint32 *)ptr;\
- break;\
- }\
-}
-
-static int build_table(VLC *vlc, int table_nb_bits,
- int nb_codes,
- const void *bits, int bits_wrap, int bits_size,
- const void *codes, int codes_wrap, int codes_size,
- const void *symbols, int symbols_wrap, int symbols_size,
- int code_prefix, int n_prefix, int flags)
-{
- int i, j, k, n, table_size, table_index, nb, n1, index, code_prefix2, symbol;
- uint32 code;
- int16 (*table)[2];
-
- table_size = 1 << table_nb_bits;
- table_index = allocTable(vlc, table_size, flags & 4);
- debug(2, "QDM2 new table index=%d size=%d code_prefix=%x n=%d", table_index, table_size, code_prefix, n_prefix);
- if (table_index < 0)
- return -1;
- table = &vlc->table[table_index];
-
- for(i = 0; i < table_size; i++) {
- table[i][1] = 0; //bits
- table[i][0] = -1; //codes
- }
-
- // first pass: map codes and compute auxillary table sizes
- for(i = 0; i < nb_codes; i++) {
- GET_DATA(n, bits, i, bits_wrap, bits_size);
- GET_DATA(code, codes, i, codes_wrap, codes_size);
- // we accept tables with holes
- if (n <= 0)
- continue;
- if (!symbols)
- symbol = i;
- else
- GET_DATA(symbol, symbols, i, symbols_wrap, symbols_size);
- debug(2, "QDM2 i=%d n=%d code=0x%x", i, n, code);
- // if code matches the prefix, it is in the table
- n -= n_prefix;
- if(flags & 2)
- code_prefix2= code & (n_prefix>=32 ? 0xffffffff : (1 << n_prefix)-1);
- else
- code_prefix2= code >> n;
- if (n > 0 && code_prefix2 == code_prefix) {
- if (n <= table_nb_bits) {
- // no need to add another table
- j = (code << (table_nb_bits - n)) & (table_size - 1);
- nb = 1 << (table_nb_bits - n);
- for(k = 0; k < nb; k++) {
- if(flags & 2)
- j = (code >> n_prefix) + (k<<n);
- debug(2, "QDM2 %4x: code=%d n=%d",j, i, n);
- if (table[j][1] /*bits*/ != 0) {
- error("QDM2 incorrect codes");
- return -1;
- }
- table[j][1] = n; //bits
- table[j][0] = symbol;
- j++;
- }
- } else {
- n -= table_nb_bits;
- j = (code >> ((flags & 2) ? n_prefix : n)) & ((1 << table_nb_bits) - 1);
- debug(2, "QDM2 %4x: n=%d (subtable)", j, n);
- // compute table size
- n1 = -table[j][1]; //bits
- if (n > n1)
- n1 = n;
- table[j][1] = -n1; //bits
- }
- }
- }
-
- // second pass : fill auxillary tables recursively
- for(i = 0;i < table_size; i++) {
- n = table[i][1]; //bits
- if (n < 0) {
- n = -n;
- if (n > table_nb_bits) {
- n = table_nb_bits;
- table[i][1] = -n; //bits
- }
- index = build_table(vlc, n, nb_codes,
- bits, bits_wrap, bits_size,
- codes, codes_wrap, codes_size,
- symbols, symbols_wrap, symbols_size,
- (flags & 2) ? (code_prefix | (i << n_prefix)) : ((code_prefix << table_nb_bits) | i),
- n_prefix + table_nb_bits, flags);
- if (index < 0)
- return -1;
- // note: realloc has been done, so reload tables
- table = &vlc->table[table_index];
- table[i][0] = index; //code
- }
- }
- return table_index;
-}
-
-/* Build VLC decoding tables suitable for use with get_vlc().
-
- 'nb_bits' set thee decoding table size (2^nb_bits) entries. The
- bigger it is, the faster is the decoding. But it should not be too
- big to save memory and L1 cache. '9' is a good compromise.
-
- 'nb_codes' : number of vlcs codes
-
- 'bits' : table which gives the size (in bits) of each vlc code.
-
- 'codes' : table which gives the bit pattern of of each vlc code.
-
- 'symbols' : table which gives the values to be returned from get_vlc().
-
- 'xxx_wrap' : give the number of bytes between each entry of the
- 'bits' or 'codes' tables.
-
- 'xxx_size' : gives the number of bytes of each entry of the 'bits'
- or 'codes' tables.
-
- 'wrap' and 'size' allows to use any memory configuration and types
- (byte/word/long) to store the 'bits', 'codes', and 'symbols' tables.
-
- 'use_static' should be set to 1 for tables, which should be freed
- with av_free_static(), 0 if free_vlc() will be used.
-*/
-void initVlcSparse(VLC *vlc, int nb_bits, int nb_codes,
- const void *bits, int bits_wrap, int bits_size,
- const void *codes, int codes_wrap, int codes_size,
- const void *symbols, int symbols_wrap, int symbols_size) {
- vlc->bits = nb_bits;
-
- if(vlc->table_size && vlc->table_size == vlc->table_allocated) {
- return;
- } else if(vlc->table_size) {
- error("called on a partially initialized table");
- }
-
- debug(2, "QDM2 build table nb_codes=%d", nb_codes);
-
- if (build_table(vlc, nb_bits, nb_codes,
- bits, bits_wrap, bits_size,
- codes, codes_wrap, codes_size,
- symbols, symbols_wrap, symbols_size,
- 0, 0, 4 | 2) < 0) {
- free(&vlc->table);
- return; // Error
- }
-
- if(vlc->table_size != vlc->table_allocated)
- error("QDM2 needed %d had %d", vlc->table_size, vlc->table_allocated);
-}
-
-void QDM2Stream::softclipTableInit(void) {
- uint16 i;
- double dfl = SOFTCLIP_THRESHOLD - 32767;
- float delta = 1.0 / -dfl;
-
- for (i = 0; i < ARRAYSIZE(_softclipTable); i++)
- _softclipTable[i] = SOFTCLIP_THRESHOLD - ((int)(sin((float)i * delta) * dfl) & 0x0000FFFF);
-}
-
-// random generated table
-void QDM2Stream::rndTableInit(void) {
- uint16 i;
- uint16 j;
- uint32 ldw, hdw;
- // TODO: Replace Code with uint64 less version...
- int64_t tmp64_1;
- int64_t random_seed = 0;
- float delta = 1.0 / 16384.0;
-
- for(i = 0; i < ARRAYSIZE(_noiseTable); i++) {
- random_seed = random_seed * 214013 + 2531011;
- _noiseTable[i] = (delta * (float)(((int32)random_seed >> 16) & 0x00007FFF)- 1.0) * 1.3;
- }
-
- for (i = 0; i < 256; i++) {
- random_seed = 81;
- ldw = i;
- for (j = 0; j < 5; j++) {
- _randomDequantIndex[i][j] = (uint8)((ldw / random_seed) & 0xFF);
- ldw = (uint32)ldw % (uint32)random_seed;
- tmp64_1 = (random_seed * 0x55555556);
- hdw = (uint32)(tmp64_1 >> 32);
- random_seed = (int64_t)(hdw + (ldw >> 31));
- }
- }
-
- for (i = 0; i < 128; i++) {
- random_seed = 25;
- ldw = i;
- for (j = 0; j < 3; j++) {
- _randomDequantType24[i][j] = (uint8)((ldw / random_seed) & 0xFF);
- ldw = (uint32)ldw % (uint32)random_seed;
- tmp64_1 = (random_seed * 0x66666667);
- hdw = (uint32)(tmp64_1 >> 33);
- random_seed = hdw + (ldw >> 31);
- }
- }
-}
-
-void QDM2Stream::initNoiseSamples(void) {
- uint16 i;
- uint32 random_seed = 0;
- float delta = 1.0 / 16384.0;
-
- for (i = 0; i < ARRAYSIZE(_noiseSamples); i++) {
- random_seed = random_seed * 214013 + 2531011;
- _noiseSamples[i] = (delta * (float)((random_seed >> 16) & 0x00007fff) - 1.0);
- }
-}
-
-static const uint16 qdm2_vlc_offs[18] = {
- 0, 260, 566, 598, 894, 1166, 1230, 1294, 1678, 1950, 2214, 2278, 2310, 2570, 2834, 3124, 3448, 3838
-};
-
-void QDM2Stream::initVlc(void) {
- static int16 qdm2_table[3838][2];
-
- if (!_vlcsInitialized) {
- _vlcTabLevel.table = &qdm2_table[qdm2_vlc_offs[0]];
- _vlcTabLevel.table_allocated = qdm2_vlc_offs[1] - qdm2_vlc_offs[0];
- _vlcTabLevel.table_size = 0;
- initVlcSparse(&_vlcTabLevel, 8, 24,
- vlc_tab_level_huffbits, 1, 1,
- vlc_tab_level_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabDiff.table = &qdm2_table[qdm2_vlc_offs[1]];
- _vlcTabDiff.table_allocated = qdm2_vlc_offs[2] - qdm2_vlc_offs[1];
- _vlcTabDiff.table_size = 0;
- initVlcSparse(&_vlcTabDiff, 8, 37,
- vlc_tab_diff_huffbits, 1, 1,
- vlc_tab_diff_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabRun.table = &qdm2_table[qdm2_vlc_offs[2]];
- _vlcTabRun.table_allocated = qdm2_vlc_offs[3] - qdm2_vlc_offs[2];
- _vlcTabRun.table_size = 0;
- initVlcSparse(&_vlcTabRun, 5, 6,
- vlc_tab_run_huffbits, 1, 1,
- vlc_tab_run_huffcodes, 1, 1, NULL, 0, 0);
-
- _fftLevelExpAltVlc.table = &qdm2_table[qdm2_vlc_offs[3]];
- _fftLevelExpAltVlc.table_allocated = qdm2_vlc_offs[4] - qdm2_vlc_offs[3];
- _fftLevelExpAltVlc.table_size = 0;
- initVlcSparse(&_fftLevelExpAltVlc, 8, 28,
- fft_level_exp_alt_huffbits, 1, 1,
- fft_level_exp_alt_huffcodes, 2, 2, NULL, 0, 0);
-
- _fftLevelExpVlc.table = &qdm2_table[qdm2_vlc_offs[4]];
- _fftLevelExpVlc.table_allocated = qdm2_vlc_offs[5] - qdm2_vlc_offs[4];
- _fftLevelExpVlc.table_size = 0;
- initVlcSparse(&_fftLevelExpVlc, 8, 20,
- fft_level_exp_huffbits, 1, 1,
- fft_level_exp_huffcodes, 2, 2, NULL, 0, 0);
-
- _fftStereoExpVlc.table = &qdm2_table[qdm2_vlc_offs[5]];
- _fftStereoExpVlc.table_allocated = qdm2_vlc_offs[6] - qdm2_vlc_offs[5];
- _fftStereoExpVlc.table_size = 0;
- initVlcSparse(&_fftStereoExpVlc, 6, 7,
- fft_stereo_exp_huffbits, 1, 1,
- fft_stereo_exp_huffcodes, 1, 1, NULL, 0, 0);
-
- _fftStereoPhaseVlc.table = &qdm2_table[qdm2_vlc_offs[6]];
- _fftStereoPhaseVlc.table_allocated = qdm2_vlc_offs[7] - qdm2_vlc_offs[6];
- _fftStereoPhaseVlc.table_size = 0;
- initVlcSparse(&_fftStereoPhaseVlc, 6, 9,
- fft_stereo_phase_huffbits, 1, 1,
- fft_stereo_phase_huffcodes, 1, 1, NULL, 0, 0);
-
- _vlcTabToneLevelIdxHi1.table = &qdm2_table[qdm2_vlc_offs[7]];
- _vlcTabToneLevelIdxHi1.table_allocated = qdm2_vlc_offs[8] - qdm2_vlc_offs[7];
- _vlcTabToneLevelIdxHi1.table_size = 0;
- initVlcSparse(&_vlcTabToneLevelIdxHi1, 8, 20,
- vlc_tab_tone_level_idx_hi1_huffbits, 1, 1,
- vlc_tab_tone_level_idx_hi1_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabToneLevelIdxMid.table = &qdm2_table[qdm2_vlc_offs[8]];
- _vlcTabToneLevelIdxMid.table_allocated = qdm2_vlc_offs[9] - qdm2_vlc_offs[8];
- _vlcTabToneLevelIdxMid.table_size = 0;
- initVlcSparse(&_vlcTabToneLevelIdxMid, 8, 24,
- vlc_tab_tone_level_idx_mid_huffbits, 1, 1,
- vlc_tab_tone_level_idx_mid_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabToneLevelIdxHi2.table = &qdm2_table[qdm2_vlc_offs[9]];
- _vlcTabToneLevelIdxHi2.table_allocated = qdm2_vlc_offs[10] - qdm2_vlc_offs[9];
- _vlcTabToneLevelIdxHi2.table_size = 0;
- initVlcSparse(&_vlcTabToneLevelIdxHi2, 8, 24,
- vlc_tab_tone_level_idx_hi2_huffbits, 1, 1,
- vlc_tab_tone_level_idx_hi2_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabType30.table = &qdm2_table[qdm2_vlc_offs[10]];
- _vlcTabType30.table_allocated = qdm2_vlc_offs[11] - qdm2_vlc_offs[10];
- _vlcTabType30.table_size = 0;
- initVlcSparse(&_vlcTabType30, 6, 9,
- vlc_tab_type30_huffbits, 1, 1,
- vlc_tab_type30_huffcodes, 1, 1, NULL, 0, 0);
-
- _vlcTabType34.table = &qdm2_table[qdm2_vlc_offs[11]];
- _vlcTabType34.table_allocated = qdm2_vlc_offs[12] - qdm2_vlc_offs[11];
- _vlcTabType34.table_size = 0;
- initVlcSparse(&_vlcTabType34, 5, 10,
- vlc_tab_type34_huffbits, 1, 1,
- vlc_tab_type34_huffcodes, 1, 1, NULL, 0, 0);
-
- _vlcTabFftToneOffset[0].table = &qdm2_table[qdm2_vlc_offs[12]];
- _vlcTabFftToneOffset[0].table_allocated = qdm2_vlc_offs[13] - qdm2_vlc_offs[12];
- _vlcTabFftToneOffset[0].table_size = 0;
- initVlcSparse(&_vlcTabFftToneOffset[0], 8, 23,
- vlc_tab_fft_tone_offset_0_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_0_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabFftToneOffset[1].table = &qdm2_table[qdm2_vlc_offs[13]];
- _vlcTabFftToneOffset[1].table_allocated = qdm2_vlc_offs[14] - qdm2_vlc_offs[13];
- _vlcTabFftToneOffset[1].table_size = 0;
- initVlcSparse(&_vlcTabFftToneOffset[1], 8, 28,
- vlc_tab_fft_tone_offset_1_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_1_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabFftToneOffset[2].table = &qdm2_table[qdm2_vlc_offs[14]];
- _vlcTabFftToneOffset[2].table_allocated = qdm2_vlc_offs[15] - qdm2_vlc_offs[14];
- _vlcTabFftToneOffset[2].table_size = 0;
- initVlcSparse(&_vlcTabFftToneOffset[2], 8, 32,
- vlc_tab_fft_tone_offset_2_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_2_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabFftToneOffset[3].table = &qdm2_table[qdm2_vlc_offs[15]];
- _vlcTabFftToneOffset[3].table_allocated = qdm2_vlc_offs[16] - qdm2_vlc_offs[15];
- _vlcTabFftToneOffset[3].table_size = 0;
- initVlcSparse(&_vlcTabFftToneOffset[3], 8, 35,
- vlc_tab_fft_tone_offset_3_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_3_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabFftToneOffset[4].table = &qdm2_table[qdm2_vlc_offs[16]];
- _vlcTabFftToneOffset[4].table_allocated = qdm2_vlc_offs[17] - qdm2_vlc_offs[16];
- _vlcTabFftToneOffset[4].table_size = 0;
- initVlcSparse(&_vlcTabFftToneOffset[4], 8, 38,
- vlc_tab_fft_tone_offset_4_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_4_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcsInitialized = true;
- }
-}
-
-QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) {
- uint32 tmp;
- int32 tmp_s;
- int tmp_val;
- int i;
-
- debug(1, "QDM2Stream::QDM2Stream() Call");
-
- _stream = stream;
- _compressedData = NULL;
- _subPacket = 0;
- memset(_quantizedCoeffs, 0, sizeof(_quantizedCoeffs));
- memset(_fftLevelExp, 0, sizeof(_fftLevelExp));
- _noiseIdx = 0;
- memset(_fftCoefsMinIndex, 0, sizeof(_fftCoefsMinIndex));
- memset(_fftCoefsMaxIndex, 0, sizeof(_fftCoefsMaxIndex));
- _fftToneStart = 0;
- _fftToneEnd = 0;
- for(i = 0; i < ARRAYSIZE(_subPacketListA); i++) {
- _subPacketListA[i].packet = NULL;
- _subPacketListA[i].next = NULL;
- }
- _subPacketsB = 0;
- for(i = 0; i < ARRAYSIZE(_subPacketListB); i++) {
- _subPacketListB[i].packet = NULL;
- _subPacketListB[i].next = NULL;
- }
- for(i = 0; i < ARRAYSIZE(_subPacketListC); i++) {
- _subPacketListC[i].packet = NULL;
- _subPacketListC[i].next = NULL;
- }
- for(i = 0; i < ARRAYSIZE(_subPacketListD); i++) {
- _subPacketListD[i].packet = NULL;
- _subPacketListD[i].next = NULL;
- }
- memset(_synthBuf, 0, sizeof(_synthBuf));
- memset(_synthBufOffset, 0, sizeof(_synthBufOffset));
- memset(_sbSamples, 0, sizeof(_sbSamples));
- memset(_outputBuffer, 0, sizeof(_outputBuffer));
- _vlcsInitialized = false;
- _superblocktype_2_3 = 0;
- _hasErrors = false;
-
- // Rewind extraData stream from any previous calls...
- extraData->seek(0, SEEK_SET);
-
- tmp_s = extraData->readSint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraSize: %d", tmp_s);
- if ((extraData->size() - extraData->pos()) / 4 + 1 != tmp_s)
- warning("QDM2Stream::QDM2Stream() extraSize mismatch - Expected %d", (extraData->size() - extraData->pos()) / 4 + 1);
- if (tmp_s < 12)
- error("QDM2Stream::QDM2Stream() Insufficient extraData");
-
- tmp = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraTag: %d", tmp);
- if (tmp != MKID_BE('frma'))
- warning("QDM2Stream::QDM2Stream() extraTag mismatch");
-
- tmp = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraType: %d", tmp);
- if (tmp == MKID_BE('QDMC'))
- warning("QDM2Stream::QDM2Stream() QDMC stream type not supported.");
- else if (tmp != MKID_BE('QDM2'))
- error("QDM2Stream::QDM2Stream() Unsupported stream type");
-
- tmp_s = extraData->readSint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraSize2: %d", tmp_s);
- if ((extraData->size() - extraData->pos()) + 4 != tmp_s)
- warning("QDM2Stream::QDM2Stream() extraSize2 mismatch - Expected %d", (extraData->size() - extraData->pos()) + 4);
-
- tmp = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraTag2: %d", tmp);
- if (tmp != MKID_BE('QDCA'))
- warning("QDM2Stream::QDM2Stream() extraTag2 mismatch");
-
- if (extraData->readUint32BE() != 1)
- warning("QDM2Stream::QDM2Stream() u0 field not 1");
-
- _channels = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() channels: %d", _channels);
-
- _sampleRate = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() sampleRate: %d", _sampleRate);
-
- _bitRate = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() bitRate: %d", _bitRate);
-
- _blockSize = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() blockSize: %d", _blockSize);
-
- _frameSize = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() frameSize: %d", _frameSize);
-
- _packetSize = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() packetSize: %d", _packetSize);
-
- if (extraData->size() - extraData->pos() != 0) {
- tmp_s = extraData->readSint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraSize3: %d", tmp_s);
- if (extraData->size() + 4 != tmp_s)
- warning("QDM2Stream::QDM2Stream() extraSize3 mismatch - Expected %d", extraData->size() + 4);
-
- tmp = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraTag3: %d", tmp);
- if (tmp != MKID_BE('QDCP'))
- warning("QDM2Stream::QDM2Stream() extraTag3 mismatch");
-
- if ((float)extraData->readUint32BE() != 1.0)
- warning("QDM2Stream::QDM2Stream() uf0 field not 1.0");
-
- if (extraData->readUint32BE() != 0)
- warning("QDM2Stream::QDM2Stream() u1 field not 0");
-
- if ((float)extraData->readUint32BE() != 1.0)
- warning("QDM2Stream::QDM2Stream() uf1 field not 1.0");
-
- if ((float)extraData->readUint32BE() != 1.0)
- warning("QDM2Stream::QDM2Stream() uf2 field not 1.0");
-
- if (extraData->readUint32BE() != 27)
- warning("QDM2Stream::QDM2Stream() u2 field not 27");
-
- if (extraData->readUint32BE() != 8)
- warning("QDM2Stream::QDM2Stream() u3 field not 8");
-
- if (extraData->readUint32BE() != 0)
- warning("QDM2Stream::QDM2Stream() u4 field not 0");
- }
-
- _fftOrder = scummvm_log2(_frameSize) + 1;
- _fftFrameSize = 2 * _frameSize; // complex has two floats
-
- // something like max decodable tones
- _groupOrder = scummvm_log2(_blockSize) + 1;
- _sFrameSize = _blockSize / 16; // 16 iterations per super block
-
- _subSampling = _fftOrder - 7;
- _frequencyRange = 255 / (1 << (2 - _subSampling));
-
- switch ((_subSampling * 2 + _channels - 1)) {
- case 0:
- tmp = 40;
- break;
- case 1:
- tmp = 48;
- break;
- case 2:
- tmp = 56;
- break;
- case 3:
- tmp = 72;
- break;
- case 4:
- tmp = 80;
- break;
- case 5:
- tmp = 100;
- break;
- default:
- tmp = _subSampling;
- break;
- }
-
- tmp_val = 0;
- if ((tmp * 1000) < _bitRate) tmp_val = 1;
- if ((tmp * 1440) < _bitRate) tmp_val = 2;
- if ((tmp * 1760) < _bitRate) tmp_val = 3;
- if ((tmp * 2240) < _bitRate) tmp_val = 4;
- _cmTableSelect = tmp_val;
-
- if (_subSampling == 0)
- tmp = 7999;
- else
- tmp = ((-(_subSampling -1)) & 8000) + 20000;
-
- if (tmp < 8000)
- _coeffPerSbSelect = 0;
- else if (tmp <= 16000)
- _coeffPerSbSelect = 1;
- else
- _coeffPerSbSelect = 2;
-
- if (_fftOrder < 7 || _fftOrder > 9)
- error("QDM2Stream::QDM2Stream() Unsupported fft_order: %d", _fftOrder);
-
- rdftInit(&_rdftCtx, _fftOrder, IRDFT);
-
- initVlc();
- ff_mpa_synth_init(ff_mpa_synth_window);
- softclipTableInit();
- rndTableInit();
- initNoiseSamples();
-
- _compressedData = new uint8[_packetSize];
-}
-
-QDM2Stream::~QDM2Stream() {
- delete[] _compressedData;
- delete _stream;
-}
-
-static int qdm2_get_vlc(GetBitContext *gb, VLC *vlc, int flag, int depth) {
- int value = getVlc2(gb, vlc->table, vlc->bits, depth);
-
- // stage-2, 3 bits exponent escape sequence
- if (value-- == 0)
- value = getBits(gb, getBits (gb, 3) + 1);
-
- // stage-3, optional
- if (flag) {
- int tmp = vlc_stage3_values[value];
-
- if ((value & ~3) > 0)
- tmp += getBits(gb, (value >> 2));
- value = tmp;
- }
-
- return value;
-}
-
-static int qdm2_get_se_vlc(VLC *vlc, GetBitContext *gb, int depth)
-{
- int value = qdm2_get_vlc(gb, vlc, 0, depth);
-
- return (value & 1) ? ((value + 1) >> 1) : -(value >> 1);
-}
-
-/**
- * QDM2 checksum
- *
- * @param data pointer to data to be checksum'ed
- * @param length data length
- * @param value checksum value
- *
- * @return 0 if checksum is OK
- */
-static uint16 qdm2_packet_checksum(const uint8 *data, int length, int value) {
- int i;
-
- for (i = 0; i < length; i++)
- value -= data[i];
-
- return (uint16)(value & 0xffff);
-}
-
-/**
- * Fills a QDM2SubPacket structure with packet type, size, and data pointer.
- *
- * @param gb bitreader context
- * @param sub_packet packet under analysis
- */
-static void qdm2_decode_sub_packet_header(GetBitContext *gb, QDM2SubPacket *sub_packet)
-{
- sub_packet->type = getBits (gb, 8);
-
- if (sub_packet->type == 0) {
- sub_packet->size = 0;
- sub_packet->data = NULL;
- } else {
- sub_packet->size = getBits (gb, 8);
-
- if (sub_packet->type & 0x80) {
- sub_packet->size <<= 8;
- sub_packet->size |= getBits (gb, 8);
- sub_packet->type &= 0x7f;
- }
-
- if (sub_packet->type == 0x7f)
- sub_packet->type |= (getBits (gb, 8) << 8);
-
- sub_packet->data = &gb->buffer[getBitsCount(gb) / 8]; // FIXME: this depends on bitreader internal data
- }
-
- debug(1, "QDM2 Subpacket: type=%d size=%d start_offs=%x", sub_packet->type, sub_packet->size, getBitsCount(gb) / 8);
-}
-
-/**
- * Return node pointer to first packet of requested type in list.
- *
- * @param list list of subpackets to be scanned
- * @param type type of searched subpacket
- * @return node pointer for subpacket if found, else NULL
- */
-static QDM2SubPNode* qdm2_search_subpacket_type_in_list(QDM2SubPNode *list, int type)
-{
- while (list != NULL && list->packet != NULL) {
- if (list->packet->type == type)
- return list;
- list = list->next;
- }
- return NULL;
-}
-
-/**
- * Replaces 8 elements with their average value.
- * Called by qdm2_decode_superblock before starting subblock decoding.
- */
-void QDM2Stream::average_quantized_coeffs(void) {
- int i, j, n, ch, sum;
-
- n = coeff_per_sb_for_avg[_coeffPerSbSelect][QDM2_SB_USED(_subSampling) - 1] + 1;
-
- for (ch = 0; ch < _channels; ch++) {
- for (i = 0; i < n; i++) {
- sum = 0;
-
- for (j = 0; j < 8; j++)
- sum += _quantizedCoeffs[ch][i][j];
-
- sum /= 8;
- if (sum > 0)
- sum--;
-
- for (j = 0; j < 8; j++)
- _quantizedCoeffs[ch][i][j] = sum;
- }
- }
-}
-
-/**
- * Build subband samples with noise weighted by q->tone_level.
- * Called by synthfilt_build_sb_samples.
- *
- * @param sb subband index
- */
-void QDM2Stream::build_sb_samples_from_noise(int sb) {
- int ch, j;
-
- FIX_NOISE_IDX(_noiseIdx);
-
- if (!_channels)
- return;
-
- for (ch = 0; ch < _channels; ch++) {
- for (j = 0; j < 64; j++) {
- _sbSamples[ch][j * 2][sb] = (int32)(SB_DITHERING_NOISE(sb, _noiseIdx) * _toneLevel[ch][sb][j] + .5);
- _sbSamples[ch][j * 2 + 1][sb] = (int32)(SB_DITHERING_NOISE(sb, _noiseIdx) * _toneLevel[ch][sb][j] + .5);
- }
- }
-}
-
-/**
- * Called while processing data from subpackets 11 and 12.
- * Used after making changes to coding_method array.
- *
- * @param sb subband index
- * @param channels number of channels
- * @param coding_method q->coding_method[0][0][0]
- */
-void QDM2Stream::fix_coding_method_array(int sb, int channels, sb_int8_array coding_method)
-{
- int j, k;
- int ch;
- int run, case_val;
- int switchtable[23] = {0,5,1,5,5,5,5,5,2,5,5,5,5,5,5,5,3,5,5,5,5,5,4};
-
- for (ch = 0; ch < channels; ch++) {
- for (j = 0; j < 64; ) {
- if((coding_method[ch][sb][j] - 8) > 22) {
- run = 1;
- case_val = 8;
- } else {
- switch (switchtable[coding_method[ch][sb][j]-8]) {
- case 0: run = 10; case_val = 10; break;
- case 1: run = 1; case_val = 16; break;
- case 2: run = 5; case_val = 24; break;
- case 3: run = 3; case_val = 30; break;
- case 4: run = 1; case_val = 30; break;
- case 5: run = 1; case_val = 8; break;
- default: run = 1; case_val = 8; break;
- }
- }
- for (k = 0; k < run; k++)
- if (j + k < 128)
- if (coding_method[ch][sb + (j + k) / 64][(j + k) % 64] > coding_method[ch][sb][j])
- if (k > 0) {
- warning("QDM2 Untested Code: not debugged, almost never used");
- memset(&coding_method[ch][sb][j + k], case_val, k * sizeof(int8));
- memset(&coding_method[ch][sb][j + k], case_val, 3 * sizeof(int8));
- }
- j += run;
- }
- }
-}
-
-/**
- * Related to synthesis filter
- * Called by process_subpacket_10
- *
- * @param flag 1 if called after getting data from subpacket 10, 0 if no subpacket 10
- */
-void QDM2Stream::fill_tone_level_array(int flag) {
- int i, sb, ch, sb_used;
- int tmp, tab;
-
- // This should never happen
- if (_channels <= 0)
- return;
-
- for (ch = 0; ch < _channels; ch++) {
- for (sb = 0; sb < 30; sb++) {
- for (i = 0; i < 8; i++) {
- if ((tab=coeff_per_sb_for_dequant[_coeffPerSbSelect][sb]) < (last_coeff[_coeffPerSbSelect] - 1))
- tmp = _quantizedCoeffs[ch][tab + 1][i] * dequant_table[_coeffPerSbSelect][tab + 1][sb]+
- _quantizedCoeffs[ch][tab][i] * dequant_table[_coeffPerSbSelect][tab][sb];
- else
- tmp = _quantizedCoeffs[ch][tab][i] * dequant_table[_coeffPerSbSelect][tab][sb];
- if(tmp < 0)
- tmp += 0xff;
- _toneLevelIdxBase[ch][sb][i] = (tmp / 256) & 0xff;
- }
- }
- }
-
- sb_used = QDM2_SB_USED(_subSampling);
-
- if ((_superblocktype_2_3 != 0) && !flag) {
- for (sb = 0; sb < sb_used; sb++) {
- for (ch = 0; ch < _channels; ch++) {
- for (i = 0; i < 64; i++) {
- _toneLevelIdx[ch][sb][i] = _toneLevelIdxBase[ch][sb][i / 8];
- if (_toneLevelIdx[ch][sb][i] < 0)
- _toneLevel[ch][sb][i] = 0;
- else
- _toneLevel[ch][sb][i] = fft_tone_level_table[0][_toneLevelIdx[ch][sb][i] & 0x3f];
- }
- }
- }
- } else {
- tab = _superblocktype_2_3 ? 0 : 1;
- for (sb = 0; sb < sb_used; sb++) {
- if ((sb >= 4) && (sb <= 23)) {
- for (ch = 0; ch < _channels; ch++) {
- for (i = 0; i < 64; i++) {
- tmp = _toneLevelIdxBase[ch][sb][i / 8] -
- _toneLevelIdxHi1[ch][sb / 8][i / 8][i % 8] -
- _toneLevelIdxMid[ch][sb - 4][i / 8] -
- _toneLevelIdxHi2[ch][sb - 4];
- _toneLevelIdx[ch][sb][i] = tmp & 0xff;
- if ((tmp < 0) || (!_superblocktype_2_3 && !tmp))
- _toneLevel[ch][sb][i] = 0;
- else
- _toneLevel[ch][sb][i] = fft_tone_level_table[tab][tmp & 0x3f];
- }
- }
- } else {
- if (sb > 4) {
- for (ch = 0; ch < _channels; ch++) {
- for (i = 0; i < 64; i++) {
- tmp = _toneLevelIdxBase[ch][sb][i / 8] -
- _toneLevelIdxHi1[ch][2][i / 8][i % 8] -
- _toneLevelIdxHi2[ch][sb - 4];
- _toneLevelIdx[ch][sb][i] = tmp & 0xff;
- if ((tmp < 0) || (!_superblocktype_2_3 && !tmp))
- _toneLevel[ch][sb][i] = 0;
- else
- _toneLevel[ch][sb][i] = fft_tone_level_table[tab][tmp & 0x3f];
- }
- }
- } else {
- for (ch = 0; ch < _channels; ch++) {
- for (i = 0; i < 64; i++) {
- tmp = _toneLevelIdx[ch][sb][i] = _toneLevelIdxBase[ch][sb][i / 8];
- if ((tmp < 0) || (!_superblocktype_2_3 && !tmp))
- _toneLevel[ch][sb][i] = 0;
- else
- _toneLevel[ch][sb][i] = fft_tone_level_table[tab][tmp & 0x3f];
- }
- }
- }
- }
- }
- }
-}
-
-/**
- * Related to synthesis filter
- * Called by process_subpacket_11
- * c is built with data from subpacket 11
- * Most of this function is used only if superblock_type_2_3 == 0, never seen it in samples
- *
- * @param tone_level_idx
- * @param tone_level_idx_temp
- * @param coding_method q->coding_method[0][0][0]
- * @param nb_channels number of channels
- * @param c coming from subpacket 11, passed as 8*c
- * @param superblocktype_2_3 flag based on superblock packet type
- * @param cm_table_select q->cm_table_select
- */
-void QDM2Stream::fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_array tone_level_idx_temp,
- sb_int8_array coding_method, int nb_channels,
- int c, int superblocktype_2_3, int cm_table_select) {
- int ch, sb, j;
- int tmp, acc, esp_40, comp;
- int add1, add2, add3, add4;
- // TODO : Remove multres 64 bit variable necessity...
- int64_t multres;
-
- // This should never happen
- if (nb_channels <= 0)
- return;
- if (!superblocktype_2_3) {
- warning("QDM2 This case is untested, no samples available");
- for (ch = 0; ch < nb_channels; ch++)
- for (sb = 0; sb < 30; sb++) {
- for (j = 1; j < 63; j++) { // The loop only iterates to 63 so the code doesn't overflow the buffer
- add1 = tone_level_idx[ch][sb][j] - 10;
- if (add1 < 0)
- add1 = 0;
- add2 = add3 = add4 = 0;
- if (sb > 1) {
- add2 = tone_level_idx[ch][sb - 2][j] + tone_level_idx_offset_table[sb][0] - 6;
- if (add2 < 0)
- add2 = 0;
- }
- if (sb > 0) {
- add3 = tone_level_idx[ch][sb - 1][j] + tone_level_idx_offset_table[sb][1] - 6;
- if (add3 < 0)
- add3 = 0;
- }
- if (sb < 29) {
- add4 = tone_level_idx[ch][sb + 1][j] + tone_level_idx_offset_table[sb][3] - 6;
- if (add4 < 0)
- add4 = 0;
- }
- tmp = tone_level_idx[ch][sb][j + 1] * 2 - add4 - add3 - add2 - add1;
- if (tmp < 0)
- tmp = 0;
- tone_level_idx_temp[ch][sb][j + 1] = tmp & 0xff;
- }
- tone_level_idx_temp[ch][sb][0] = tone_level_idx_temp[ch][sb][1];
- }
- acc = 0;
- for (ch = 0; ch < nb_channels; ch++)
- for (sb = 0; sb < 30; sb++)
- for (j = 0; j < 64; j++)
- acc += tone_level_idx_temp[ch][sb][j];
-
- multres = 0x66666667 * (acc * 10);
- esp_40 = (multres >> 32) / 8 + ((multres & 0xffffffff) >> 31);
- for (ch = 0; ch < nb_channels; ch++)
- for (sb = 0; sb < 30; sb++)
- for (j = 0; j < 64; j++) {
- comp = tone_level_idx_temp[ch][sb][j]* esp_40 * 10;
- if (comp < 0)
- comp += 0xff;
- comp /= 256; // signed shift
- switch(sb) {
- case 0:
- if (comp < 30)
- comp = 30;
- comp += 15;
- break;
- case 1:
- if (comp < 24)
- comp = 24;
- comp += 10;
- break;
- case 2:
- case 3:
- case 4:
- if (comp < 16)
- comp = 16;
- }
- if (comp <= 5)
- tmp = 0;
- else if (comp <= 10)
- tmp = 10;
- else if (comp <= 16)
- tmp = 16;
- else if (comp <= 24)
- tmp = -1;
- else
- tmp = 0;
- coding_method[ch][sb][j] = ((tmp & 0xfffa) + 30 )& 0xff;
- }
- for (sb = 0; sb < 30; sb++)
- fix_coding_method_array(sb, nb_channels, coding_method);
- for (ch = 0; ch < nb_channels; ch++)
- for (sb = 0; sb < 30; sb++)
- for (j = 0; j < 64; j++)
- if (sb >= 10) {
- if (coding_method[ch][sb][j] < 10)
- coding_method[ch][sb][j] = 10;
- } else {
- if (sb >= 2) {
- if (coding_method[ch][sb][j] < 16)
- coding_method[ch][sb][j] = 16;
- } else {
- if (coding_method[ch][sb][j] < 30)
- coding_method[ch][sb][j] = 30;
- }
- }
- } else { // superblocktype_2_3 != 0
- for (ch = 0; ch < nb_channels; ch++)
- for (sb = 0; sb < 30; sb++)
- for (j = 0; j < 64; j++)
- coding_method[ch][sb][j] = coding_method_table[cm_table_select][sb];
- }
-}
-
-/**
- *
- * Called by process_subpacket_11 to process more data from subpacket 11 with sb 0-8
- * Called by process_subpacket_12 to process data from subpacket 12 with sb 8-sb_used
- *
- * @param gb bitreader context
- * @param length packet length in bits
- * @param sb_min lower subband processed (sb_min included)
- * @param sb_max higher subband processed (sb_max excluded)
- */
-void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int sb_min, int sb_max) {
- int sb, j, k, n, ch, run, channels;
- int joined_stereo, zero_encoding, chs;
- int type34_first;
- float type34_div = 0;
- float type34_predictor;
- float samples[10], sign_bits[16];
-
- if (length == 0) {
- // If no data use noise
- for (sb = sb_min; sb < sb_max; sb++)
- build_sb_samples_from_noise(sb);
-
- return;
- }
-
- for (sb = sb_min; sb < sb_max; sb++) {
- FIX_NOISE_IDX(_noiseIdx);
-
- channels = _channels;
-
- if (_channels <= 1 || sb < 12)
- joined_stereo = 0;
- else if (sb >= 24)
- joined_stereo = 1;
- else
- joined_stereo = (BITS_LEFT(length,gb) >= 1) ? getBits1 (gb) : 0;
-
- if (joined_stereo) {
- if (BITS_LEFT(length,gb) >= 16)
- for (j = 0; j < 16; j++)
- sign_bits[j] = getBits1(gb);
-
- for (j = 0; j < 64; j++)
- if (_codingMethod[1][sb][j] > _codingMethod[0][sb][j])
- _codingMethod[0][sb][j] = _codingMethod[1][sb][j];
-
- fix_coding_method_array(sb, _channels, _codingMethod);
- channels = 1;
- }
-
- for (ch = 0; ch < channels; ch++) {
- zero_encoding = (BITS_LEFT(length,gb) >= 1) ? getBits1(gb) : 0;
- type34_predictor = 0.0;
- type34_first = 1;
-
- for (j = 0; j < 128; ) {
- switch (_codingMethod[ch][sb][j / 2]) {
- case 8:
- if (BITS_LEFT(length,gb) >= 10) {
- if (zero_encoding) {
- for (k = 0; k < 5; k++) {
- if ((j + 2 * k) >= 128)
- break;
- samples[2 * k] = getBits1(gb) ? dequant_1bit[joined_stereo][2 * getBits1(gb)] : 0;
- }
- } else {
- n = getBits(gb, 8);
- for (k = 0; k < 5; k++)
- samples[2 * k] = dequant_1bit[joined_stereo][_randomDequantIndex[n][k]];
- }
- for (k = 0; k < 5; k++)
- samples[2 * k + 1] = SB_DITHERING_NOISE(sb, _noiseIdx);
- } else {
- for (k = 0; k < 10; k++)
- samples[k] = SB_DITHERING_NOISE(sb, _noiseIdx);
- }
- run = 10;
- break;
-
- case 10:
- if (BITS_LEFT(length,gb) >= 1) {
- double f = 0.81;
-
- if (getBits1(gb))
- f = -f;
- f -= _noiseSamples[((sb + 1) * (j +5 * ch + 1)) & 127] * 9.0 / 40.0;
- samples[0] = f;
- } else {
- samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
- }
- run = 1;
- break;
-
- case 16:
- if (BITS_LEFT(length,gb) >= 10) {
- if (zero_encoding) {
- for (k = 0; k < 5; k++) {
- if ((j + k) >= 128)
- break;
- samples[k] = (getBits1(gb) == 0) ? 0 : dequant_1bit[joined_stereo][2 * getBits1(gb)];
- }
- } else {
- n = getBits (gb, 8);
- for (k = 0; k < 5; k++)
- samples[k] = dequant_1bit[joined_stereo][_randomDequantIndex[n][k]];
- }
- } else {
- for (k = 0; k < 5; k++)
- samples[k] = SB_DITHERING_NOISE(sb, _noiseIdx);
- }
- run = 5;
- break;
-
- case 24:
- if (BITS_LEFT(length,gb) >= 7) {
- n = getBits(gb, 7);
- for (k = 0; k < 3; k++)
- samples[k] = (_randomDequantType24[n][k] - 2.0) * 0.5;
- } else {
- for (k = 0; k < 3; k++)
- samples[k] = SB_DITHERING_NOISE(sb, _noiseIdx);
- }
- run = 3;
- break;
-
- case 30:
- if (BITS_LEFT(length,gb) >= 4)
- samples[0] = type30_dequant[qdm2_get_vlc(gb, &_vlcTabType30, 0, 1)];
- else
- samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
-
- run = 1;
- break;
-
- case 34:
- if (BITS_LEFT(length,gb) >= 7) {
- if (type34_first) {
- type34_div = (float)(1 << getBits(gb, 2));
- samples[0] = ((float)getBits(gb, 5) - 16.0) / 15.0;
- type34_predictor = samples[0];
- type34_first = 0;
- } else {
- samples[0] = type34_delta[qdm2_get_vlc(gb, &_vlcTabType34, 0, 1)] / type34_div + type34_predictor;
- type34_predictor = samples[0];
- }
- } else {
- samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
- }
- run = 1;
- break;
-
- default:
- samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
- run = 1;
- break;
- }
-
- if (joined_stereo) {
- float tmp[10][MPA_MAX_CHANNELS];
-
- for (k = 0; k < run; k++) {
- tmp[k][0] = samples[k];
- tmp[k][1] = (sign_bits[(j + k) / 8]) ? -samples[k] : samples[k];
- }
- for (chs = 0; chs < _channels; chs++)
- for (k = 0; k < run; k++)
- if ((j + k) < 128)
- _sbSamples[chs][j + k][sb] = (int32)(_toneLevel[chs][sb][((j + k)/2)] * tmp[k][chs] + .5);
- } else {
- for (k = 0; k < run; k++)
- if ((j + k) < 128)
- _sbSamples[ch][j + k][sb] = (int32)(_toneLevel[ch][sb][(j + k)/2] * samples[k] + .5);
- }
-
- j += run;
- } // j loop
- } // channel loop
- } // subband loop
-}
-
-/**
- * Init the first element of a channel in quantized_coeffs with data from packet 10 (quantized_coeffs[ch][0]).
- * This is similar to process_subpacket_9, but for a single channel and for element [0]
- * same VLC tables as process_subpacket_9 are used.
- *
- * @param quantized_coeffs pointer to quantized_coeffs[ch][0]
- * @param gb bitreader context
- * @param length packet length in bits
- */
-void QDM2Stream::init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitContext *gb, int length) {
- int i, k, run, level, diff;
-
- if (BITS_LEFT(length,gb) < 16)
- return;
- level = qdm2_get_vlc(gb, &_vlcTabLevel, 0, 2);
-
- quantized_coeffs[0] = level;
-
- for (i = 0; i < 7; ) {
- if (BITS_LEFT(length,gb) < 16)
- break;
- run = qdm2_get_vlc(gb, &_vlcTabRun, 0, 1) + 1;
-
- if (BITS_LEFT(length,gb) < 16)
- break;
- diff = qdm2_get_se_vlc(&_vlcTabDiff, gb, 2);
-
- for (k = 1; k <= run; k++)
- quantized_coeffs[i + k] = (level + ((k * diff) / run));
-
- level += diff;
- i += run;
- }
-}
-
-/**
- * Related to synthesis filter, process data from packet 10
- * Init part of quantized_coeffs via function init_quantized_coeffs_elem0
- * Init tone_level_idx_hi1, tone_level_idx_hi2, tone_level_idx_mid with data from packet 10
- *
- * @param gb bitreader context
- * @param length packet length in bits
- */
-void QDM2Stream::init_tone_level_dequantization(GetBitContext *gb, int length) {
- int sb, j, k, n, ch;
-
- for (ch = 0; ch < _channels; ch++) {
- init_quantized_coeffs_elem0(_quantizedCoeffs[ch][0], gb, length);
-
- if (BITS_LEFT(length,gb) < 16) {
- memset(_quantizedCoeffs[ch][0], 0, 8);
- break;
- }
- }
-
- n = _subSampling + 1;
-
- for (sb = 0; sb < n; sb++)
- for (ch = 0; ch < _channels; ch++)
- for (j = 0; j < 8; j++) {
- if (BITS_LEFT(length,gb) < 1)
- break;
- if (getBits1(gb)) {
- for (k=0; k < 8; k++) {
- if (BITS_LEFT(length,gb) < 16)
- break;
- _toneLevelIdxHi1[ch][sb][j][k] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxHi1, 0, 2);
- }
- } else {
- for (k=0; k < 8; k++)
- _toneLevelIdxHi1[ch][sb][j][k] = 0;
- }
- }
-
- n = QDM2_SB_USED(_subSampling) - 4;
-
- for (sb = 0; sb < n; sb++)
- for (ch = 0; ch < _channels; ch++) {
- if (BITS_LEFT(length,gb) < 16)
- break;
- _toneLevelIdxHi2[ch][sb] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxHi2, 0, 2);
- if (sb > 19)
- _toneLevelIdxHi2[ch][sb] -= 16;
- else
- for (j = 0; j < 8; j++)
- _toneLevelIdxMid[ch][sb][j] = -16;
- }
-
- n = QDM2_SB_USED(_subSampling) - 5;
-
- for (sb = 0; sb < n; sb++) {
- for (ch = 0; ch < _channels; ch++) {
- for (j = 0; j < 8; j++) {
- if (BITS_LEFT(length,gb) < 16)
- break;
- _toneLevelIdxMid[ch][sb][j] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxMid, 0, 2) - 32;
- }
- }
- }
-}
-
-/**
- * Process subpacket 9, init quantized_coeffs with data from it
- *
- * @param node pointer to node with packet
- */
-void QDM2Stream::process_subpacket_9(QDM2SubPNode *node) {
- GetBitContext gb;
- int i, j, k, n, ch, run, level, diff;
-
- initGetBits(&gb, node->packet->data, node->packet->size*8);
-
- n = coeff_per_sb_for_avg[_coeffPerSbSelect][QDM2_SB_USED(_subSampling) - 1] + 1; // same as averagesomething function
-
- for (i = 1; i < n; i++)
- for (ch = 0; ch < _channels; ch++) {
- level = qdm2_get_vlc(&gb, &_vlcTabLevel, 0, 2);
- _quantizedCoeffs[ch][i][0] = level;
-
- for (j = 0; j < (8 - 1); ) {
- run = qdm2_get_vlc(&gb, &_vlcTabRun, 0, 1) + 1;
- diff = qdm2_get_se_vlc(&_vlcTabDiff, &gb, 2);
-
- for (k = 1; k <= run; k++)
- _quantizedCoeffs[ch][i][j + k] = (level + ((k*diff) / run));
-
- level += diff;
- j += run;
- }
- }
-
- for (ch = 0; ch < _channels; ch++)
- for (i = 0; i < 8; i++)
- _quantizedCoeffs[ch][0][i] = 0;
-}
-
-/**
- * Process subpacket 10 if not null, else
- *
- * @param node pointer to node with packet
- * @param length packet length in bits
- */
-void QDM2Stream::process_subpacket_10(QDM2SubPNode *node, int length) {
- GetBitContext gb;
-
- initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
-
- if (length != 0) {
- init_tone_level_dequantization(&gb, length);
- fill_tone_level_array(1);
- } else {
- fill_tone_level_array(0);
- }
-}
-
-/**
- * Process subpacket 11
- *
- * @param node pointer to node with packet
- * @param length packet length in bit
- */
-void QDM2Stream::process_subpacket_11(QDM2SubPNode *node, int length) {
- GetBitContext gb;
-
- initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
- if (length >= 32) {
- int c = getBits (&gb, 13);
-
- if (c > 3)
- fill_coding_method_array(_toneLevelIdx, _toneLevelIdxTemp, _codingMethod,
- _channels, 8*c, _superblocktype_2_3, _cmTableSelect);
- }
-
- synthfilt_build_sb_samples(&gb, length, 0, 8);
-}
-
-/**
- * Process subpacket 12
- *
- * @param node pointer to node with packet
- * @param length packet length in bits
- */
-void QDM2Stream::process_subpacket_12(QDM2SubPNode *node, int length) {
- GetBitContext gb;
-
- initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
- synthfilt_build_sb_samples(&gb, length, 8, QDM2_SB_USED(_subSampling));
-}
-
-/*
- * Process new subpackets for synthesis filter
- *
- * @param list list with synthesis filter packets (list D)
- */
-void QDM2Stream::process_synthesis_subpackets(QDM2SubPNode *list) {
- struct QDM2SubPNode *nodes[4];
-
- nodes[0] = qdm2_search_subpacket_type_in_list(list, 9);
- if (nodes[0] != NULL)
- process_subpacket_9(nodes[0]);
-
- nodes[1] = qdm2_search_subpacket_type_in_list(list, 10);
- if (nodes[1] != NULL)
- process_subpacket_10(nodes[1], nodes[1]->packet->size << 3);
- else
- process_subpacket_10(NULL, 0);
-
- nodes[2] = qdm2_search_subpacket_type_in_list(list, 11);
- if (nodes[0] != NULL && nodes[1] != NULL && nodes[2] != NULL)
- process_subpacket_11(nodes[2], (nodes[2]->packet->size << 3));
- else
- process_subpacket_11(NULL, 0);
-
- nodes[3] = qdm2_search_subpacket_type_in_list(list, 12);
- if (nodes[0] != NULL && nodes[1] != NULL && nodes[3] != NULL)
- process_subpacket_12(nodes[3], (nodes[3]->packet->size << 3));
- else
- process_subpacket_12(NULL, 0);
-}
-
-/*
- * Decode superblock, fill packet lists.
- *
- */
-void QDM2Stream::qdm2_decode_super_block(void) {
- GetBitContext gb;
- struct QDM2SubPacket header, *packet;
- int i, packet_bytes, sub_packet_size, subPacketsD;
- unsigned int next_index = 0;
-
- memset(_toneLevelIdxHi1, 0, sizeof(_toneLevelIdxHi1));
- memset(_toneLevelIdxMid, 0, sizeof(_toneLevelIdxMid));
- memset(_toneLevelIdxHi2, 0, sizeof(_toneLevelIdxHi2));
-
- _subPacketsB = 0;
- subPacketsD = 0;
-
- average_quantized_coeffs(); // average elements in quantized_coeffs[max_ch][10][8]
-
- initGetBits(&gb, _compressedData, _packetSize*8);
- qdm2_decode_sub_packet_header(&gb, &header);
-
- if (header.type < 2 || header.type >= 8) {
- _hasErrors = true;
- error("QDM2 : bad superblock type");
- return;
- }
-
- _superblocktype_2_3 = (header.type == 2 || header.type == 3);
- packet_bytes = (_packetSize - getBitsCount(&gb) / 8);
-
- initGetBits(&gb, header.data, header.size*8);
-
- if (header.type == 2 || header.type == 4 || header.type == 5) {
- int csum = 257 * getBits(&gb, 8) + 2 * getBits(&gb, 8);
-
- csum = qdm2_packet_checksum(_compressedData, _packetSize, csum);
-
- if (csum != 0) {
- _hasErrors = true;
- error("QDM2 : bad packet checksum");
- return;
- }
- }
-
- _subPacketListB[0].packet = NULL;
- _subPacketListD[0].packet = NULL;
-
- for (i = 0; i < 6; i++)
- if (--_fftLevelExp[i] < 0)
- _fftLevelExp[i] = 0;
-
- for (i = 0; packet_bytes > 0; i++) {
- int j;
-
- _subPacketListA[i].next = NULL;
-
- if (i > 0) {
- _subPacketListA[i - 1].next = &_subPacketListA[i];
-
- // seek to next block
- initGetBits(&gb, header.data, header.size*8);
- skipBits(&gb, next_index*8);
-
- if (next_index >= header.size)
- break;
- }
-
- // decode subpacket
- packet = &_subPackets[i];
- qdm2_decode_sub_packet_header(&gb, packet);
- next_index = packet->size + getBitsCount(&gb) / 8;
- sub_packet_size = ((packet->size > 0xff) ? 1 : 0) + packet->size + 2;
-
- if (packet->type == 0)
- break;
-
- if (sub_packet_size > packet_bytes) {
- if (packet->type != 10 && packet->type != 11 && packet->type != 12)
- break;
- packet->size += packet_bytes - sub_packet_size;
- }
-
- packet_bytes -= sub_packet_size;
-
- // add subpacket to 'all subpackets' list
- _subPacketListA[i].packet = packet;
-
- // add subpacket to related list
- if (packet->type == 8) {
- error("Unsupported packet type 8");
- return;
- } else if (packet->type >= 9 && packet->type <= 12) {
- // packets for MPEG Audio like Synthesis Filter
- QDM2_LIST_ADD(_subPacketListD, subPacketsD, packet);
- } else if (packet->type == 13) {
- for (j = 0; j < 6; j++)
- _fftLevelExp[j] = getBits(&gb, 6);
- } else if (packet->type == 14) {
- for (j = 0; j < 6; j++)
- _fftLevelExp[j] = qdm2_get_vlc(&gb, &_fftLevelExpVlc, 0, 2);
- } else if (packet->type == 15) {
- error("Unsupported packet type 15");
- return;
- } else if (packet->type >= 16 && packet->type < 48 && !fft_subpackets[packet->type - 16]) {
- // packets for FFT
- QDM2_LIST_ADD(_subPacketListB, _subPacketsB, packet);
- }
- } // Packet bytes loop
-
-// ****************************************************************
- if (_subPacketListD[0].packet != NULL) {
- process_synthesis_subpackets(_subPacketListD);
- _doSynthFilter = 1;
- } else if (_doSynthFilter) {
- process_subpacket_10(NULL, 0);
- process_subpacket_11(NULL, 0);
- process_subpacket_12(NULL, 0);
- }
-// ****************************************************************
-}
-
-void QDM2Stream::qdm2_fft_init_coefficient(int sub_packet, int offset, int duration,
- int channel, int exp, int phase) {
- if (_fftCoefsMinIndex[duration] < 0)
- _fftCoefsMinIndex[duration] = _fftCoefsIndex;
-
- _fftCoefs[_fftCoefsIndex].sub_packet = ((sub_packet >= 16) ? (sub_packet - 16) : sub_packet);
- _fftCoefs[_fftCoefsIndex].channel = channel;
- _fftCoefs[_fftCoefsIndex].offset = offset;
- _fftCoefs[_fftCoefsIndex].exp = exp;
- _fftCoefs[_fftCoefsIndex].phase = phase;
- _fftCoefsIndex++;
-}
-
-void QDM2Stream::qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b) {
- debug(1, "QDM2Stream::qdm2_fft_decode_tones() duration: %d b:%d", duration, b);
- int channel, stereo, phase, exp;
- int local_int_4, local_int_8, stereo_phase, local_int_10;
- int local_int_14, stereo_exp, local_int_20, local_int_28;
- int n, offset;
-
- local_int_4 = 0;
- local_int_28 = 0;
- local_int_20 = 2;
- local_int_8 = (4 - duration);
- local_int_10 = 1 << (_groupOrder - duration - 1);
- offset = 1;
-
- while (1) {
- if (_superblocktype_2_3) {
- debug(1, "QDM2Stream::qdm2_fft_decode_tones() local_int_8: %d", local_int_8);
- while ((n = qdm2_get_vlc(gb, &_vlcTabFftToneOffset[local_int_8], 1, 2)) < 2) {
- debug(1, "QDM2Stream::qdm2_fft_decode_tones() local_int_8: %d", local_int_8);
- offset = 1;
- if (n == 0) {
- local_int_4 += local_int_10;
- local_int_28 += (1 << local_int_8);
- } else {
- local_int_4 += 8*local_int_10;
- local_int_28 += (8 << local_int_8);
- }
- }
- offset += (n - 2);
- } else {
- offset += qdm2_get_vlc(gb, &_vlcTabFftToneOffset[local_int_8], 1, 2);
- while (offset >= (local_int_10 - 1)) {
- offset += (1 - (local_int_10 - 1));
- local_int_4 += local_int_10;
- local_int_28 += (1 << local_int_8);
- }
- }
-
- if (local_int_4 >= _blockSize)
- return;
-
- local_int_14 = (offset >> local_int_8);
-
- if (_channels > 1) {
- channel = getBits1(gb);
- stereo = getBits1(gb);
- } else {
- channel = 0;
- stereo = 0;
- }
-
- exp = qdm2_get_vlc(gb, (b ? &_fftLevelExpVlc : &_fftLevelExpAltVlc), 0, 2);
- exp += _fftLevelExp[fft_level_index_table[local_int_14]];
- exp = (exp < 0) ? 0 : exp;
-
- phase = getBits(gb, 3);
- stereo_exp = 0;
- stereo_phase = 0;
-
- if (stereo) {
- stereo_exp = (exp - qdm2_get_vlc(gb, &_fftStereoExpVlc, 0, 1));
- stereo_phase = (phase - qdm2_get_vlc(gb, &_fftStereoPhaseVlc, 0, 1));
- if (stereo_phase < 0)
- stereo_phase += 8;
- }
-
- if (_frequencyRange > (local_int_14 + 1)) {
- int sub_packet = (local_int_20 + local_int_28);
-
- qdm2_fft_init_coefficient(sub_packet, offset, duration, channel, exp, phase);
- if (stereo)
- qdm2_fft_init_coefficient(sub_packet, offset, duration, (1 - channel), stereo_exp, stereo_phase);
- }
-
- offset++;
- }
-}
-
-void QDM2Stream::qdm2_decode_fft_packets(void) {
- debug(1, "QDM2Stream::qdm2_decode_fft_packets()");
- int i, j, min, max, value, type, unknown_flag;
- GetBitContext gb;
-
- if (_subPacketListB[0].packet == NULL)
- return;
-
- // reset minimum indexes for FFT coefficients
- _fftCoefsIndex = 0;
- for (i=0; i < 5; i++)
- _fftCoefsMinIndex[i] = -1;
-
- // process subpackets ordered by type, largest type first
- for (i = 0, max = 256; i < _subPacketsB; i++) {
- QDM2SubPacket *packet= NULL;
-
- // find subpacket with largest type less than max
- for (j = 0, min = 0; j < _subPacketsB; j++) {
- value = _subPacketListB[j].packet->type;
- if (value > min && value < max) {
- min = value;
- packet = _subPacketListB[j].packet;
- }
- }
-
- max = min;
-
- // check for errors (?)
- if (!packet)
- return;
-
- if (i == 0 && (packet->type < 16 || packet->type >= 48 || fft_subpackets[packet->type - 16]))
- return;
-
- // decode FFT tones
- debug(1, "QDM2Stream::qdm2_decode_fft_packets initGetBits() packet->size*8: %d", packet->size*8);
- initGetBits(&gb, packet->data, packet->size*8);
-
- if (packet->type >= 32 && packet->type < 48 && !fft_subpackets[packet->type - 16])
- unknown_flag = 1;
- else
- unknown_flag = 0;
-
- type = packet->type;
-
- if ((type >= 17 && type < 24) || (type >= 33 && type < 40)) {
- int duration = _subSampling + 5 - (type & 15);
-
- if (duration >= 0 && duration < 4) { // TODO: Should be <= 4?
- debug(1, "QDM2Stream::qdm2_decode_fft_packets qdm2_fft_decode_tones() #1");
- qdm2_fft_decode_tones(duration, &gb, unknown_flag);
- }
- } else if (type == 31) {
- for (j=0; j < 4; j++) {
- debug(1, "QDM2Stream::qdm2_decode_fft_packets qdm2_fft_decode_tones() #2");
- qdm2_fft_decode_tones(j, &gb, unknown_flag);
- }
- } else if (type == 46) {
- for (j=0; j < 6; j++)
- _fftLevelExp[j] = getBits(&gb, 6);
- for (j=0; j < 4; j++) {
- debug(1, "QDM2Stream::qdm2_decode_fft_packets qdm2_fft_decode_tones() #3");
- qdm2_fft_decode_tones(j, &gb, unknown_flag);
- }
- }
- } // Loop on B packets
-
- // calculate maximum indexes for FFT coefficients
- for (i = 0, j = -1; i < 5; i++)
- if (_fftCoefsMinIndex[i] >= 0) {
- if (j >= 0)
- _fftCoefsMaxIndex[j] = _fftCoefsMinIndex[i];
- j = i;
- }
- if (j >= 0)
- _fftCoefsMaxIndex[j] = _fftCoefsIndex;
-}
-
-void QDM2Stream::qdm2_fft_generate_tone(FFTTone *tone)
-{
- float level, f[6];
- int i;
- QDM2Complex c;
- const double iscale = 2.0 * PI / 512.0;
-
- tone->phase += tone->phase_shift;
-
- // calculate current level (maximum amplitude) of tone
- level = fft_tone_envelope_table[tone->duration][tone->time_index] * tone->level;
- c.im = level * sin(tone->phase*iscale);
- c.re = level * cos(tone->phase*iscale);
-
- // generate FFT coefficients for tone
- if (tone->duration >= 3 || tone->cutoff >= 3) {
- tone->complex[0].im += c.im;
- tone->complex[0].re += c.re;
- tone->complex[1].im -= c.im;
- tone->complex[1].re -= c.re;
- } else {
- f[1] = -tone->table[4];
- f[0] = tone->table[3] - tone->table[0];
- f[2] = 1.0 - tone->table[2] - tone->table[3];
- f[3] = tone->table[1] + tone->table[4] - 1.0;
- f[4] = tone->table[0] - tone->table[1];
- f[5] = tone->table[2];
- for (i = 0; i < 2; i++) {
- tone->complex[fft_cutoff_index_table[tone->cutoff][i]].re += c.re * f[i];
- tone->complex[fft_cutoff_index_table[tone->cutoff][i]].im += c.im *((tone->cutoff <= i) ? -f[i] : f[i]);
- }
- for (i = 0; i < 4; i++) {
- tone->complex[i].re += c.re * f[i+2];
- tone->complex[i].im += c.im * f[i+2];
- }
- }
-
- // copy the tone if it has not yet died out
- if (++tone->time_index < ((1 << (5 - tone->duration)) - 1)) {
- memcpy(&_fftTones[_fftToneEnd], tone, sizeof(FFTTone));
- _fftToneEnd = (_fftToneEnd + 1) % 1000;
- }
-}
-
-void QDM2Stream::qdm2_fft_tone_synthesizer(uint8 sub_packet) {
- int i, j, ch;
- const double iscale = 0.25 * PI;
-
- for (ch = 0; ch < _channels; ch++) {
- memset(_fft.complex[ch], 0, _frameSize * sizeof(QDM2Complex));
- }
-
- // apply FFT tones with duration 4 (1 FFT period)
- if (_fftCoefsMinIndex[4] >= 0)
- for (i = _fftCoefsMinIndex[4]; i < _fftCoefsMaxIndex[4]; i++) {
- float level;
- QDM2Complex c;
-
- if (_fftCoefs[i].sub_packet != sub_packet)
- break;
-
- ch = (_channels == 1) ? 0 : _fftCoefs[i].channel;
- level = (_fftCoefs[i].exp < 0) ? 0.0 : fft_tone_level_table[_superblocktype_2_3 ? 0 : 1][_fftCoefs[i].exp & 63];
-
- c.re = level * cos(_fftCoefs[i].phase * iscale);
- c.im = level * sin(_fftCoefs[i].phase * iscale);
- _fft.complex[ch][_fftCoefs[i].offset + 0].re += c.re;
- _fft.complex[ch][_fftCoefs[i].offset + 0].im += c.im;
- _fft.complex[ch][_fftCoefs[i].offset + 1].re -= c.re;
- _fft.complex[ch][_fftCoefs[i].offset + 1].im -= c.im;
- }
-
- // generate existing FFT tones
- for (i = _fftToneEnd; i != _fftToneStart; ) {
- qdm2_fft_generate_tone(&_fftTones[_fftToneStart]);
- _fftToneStart = (_fftToneStart + 1) % 1000;
- }
-
- // create and generate new FFT tones with duration 0 (long) to 3 (short)
- for (i = 0; i < 4; i++)
- if (_fftCoefsMinIndex[i] >= 0) {
- for (j = _fftCoefsMinIndex[i]; j < _fftCoefsMaxIndex[i]; j++) {
- int offset, four_i;
- FFTTone tone;
-
- if (_fftCoefs[j].sub_packet != sub_packet)
- break;
-
- four_i = (4 - i);
- offset = _fftCoefs[j].offset >> four_i;
- ch = (_channels == 1) ? 0 : _fftCoefs[j].channel;
-
- if (offset < _frequencyRange) {
- if (offset < 2)
- tone.cutoff = offset;
- else
- tone.cutoff = (offset >= 60) ? 3 : 2;
-
- tone.level = (_fftCoefs[j].exp < 0) ? 0.0 : fft_tone_level_table[_superblocktype_2_3 ? 0 : 1][_fftCoefs[j].exp & 63];
- tone.complex = &_fft.complex[ch][offset];
- tone.table = fft_tone_sample_table[i][_fftCoefs[j].offset - (offset << four_i)];
- tone.phase = 64 * _fftCoefs[j].phase - (offset << 8) - 128;
- tone.phase_shift = (2 * _fftCoefs[j].offset + 1) << (7 - four_i);
- tone.duration = i;
- tone.time_index = 0;
-
- qdm2_fft_generate_tone(&tone);
- }
- }
- _fftCoefsMinIndex[i] = j;
- }
-}
-
-void QDM2Stream::qdm2_calculate_fft(int channel) {
- debug(1, "QDM2Stream::qdm2_calculate_fft channel: %d", channel);
- const float gain = (_channels == 1 && _channels == 2) ? 0.5f : 1.0f;
- int i;
-
- _fft.complex[channel][0].re *= 2.0f;
- _fft.complex[channel][0].im = 0.0f;
-
- //debug(1, "QDM2Stream::qdm2_calculate_fft _fft.complex[channel][0].re: %lf", _fft.complex[channel][0].re);
- //debug(1, "QDM2Stream::qdm2_calculate_fft _fft.complex[channel][0].im: %lf", _fft.complex[channel][0].im);
-
- rdftCalc(&_rdftCtx, (float *)_fft.complex[channel]);
-
- // add samples to output buffer
- for (i = 0; i < ((_fftFrameSize + 15) & ~15); i++)
- _outputBuffer[_channels * i + channel] += ((float *) _fft.complex[channel])[i] * gain;
-}
-
-/**
- * @param index subpacket number
- */
-void QDM2Stream::qdm2_synthesis_filter(uint8 index)
-{
- int16 samples[MPA_MAX_CHANNELS * MPA_FRAME_SIZE];
- int i, k, ch, sb_used, sub_sampling, dither_state = 0;
-
- // copy sb_samples
- sb_used = QDM2_SB_USED(_subSampling);
-
- for (ch = 0; ch < _channels; ch++)
- for (i = 0; i < 8; i++)
- for (k = sb_used; k < 32; k++)
- _sbSamples[ch][(8 * index) + i][k] = 0;
-
- for (ch = 0; ch < _channels; ch++) {
- int16 *samples_ptr = samples + ch;
-
- for (i = 0; i < 8; i++) {
- ff_mpa_synth_filter(_synthBuf[ch], &(_synthBufOffset[ch]),
- ff_mpa_synth_window, &dither_state,
- samples_ptr, _channels,
- _sbSamples[ch][(8 * index) + i]);
- samples_ptr += 32 * _channels;
- }
- }
-
- // add samples to output buffer
- sub_sampling = (4 >> _subSampling);
-
- for (ch = 0; ch < _channels; ch++)
- for (i = 0; i < _sFrameSize; i++)
- _outputBuffer[_channels * i + ch] += (float)(samples[_channels * sub_sampling * i + ch] >> (sizeof(int16)*8-16));
-}
-
-int QDM2Stream::qdm2_decodeFrame(Common::SeekableReadStream *in) {
- debug(1, "QDM2Stream::qdm2_decodeFrame in->pos(): %d in->size(): %d", in->pos(), in->size());
- int ch, i;
- const int frame_size = (_sFrameSize * _channels);
-
- // select input buffer
- if(in->eos() || in->size() == in->pos()) {
- debug(1, "QDM2Stream::qdm2_decodeFrame End of Input Stream");
- return 0;
- }
- if((in->size() - in->pos()) < _packetSize) {
- debug(1, "QDM2Stream::qdm2_decodeFrame Insufficient Packet Data in Input Stream Found: %d Need: %d", in->size() - in->pos(), _packetSize);
- return 0;
- }
-
- in->read(_compressedData, _packetSize);
- debug(1, "QDM2Stream::qdm2_decodeFrame constructed input data");
-
- // copy old block, clear new block of output samples
- memmove(_outputBuffer, &_outputBuffer[frame_size], frame_size * sizeof(float));
- memset(&_outputBuffer[frame_size], 0, frame_size * sizeof(float));
- debug(1, "QDM2Stream::qdm2_decodeFrame cleared outputBuffer");
-
- // decode block of QDM2 compressed data
- debug(1, "QDM2Stream::qdm2_decodeFrame decode block of QDM2 compressed data");
- if (_subPacket == 0) {
- _hasErrors = false; // reset it for a new super block
- debug(1, "QDM2 : Superblock follows");
- qdm2_decode_super_block();
- }
-
- // parse subpackets
- debug(1, "QDM2Stream::qdm2_decodeFrame parse subpackets");
- if (!_hasErrors) {
- if (_subPacket == 2) {
- debug(1, "QDM2Stream::qdm2_decodeFrame qdm2_decode_fft_packets()");
- qdm2_decode_fft_packets();
- }
-
- debug(1, "QDM2Stream::qdm2_decodeFrame qdm2_fft_tone_synthesizer(%d)", _subPacket);
- qdm2_fft_tone_synthesizer(_subPacket);
- }
-
- // sound synthesis stage 1 (FFT)
- debug(1, "QDM2Stream::qdm2_decodeFrame sound synthesis stage 1 (FFT)");
- for (ch = 0; ch < _channels; ch++) {
- qdm2_calculate_fft(ch);
-
- if (!_hasErrors && _subPacketListC[0].packet != NULL) {
- error("QDM2 : has errors, and C list is not empty");
- return 0;
- }
- }
-
- // sound synthesis stage 2 (MPEG audio like synthesis filter)
- debug(1, "QDM2Stream::qdm2_decodeFrame sound synthesis stage 2 (MPEG audio like synthesis filter)");
- if (!_hasErrors && _doSynthFilter)
- qdm2_synthesis_filter(_subPacket);
-
- _subPacket = (_subPacket + 1) % 16;
-
- if(_hasErrors)
- warning("QDM2 Packet error...");
-
- // clip and convert output float[] to 16bit signed samples
- debug(1, "QDM2Stream::qdm2_decodeFrame clip and convert output float[] to 16bit signed samples");
-
-/*
- debugN(1, "Input Data Packet:");
- for(i = 0; i < _packetSize; i++) {
- debugN(1, " %d", _compressedData[i]);
- }
- debugN(1, " Output Data Packet:");
- for(i = 0; i < frame_size; i++) {
- debugN(1, " %d", (int)_outputBuffer[i]);
- }
- debug(1, "");
-*/
-
- for (i = 0; i < frame_size; i++) {
- //debug(1, "QDM2Stream::qdm2_decodeFrame i: %d", i);
- int value = (int)_outputBuffer[i];
-
- if (value > SOFTCLIP_THRESHOLD)
- value = (value > HARDCLIP_THRESHOLD) ? 32767 : _softclipTable[ value - SOFTCLIP_THRESHOLD];
- else if (value < -SOFTCLIP_THRESHOLD)
- value = (value < -HARDCLIP_THRESHOLD) ? -32767 : -_softclipTable[-value - SOFTCLIP_THRESHOLD];
-
- _outputSamples.push_back(value);
- }
- return frame_size;
-}
-
-int QDM2Stream::readBuffer(int16 *buffer, const int numSamples) {
- debug(1, "QDM2Stream::readBuffer numSamples: %d", numSamples);
- int32 decodedSamples = _outputSamples.size();
- int32 i;
-
- //while((int)_outputSamples.size() < numSamples) {
- while(!_stream->eos() && _stream->pos() != _stream->size()) {
- i = qdm2_decodeFrame(_stream);
- if(i == 0)
- break; // Out Of Decode Frames...
- decodedSamples += i;
- }
- if(decodedSamples > numSamples)
- decodedSamples = numSamples;
-
- for(i = 0; i < decodedSamples; i++)
- buffer[i] = _outputSamples.remove_at(0);
-
- return decodedSamples;
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/qdm2.h b/engines/mohawk/video/qdm2.h
deleted file mode 100644
index ffa5f77030..0000000000
--- a/engines/mohawk/video/qdm2.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_VIDEO_QDM2_H
-#define MOHAWK_VIDEO_QDM2_H
-
-#include "sound/audiostream.h"
-#include "common/array.h"
-#include "common/stream.h"
-
-namespace Mohawk {
-
-enum {
- SOFTCLIP_THRESHOLD = 27600,
- HARDCLIP_THRESHOLD = 35716,
- MPA_MAX_CHANNELS = 2,
- MPA_FRAME_SIZE = 1152,
- FF_INPUT_BUFFER_PADDING_SIZE = 8
-};
-
-typedef int8 sb_int8_array[2][30][64];
-
-/* bit input */
-/* buffer, buffer_end and size_in_bits must be present and used by every reader */
-struct GetBitContext {
- const uint8 *buffer, *bufferEnd;
- int index;
- int sizeInBits;
-};
-
-struct QDM2SubPacket {
- int type;
- unsigned int size;
- const uint8 *data; // pointer to subpacket data (points to input data buffer, it's not a private copy)
-};
-
-struct QDM2SubPNode {
- QDM2SubPacket *packet;
- struct QDM2SubPNode *next; // pointer to next packet in the list, NULL if leaf node
-};
-
-struct QDM2Complex {
- float re;
- float im;
-};
-
-struct FFTTone {
- float level;
- QDM2Complex *complex;
- const float *table;
- int phase;
- int phase_shift;
- int duration;
- short time_index;
- short cutoff;
-};
-
-struct FFTCoefficient {
- int16 sub_packet;
- uint8 channel;
- int16 offset;
- int16 exp;
- uint8 phase;
-};
-
-struct VLC {
- int32 bits;
- int16 (*table)[2]; // code, bits
- int32 table_size;
- int32 table_allocated;
-};
-
-#include "common/pack-start.h"
-struct QDM2FFT {
- QDM2Complex complex[MPA_MAX_CHANNELS][256];
-} PACKED_STRUCT;
-#include "common/pack-end.h"
-
-enum RDFTransformType {
- RDFT,
- IRDFT,
- RIDFT,
- IRIDFT
-};
-
-struct FFTComplex {
- float re, im;
-};
-
-struct FFTContext {
- int nbits;
- int inverse;
- uint16 *revtab;
- FFTComplex *exptab;
- FFTComplex *tmpBuf;
- int mdctSize; // size of MDCT (i.e. number of input data * 2)
- int mdctBits; // n = 2^nbits
- // pre/post rotation tables
- float *tcos;
- float *tsin;
- void (*fftPermute)(struct FFTContext *s, FFTComplex *z);
- void (*fftCalc)(struct FFTContext *s, FFTComplex *z);
- void (*imdctCalc)(struct FFTContext *s, float *output, const float *input);
- void (*imdctHalf)(struct FFTContext *s, float *output, const float *input);
- void (*mdctCalc)(struct FFTContext *s, float *output, const float *input);
- int splitRadix;
- int permutation;
-};
-
-enum {
- FF_MDCT_PERM_NONE = 0,
- FF_MDCT_PERM_INTERLEAVE = 1
-};
-
-struct RDFTContext {
- int nbits;
- int inverse;
- int signConvention;
-
- // pre/post rotation tables
- float *tcos;
- float *tsin;
- FFTContext fft;
-};
-
-class QDM2Stream : public Audio::AudioStream {
-public:
- QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData);
- ~QDM2Stream();
-
- bool isStereo() const { return _channels == 2; }
- bool endOfData() const { return ((_stream->pos() == _stream->size()) && (_outputSamples.size() == 0)); }
- int getRate() const { return _sampleRate; }
- int readBuffer(int16 *buffer, const int numSamples);
-
-private:
- Common::SeekableReadStream *_stream;
-
- // Parameters from codec header, do not change during playback
- uint8 _channels;
- uint16 _sampleRate;
- uint16 _bitRate;
- uint16 _blockSize; // Group
- uint16 _frameSize; // FFT
- uint16 _packetSize; // Checksum
-
- // Parameters built from header parameters, do not change during playback
- int _groupOrder; // order of frame group
- int _fftOrder; // order of FFT (actually fft order+1)
- int _fftFrameSize; // size of fft frame, in components (1 comples = re + im)
- int _sFrameSize; // size of data frame
- int _frequencyRange;
- int _subSampling; // subsampling: 0=25%, 1=50%, 2=100% */
- int _coeffPerSbSelect; // selector for "num. of coeffs. per subband" tables. Can be 0, 1, 2
- int _cmTableSelect; // selector for "coding method" tables. Can be 0, 1 (from init: 0-4)
-
- // Packets and packet lists
- QDM2SubPacket _subPackets[16]; // the packets themselves
- QDM2SubPNode _subPacketListA[16]; // list of all packets
- QDM2SubPNode _subPacketListB[16]; // FFT packets B are on list
- int _subPacketsB; // number of packets on 'B' list
- QDM2SubPNode _subPacketListC[16]; // packets with errors?
- QDM2SubPNode _subPacketListD[16]; // DCT packets
-
- // FFT and tones
- FFTTone _fftTones[1000];
- int _fftToneStart;
- int _fftToneEnd;
- FFTCoefficient _fftCoefs[1000];
- int _fftCoefsIndex;
- int _fftCoefsMinIndex[5];
- int _fftCoefsMaxIndex[5];
- int _fftLevelExp[6];
- //RDFTContext _rdftCtx;
- QDM2FFT _fft;
-
- // I/O data
- uint8 *_compressedData;
- float _outputBuffer[1024];
- Common::Array<int16> _outputSamples;
-
- // Synthesis filter
- int16 ff_mpa_synth_window[512];
- int16 _synthBuf[MPA_MAX_CHANNELS][512*2];
- int _synthBufOffset[MPA_MAX_CHANNELS];
- int32 _sbSamples[MPA_MAX_CHANNELS][128][32];
-
- // Mixed temporary data used in decoding
- float _toneLevel[MPA_MAX_CHANNELS][30][64];
- int8 _codingMethod[MPA_MAX_CHANNELS][30][64];
- int8 _quantizedCoeffs[MPA_MAX_CHANNELS][10][8];
- int8 _toneLevelIdxBase[MPA_MAX_CHANNELS][30][8];
- int8 _toneLevelIdxHi1[MPA_MAX_CHANNELS][3][8][8];
- int8 _toneLevelIdxMid[MPA_MAX_CHANNELS][26][8];
- int8 _toneLevelIdxHi2[MPA_MAX_CHANNELS][26];
- int8 _toneLevelIdx[MPA_MAX_CHANNELS][30][64];
- int8 _toneLevelIdxTemp[MPA_MAX_CHANNELS][30][64];
-
- // Flags
- bool _hasErrors; // packet has errors
- int _superblocktype_2_3; // select fft tables and some algorithm based on superblock type
- int _doSynthFilter; // used to perform or skip synthesis filter
-
- uint8 _subPacket; // 0 to 15
- int _noiseIdx; // index for dithering noise table
-
- byte _emptyBuffer[FF_INPUT_BUFFER_PADDING_SIZE];
-
- VLC _vlcTabLevel;
- VLC _vlcTabDiff;
- VLC _vlcTabRun;
- VLC _fftLevelExpAltVlc;
- VLC _fftLevelExpVlc;
- VLC _fftStereoExpVlc;
- VLC _fftStereoPhaseVlc;
- VLC _vlcTabToneLevelIdxHi1;
- VLC _vlcTabToneLevelIdxMid;
- VLC _vlcTabToneLevelIdxHi2;
- VLC _vlcTabType30;
- VLC _vlcTabType34;
- VLC _vlcTabFftToneOffset[5];
- bool _vlcsInitialized;
- void initVlc(void);
-
- uint16 _softclipTable[HARDCLIP_THRESHOLD - SOFTCLIP_THRESHOLD + 1];
- void softclipTableInit(void);
-
- float _noiseTable[4096];
- byte _randomDequantIndex[256][5];
- byte _randomDequantType24[128][3];
- void rndTableInit(void);
-
- float _noiseSamples[128];
- void initNoiseSamples(void);
-
- RDFTContext _rdftCtx;
-
- void average_quantized_coeffs(void);
- void build_sb_samples_from_noise(int sb);
- void fix_coding_method_array(int sb, int channels, sb_int8_array coding_method);
- void fill_tone_level_array(int flag);
- void fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_array tone_level_idx_temp,
- sb_int8_array coding_method, int nb_channels,
- int c, int superblocktype_2_3, int cm_table_select);
- void synthfilt_build_sb_samples(GetBitContext *gb, int length, int sb_min, int sb_max);
- void init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitContext *gb, int length);
- void init_tone_level_dequantization(GetBitContext *gb, int length);
- void process_subpacket_9(QDM2SubPNode *node);
- void process_subpacket_10(QDM2SubPNode *node, int length);
- void process_subpacket_11(QDM2SubPNode *node, int length);
- void process_subpacket_12(QDM2SubPNode *node, int length);
- void process_synthesis_subpackets(QDM2SubPNode *list);
- void qdm2_decode_super_block(void);
- void qdm2_fft_init_coefficient(int sub_packet, int offset, int duration,
- int channel, int exp, int phase);
- void qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b);
- void qdm2_decode_fft_packets(void);
- void qdm2_fft_generate_tone(FFTTone *tone);
- void qdm2_fft_tone_synthesizer(uint8 sub_packet);
- void qdm2_calculate_fft(int channel);
- void qdm2_synthesis_filter(uint8 index);
- int qdm2_decodeFrame(Common::SeekableReadStream *in);
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/video/qdm2data.h b/engines/mohawk/video/qdm2data.h
deleted file mode 100644
index f1c18db41c..0000000000
--- a/engines/mohawk/video/qdm2data.h
+++ /dev/null
@@ -1,531 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_VIDEO_QDM2DATA_H
-#define MOHAWK_VIDEO_QDM2DATA_H
-
-#include "common/scummsys.h"
-
-namespace Mohawk {
-
-/// VLC TABLES
-
-// values in this table range from -1..23; adjust retrieved value by -1
-static const uint16 vlc_tab_level_huffcodes[24] = {
- 0x037c, 0x0004, 0x003c, 0x004c, 0x003a, 0x002c, 0x001c, 0x001a,
- 0x0024, 0x0014, 0x0001, 0x0002, 0x0000, 0x0003, 0x0007, 0x0005,
- 0x0006, 0x0008, 0x0009, 0x000a, 0x000c, 0x00fc, 0x007c, 0x017c
-};
-
-static const byte vlc_tab_level_huffbits[24] = {
- 10, 6, 7, 7, 6, 6, 6, 6, 6, 5, 4, 4, 4, 3, 3, 3, 3, 4, 4, 5, 7, 8, 9, 10
-};
-
-// values in this table range from -1..36; adjust retrieved value by -1
-static const uint16 vlc_tab_diff_huffcodes[37] = {
- 0x1c57, 0x0004, 0x0000, 0x0001, 0x0003, 0x0002, 0x000f, 0x000e,
- 0x0007, 0x0016, 0x0037, 0x0027, 0x0026, 0x0066, 0x0006, 0x0097,
- 0x0046, 0x01c6, 0x0017, 0x0786, 0x0086, 0x0257, 0x00d7, 0x0357,
- 0x00c6, 0x0386, 0x0186, 0x0000, 0x0157, 0x0c57, 0x0057, 0x0000,
- 0x0b86, 0x0000, 0x1457, 0x0000, 0x0457
-};
-
-static const byte vlc_tab_diff_huffbits[37] = {
- 13, 3, 3, 2, 3, 3, 4, 4, 6, 5, 6, 6, 7, 7, 8, 8,
- 8, 9, 8, 11, 9, 10, 8, 10, 9, 12, 10, 0, 10, 13, 11, 0,
- 12, 0, 13, 0, 13
-};
-
-// values in this table range from -1..5; adjust retrieved value by -1
-static const byte vlc_tab_run_huffcodes[6] = {
- 0x1f, 0x00, 0x01, 0x03, 0x07, 0x0f
-};
-
-static const byte vlc_tab_run_huffbits[6] = {
- 5, 1, 2, 3, 4, 5
-};
-
-// values in this table range from -1..19; adjust retrieved value by -1
-static const uint16 vlc_tab_tone_level_idx_hi1_huffcodes[20] = {
- 0x5714, 0x000c, 0x0002, 0x0001, 0x0000, 0x0004, 0x0034, 0x0054,
- 0x0094, 0x0014, 0x0114, 0x0214, 0x0314, 0x0614, 0x0e14, 0x0f14,
- 0x2714, 0x0714, 0x1714, 0x3714
-};
-
-static const byte vlc_tab_tone_level_idx_hi1_huffbits[20] = {
- 15, 4, 2, 1, 3, 5, 6, 7, 8, 10, 10, 11, 11, 12, 12, 12, 14, 14, 15, 14
-};
-
-// values in this table range from -1..23; adjust retrieved value by -1
-static const uint16 vlc_tab_tone_level_idx_mid_huffcodes[24] = {
- 0x0fea, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x03ea, 0x00ea, 0x002a, 0x001a,
- 0x0006, 0x0001, 0x0000, 0x0002, 0x000a, 0x006a, 0x01ea, 0x07ea
-};
-
-static const byte vlc_tab_tone_level_idx_mid_huffbits[24] = {
- 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 7, 5, 3, 1, 2, 4, 6, 8, 10, 12
-};
-
-// values in this table range from -1..23; adjust retrieved value by -1
-static const uint16 vlc_tab_tone_level_idx_hi2_huffcodes[24] = {
- 0x0664, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0064, 0x00e4,
- 0x00a4, 0x0068, 0x0004, 0x0008, 0x0014, 0x0018, 0x0000, 0x0001,
- 0x0002, 0x0003, 0x000c, 0x0028, 0x0024, 0x0164, 0x0000, 0x0264
-};
-
-static const byte vlc_tab_tone_level_idx_hi2_huffbits[24] = {
- 11, 0, 0, 0, 0, 0, 10, 8, 8, 7, 6, 6, 5, 5, 4, 2, 2, 2, 4, 7, 8, 9, 0, 11
-};
-
-// values in this table range from -1..8; adjust retrieved value by -1
-static const byte vlc_tab_type30_huffcodes[9] = {
- 0x3c, 0x06, 0x00, 0x01, 0x03, 0x02, 0x04, 0x0c, 0x1c
-};
-
-static const byte vlc_tab_type30_huffbits[9] = {
- 6, 3, 3, 2, 2, 3, 4, 5, 6
-};
-
-// values in this table range from -1..9; adjust retrieved value by -1
-static const byte vlc_tab_type34_huffcodes[10] = {
- 0x18, 0x00, 0x01, 0x04, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08
-};
-
-static const byte vlc_tab_type34_huffbits[10] = {
- 5, 4, 3, 3, 3, 3, 3, 3, 3, 5
-};
-
-// values in this table range from -1..22; adjust retrieved value by -1
-static const uint16 vlc_tab_fft_tone_offset_0_huffcodes[23] = {
- 0x038e, 0x0001, 0x0000, 0x0022, 0x000a, 0x0006, 0x0012, 0x0002,
- 0x001e, 0x003e, 0x0056, 0x0016, 0x000e, 0x0032, 0x0072, 0x0042,
- 0x008e, 0x004e, 0x00f2, 0x002e, 0x0036, 0x00c2, 0x018e
-};
-
-static const byte vlc_tab_fft_tone_offset_0_huffbits[23] = {
- 10, 1, 2, 6, 4, 5, 6, 7, 6, 6, 7, 7, 8, 7, 8, 8, 9, 7, 8, 6, 6, 8, 10
-};
-
-// values in this table range from -1..27; adjust retrieved value by -1
-static const uint16 vlc_tab_fft_tone_offset_1_huffcodes[28] = {
- 0x07a4, 0x0001, 0x0020, 0x0012, 0x001c, 0x0008, 0x0006, 0x0010,
- 0x0000, 0x0014, 0x0004, 0x0032, 0x0070, 0x000c, 0x0002, 0x003a,
- 0x001a, 0x002c, 0x002a, 0x0022, 0x0024, 0x000a, 0x0064, 0x0030,
- 0x0062, 0x00a4, 0x01a4, 0x03a4
-};
-
-static const byte vlc_tab_fft_tone_offset_1_huffbits[28] = {
- 11, 1, 6, 6, 5, 4, 3, 6, 6, 5, 6, 6, 7, 6, 6, 6,
- 6, 6, 6, 7, 8, 6, 7, 7, 7, 9, 10, 11
-};
-
-// values in this table range from -1..31; adjust retrieved value by -1
-static const uint16 vlc_tab_fft_tone_offset_2_huffcodes[32] = {
- 0x1760, 0x0001, 0x0000, 0x0082, 0x000c, 0x0006, 0x0003, 0x0007,
- 0x0008, 0x0004, 0x0010, 0x0012, 0x0022, 0x001a, 0x0000, 0x0020,
- 0x000a, 0x0040, 0x004a, 0x006a, 0x002a, 0x0042, 0x0002, 0x0060,
- 0x00aa, 0x00e0, 0x00c2, 0x01c2, 0x0160, 0x0360, 0x0760, 0x0f60
-};
-
-static const byte vlc_tab_fft_tone_offset_2_huffbits[32] = {
- 13, 2, 0, 8, 4, 3, 3, 3, 4, 4, 5, 5, 6, 5, 7, 7,
- 7, 7, 7, 7, 8, 8, 8, 9, 8, 8, 9, 9, 10, 11, 13, 12
-};
-
-// values in this table range from -1..34; adjust retrieved value by -1
-static const uint16 vlc_tab_fft_tone_offset_3_huffcodes[35] = {
- 0x33ea, 0x0005, 0x0000, 0x000c, 0x0000, 0x0006, 0x0003, 0x0008,
- 0x0002, 0x0001, 0x0004, 0x0007, 0x001a, 0x000f, 0x001c, 0x002c,
- 0x000a, 0x001d, 0x002d, 0x002a, 0x000d, 0x004c, 0x008c, 0x006a,
- 0x00cd, 0x004d, 0x00ea, 0x020c, 0x030c, 0x010c, 0x01ea, 0x07ea,
- 0x0bea, 0x03ea, 0x13ea
-};
-
-static const byte vlc_tab_fft_tone_offset_3_huffbits[35] = {
- 14, 4, 0, 10, 4, 3, 3, 4, 4, 3, 4, 4, 5, 4, 5, 6,
- 6, 5, 6, 7, 7, 7, 8, 8, 8, 8, 9, 10, 10, 10, 10, 11,
- 12, 13, 14
-};
-
-// values in this table range from -1..37; adjust retrieved value by -1
-static const uint16 vlc_tab_fft_tone_offset_4_huffcodes[38] = {
- 0x5282, 0x0016, 0x0000, 0x0136, 0x0004, 0x0000, 0x0007, 0x000a,
- 0x000e, 0x0003, 0x0001, 0x000d, 0x0006, 0x0009, 0x0012, 0x0005,
- 0x0025, 0x0022, 0x0015, 0x0002, 0x0076, 0x0035, 0x0042, 0x00c2,
- 0x0182, 0x00b6, 0x0036, 0x03c2, 0x0482, 0x01c2, 0x0682, 0x0882,
- 0x0a82, 0x0082, 0x0282, 0x1282, 0x3282, 0x2282
-};
-
-static const byte vlc_tab_fft_tone_offset_4_huffbits[38] = {
- 15, 6, 0, 9, 3, 3, 3, 4, 4, 3, 4, 4, 5, 4, 5, 6,
- 6, 6, 6, 8, 7, 6, 8, 9, 9, 8, 9, 10, 11, 10, 11, 12,
- 12, 12, 14, 15, 14, 14
-};
-
-/// FFT TABLES
-
-// values in this table range from -1..27; adjust retrieved value by -1
-static const uint16 fft_level_exp_alt_huffcodes[28] = {
- 0x1ec6, 0x0006, 0x00c2, 0x0142, 0x0242, 0x0246, 0x00c6, 0x0046,
- 0x0042, 0x0146, 0x00a2, 0x0062, 0x0026, 0x0016, 0x000e, 0x0005,
- 0x0004, 0x0003, 0x0000, 0x0001, 0x000a, 0x0012, 0x0002, 0x0022,
- 0x01c6, 0x02c6, 0x06c6, 0x0ec6
-};
-
-static const byte fft_level_exp_alt_huffbits[28] = {
- 13, 7, 8, 9, 10, 10, 10, 10, 10, 9, 8, 7, 6, 5, 4, 3,
- 3, 2, 3, 3, 4, 5, 7, 8, 9, 11, 12, 13
-};
-
-// values in this table range from -1..19; adjust retrieved value by -1
-static const uint16 fft_level_exp_huffcodes[20] = {
- 0x0f24, 0x0001, 0x0002, 0x0000, 0x0006, 0x0005, 0x0007, 0x000c,
- 0x000b, 0x0014, 0x0013, 0x0004, 0x0003, 0x0023, 0x0064, 0x00a4,
- 0x0024, 0x0124, 0x0324, 0x0724
-};
-
-static const byte fft_level_exp_huffbits[20] = {
- 12, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 10, 11, 12
-};
-
-// values in this table range from -1..6; adjust retrieved value by -1
-static const byte fft_stereo_exp_huffcodes[7] = {
- 0x3e, 0x01, 0x00, 0x02, 0x06, 0x0e, 0x1e
-};
-
-static const byte fft_stereo_exp_huffbits[7] = {
- 6, 1, 2, 3, 4, 5, 6
-};
-
-// values in this table range from -1..8; adjust retrieved value by -1
-static const byte fft_stereo_phase_huffcodes[9] = {
- 0x35, 0x02, 0x00, 0x01, 0x0d, 0x15, 0x05, 0x09, 0x03
-};
-
-static const byte fft_stereo_phase_huffbits[9] = {
- 6, 2, 2, 4, 4, 6, 5, 4, 2
-};
-
-static const int fft_cutoff_index_table[4][2] = {
- { 1, 2 }, {-1, 0 }, {-1,-2 }, { 0, 0 }
-};
-
-static const int16 fft_level_index_table[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-};
-
-static const byte last_coeff[3] = {
- 4, 7, 10
-};
-
-static const byte coeff_per_sb_for_avg[3][30] = {
- { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
- { 0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 },
- { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9 }
-};
-
-static const uint32 dequant_table[3][10][30] = {
- { { 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 256, 256, 205, 154, 102, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 51, 102, 154, 205, 256, 238, 219, 201, 183, 165, 146, 128, 110, 91, 73, 55, 37, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 18, 37, 55, 73, 91, 110, 128, 146, 165, 183, 201, 219, 238, 256, 228, 199, 171, 142, 114, 85, 57, 28 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
- { { 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 85, 171, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 85, 171, 256, 219, 183, 146, 110, 73, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 73, 110, 146, 183, 219, 256, 228, 199, 171, 142, 114, 85, 57, 28, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 57, 85, 114, 142, 171, 199, 228, 256, 213, 171, 128, 85, 43 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
- { { 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 256, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 85, 171, 256, 192, 128, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 128, 192, 256, 205, 154, 102, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 102, 154, 205, 256, 213, 171, 128, 85, 43, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 85, 128, 171, 213, 256, 213, 171, 128, 85, 43 } }
-};
-
-static const byte coeff_per_sb_for_dequant[3][30] = {
- { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
- { 0, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6 },
- { 0, 1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9 }
-};
-
-// first index is subband, 2nd index is 0, 1 or 3 (2 is unused)
-static const int8 tone_level_idx_offset_table[30][4] = {
- { -50, -50, 0, -50 },
- { -50, -50, 0, -50 },
- { -50, -9, 0, -19 },
- { -16, -6, 0, -12 },
- { -11, -4, 0, -8 },
- { -8, -3, 0, -6 },
- { -7, -3, 0, -5 },
- { -6, -2, 0, -4 },
- { -5, -2, 0, -3 },
- { -4, -1, 0, -3 },
- { -4, -1, 0, -2 },
- { -3, -1, 0, -2 },
- { -3, -1, 0, -2 },
- { -3, -1, 0, -2 },
- { -2, -1, 0, -1 },
- { -2, -1, 0, -1 },
- { -2, -1, 0, -1 },
- { -2, 0, 0, -1 },
- { -2, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, 0 },
- { -1, 0, 0, 0 },
- { -1, 0, 0, 0 },
- { -1, 0, 0, 0 }
-};
-
-/* all my samples have 1st index 0 or 1 */
-/* second index is subband, only indexes 0-29 seem to be used */
-static const int8 coding_method_table[5][30] = {
- { 34, 30, 24, 24, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
- },
- { 34, 30, 24, 24, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
- },
- { 34, 30, 30, 30, 24, 24, 16, 16, 16, 16, 16, 16, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
- },
- { 34, 34, 30, 30, 24, 24, 24, 24, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10, 10
- },
- { 34, 34, 30, 30, 30, 30, 30, 30, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
- },
-};
-
-static const int vlc_stage3_values[60] = {
- 0, 1, 2, 3, 4, 6, 8, 10, 12, 16, 20, 24,
- 28, 36, 44, 52, 60, 76, 92, 108, 124, 156, 188, 220,
- 252, 316, 380, 444, 508, 636, 764, 892, 1020, 1276, 1532, 1788,
- 2044, 2556, 3068, 3580, 4092, 5116, 6140, 7164, 8188, 10236, 12284, 14332,
- 16380, 20476, 24572, 28668, 32764, 40956, 49148, 57340, 65532, 81916, 98300,114684
-};
-
-static const float fft_tone_sample_table[4][16][5] = {
- { { .0100000000f,-.0037037037f,-.0020000000f,-.0069444444f,-.0018416207f },
- { .0416666667f, .0000000000f, .0000000000f,-.0208333333f,-.0123456791f },
- { .1250000000f, .0558035709f, .0330687836f,-.0164473690f,-.0097465888f },
- { .1562500000f, .0625000000f, .0370370370f,-.0062500000f,-.0037037037f },
- { .1996007860f, .0781250000f, .0462962948f, .0022727272f, .0013468013f },
- { .2000000000f, .0625000000f, .0370370373f, .0208333333f, .0074074073f },
- { .2127659619f, .0555555556f, .0329218097f, .0208333333f, .0123456791f },
- { .2173913121f, .0473484844f, .0280583613f, .0347222239f, .0205761325f },
- { .2173913121f, .0347222239f, .0205761325f, .0473484844f, .0280583613f },
- { .2127659619f, .0208333333f, .0123456791f, .0555555556f, .0329218097f },
- { .2000000000f, .0208333333f, .0074074073f, .0625000000f, .0370370370f },
- { .1996007860f, .0022727272f, .0013468013f, .0781250000f, .0462962948f },
- { .1562500000f,-.0062500000f,-.0037037037f, .0625000000f, .0370370370f },
- { .1250000000f,-.0164473690f,-.0097465888f, .0558035709f, .0330687836f },
- { .0416666667f,-.0208333333f,-.0123456791f, .0000000000f, .0000000000f },
- { .0100000000f,-.0069444444f,-.0018416207f,-.0037037037f,-.0020000000f } },
-
- { { .0050000000f,-.0200000000f, .0125000000f,-.3030303030f, .0020000000f },
- { .1041666642f, .0400000000f,-.0250000000f, .0333333333f,-.0200000000f },
- { .1250000000f, .0100000000f, .0142857144f,-.0500000007f,-.0200000000f },
- { .1562500000f,-.0006250000f,-.00049382716f,-.000625000f,-.00049382716f },
- { .1562500000f,-.0006250000f,-.00049382716f,-.000625000f,-.00049382716f },
- { .1250000000f,-.0500000000f,-.0200000000f, .0100000000f, .0142857144f },
- { .1041666667f, .0333333333f,-.0200000000f, .0400000000f,-.0250000000f },
- { .0050000000f,-.3030303030f, .0020000001f,-.0200000000f, .0125000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f } },
-
- { { .1428571492f, .1250000000f,-.0285714287f,-.0357142873f, .0208333333f },
- { .1818181818f, .0588235296f, .0333333333f, .0212765951f, .0100000000f },
- { .1818181818f, .0212765951f, .0100000000f, .0588235296f, .0333333333f },
- { .1428571492f,-.0357142873f, .0208333333f, .1250000000f,-.0285714287f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f } },
-
- { { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f } }
-};
-
-static const float fft_tone_level_table[2][64] = { {
-// pow ~ (i > 46) ? 0 : (((((i & 1) ? 431 : 304) << (i >> 1))) / 1024.0);
- 0.17677669f, 0.42677650f, 0.60355347f, 0.85355347f,
- 1.20710683f, 1.68359375f, 2.37500000f, 3.36718750f,
- 4.75000000f, 6.73437500f, 9.50000000f, 13.4687500f,
- 19.0000000f, 26.9375000f, 38.0000000f, 53.8750000f,
- 76.0000000f, 107.750000f, 152.000000f, 215.500000f,
- 304.000000f, 431.000000f, 608.000000f, 862.000000f,
- 1216.00000f, 1724.00000f, 2432.00000f, 3448.00000f,
- 4864.00000f, 6896.00000f, 9728.00000f, 13792.0000f,
- 19456.0000f, 27584.0000f, 38912.0000f, 55168.0000f,
- 77824.0000f, 110336.000f, 155648.000f, 220672.000f,
- 311296.000f, 441344.000f, 622592.000f, 882688.000f,
- 1245184.00f, 1765376.00f, 2490368.00f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- }, {
-// pow = (i > 45) ? 0 : ((((i & 1) ? 431 : 304) << (i >> 1)) / 512.0);
- 0.59375000f, 0.84179688f, 1.18750000f, 1.68359375f,
- 2.37500000f, 3.36718750f, 4.75000000f, 6.73437500f,
- 9.50000000f, 13.4687500f, 19.0000000f, 26.9375000f,
- 38.0000000f, 53.8750000f, 76.0000000f, 107.750000f,
- 152.000000f, 215.500000f, 304.000000f, 431.000000f,
- 608.000000f, 862.000000f, 1216.00000f, 1724.00000f,
- 2432.00000f, 3448.00000f, 4864.00000f, 6896.00000f,
- 9728.00000f, 13792.0000f, 19456.0000f, 27584.0000f,
- 38912.0000f, 55168.0000f, 77824.0000f, 110336.000f,
- 155648.000f, 220672.000f, 311296.000f, 441344.000f,
- 622592.000f, 882688.000f, 1245184.00f, 1765376.00f,
- 2490368.00f, 3530752.00f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f
-} };
-
-static const float fft_tone_envelope_table[4][31] = {
- { .009607375f, .038060248f, .084265202f, .146446645f, .222214907f, .308658302f,
- .402454883f, .500000060f, .597545207f, .691341758f, .777785182f, .853553414f,
- .915734828f, .961939812f, .990392685f, 1.00000000f, .990392625f, .961939752f,
- .915734768f, .853553295f, .777785063f, .691341639f, .597545087f, .500000000f,
- .402454853f, .308658272f, .222214878f, .146446615f, .084265172f, .038060218f,
- .009607345f },
- { .038060248f, .146446645f, .308658302f, .500000060f, .691341758f, .853553414f,
- .961939812f, 1.00000000f, .961939752f, .853553295f, .691341639f, .500000000f,
- .308658272f, .146446615f, .038060218f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f },
- { .146446645f, .500000060f, .853553414f, 1.00000000f, .853553295f, .500000000f,
- .146446615f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f },
- { .500000060f, 1.00000000f, .500000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f }
-};
-
-static const float sb_noise_attenuation[32] = {
- 0.0f, 0.0f, 0.3f, 0.4f, 0.5f, 0.7f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-};
-
-static const byte fft_subpackets[32] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0
-};
-
-// first index is joined_stereo, second index is 0 or 2 (1 is unused)
-static const float dequant_1bit[2][3] = {
- {-0.920000f, 0.000000f, 0.920000f },
- {-0.890000f, 0.000000f, 0.890000f }
-};
-
-static const float type30_dequant[8] = {
- -1.0f,-0.625f,-0.291666656732559f,0.0f,
- 0.25f,0.5f,0.75f,1.0f,
-};
-
-static const float type34_delta[10] = { // FIXME: covers 8 entries..
- -1.0f,-0.60947573184967f,-0.333333343267441f,-0.138071194291115f,0.0f,
- 0.138071194291115f,0.333333343267441f,0.60947573184967f,1.0f,0.0f,
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/video/qt_player.cpp b/engines/mohawk/video/qt_player.cpp
deleted file mode 100644
index 0ed05bb84d..0000000000
--- a/engines/mohawk/video/qt_player.cpp
+++ /dev/null
@@ -1,1272 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-//
-// Heavily based on ffmpeg code.
-//
-// Copyright (c) 2001 Fabrice Bellard.
-// First version by Francois Revol revol@free.fr
-// Seek function by Gael Chardon gael.dev@4now.net
-//
-
-#include "mohawk/video/qt_player.h"
-
-#include "common/debug.h"
-#include "common/endian.h"
-#include "common/util.h"
-#include "common/zlib.h"
-
-// Audio codecs
-#include "sound/decoders/adpcm.h"
-#include "sound/decoders/raw.h"
-#include "mohawk/video/qdm2.h"
-
-// Video codecs
-#include "mohawk/jpeg.h"
-#include "mohawk/video/cinepak.h"
-#include "mohawk/video/qtrle.h"
-#include "mohawk/video/rpza.h"
-#include "mohawk/video/smc.h"
-
-namespace Mohawk {
-
-////////////////////////////////////////////
-// QTPlayer
-////////////////////////////////////////////
-
-QTPlayer::QTPlayer() : Graphics::VideoDecoder() {
- _audStream = NULL;
- _beginOffset = 0;
- _videoCodec = NULL;
- _curFrame = -1;
- _startTime = _nextFrameStartTime = 0;
- _audHandle = Audio::SoundHandle();
- _numStreams = 0;
- _fd = 0;
- _scaledSurface = 0;
- _dirtyPalette = false;
-}
-
-QTPlayer::~QTPlayer() {
- close();
-}
-
-uint16 QTPlayer::getWidth() const {
- if (_videoStreamIndex < 0)
- return 0;
-
- return _streams[_videoStreamIndex]->width / getScaleMode();
-}
-
-uint16 QTPlayer::getHeight() const {
- if (_videoStreamIndex < 0)
- return 0;
-
- return _streams[_videoStreamIndex]->height / getScaleMode();
-}
-
-uint32 QTPlayer::getFrameCount() const {
- if (_videoStreamIndex < 0)
- return 0;
-
- return _streams[_videoStreamIndex]->nb_frames;
-}
-
-byte QTPlayer::getBitsPerPixel() {
- if (_videoStreamIndex < 0)
- return 0;
-
- return _streams[_videoStreamIndex]->bits_per_sample & 0x1F;
-}
-
-uint32 QTPlayer::getCodecTag() {
- if (_videoStreamIndex < 0)
- return 0;
-
- return _streams[_videoStreamIndex]->codec_tag;
-}
-
-ScaleMode QTPlayer::getScaleMode() const {
- if (_videoStreamIndex < 0)
- return kScaleNormal;
-
- return (ScaleMode)(_scaleMode * _streams[_videoStreamIndex]->scaleMode);
-}
-
-uint32 QTPlayer::getFrameDuration() {
- if (_videoStreamIndex < 0)
- return 0;
-
- uint32 curFrameIndex = 0;
- for (int32 i = 0; i < _streams[_videoStreamIndex]->stts_count; i++) {
- curFrameIndex += _streams[_videoStreamIndex]->stts_data[i].count;
- if ((uint32)_curFrame < curFrameIndex) {
- // Ok, now we have what duration this frame has.
- return _streams[_videoStreamIndex]->stts_data[i].duration;
- }
- }
-
- // This should never occur
- error ("Cannot find duration for frame %d", _curFrame);
- return 0;
-}
-
-Graphics::PixelFormat QTPlayer::getPixelFormat() const {
- if (!_videoCodec)
- return Graphics::PixelFormat::createFormatCLUT8();
-
- return _videoCodec->getPixelFormat();
-}
-
-void QTPlayer::rewind() {
- delete _videoCodec; _videoCodec = NULL;
- _curFrame = -1;
- _startTime = _nextFrameStartTime = 0;
-
- // Restart the audio too
- stopAudio();
- if (_audioStreamIndex >= 0) {
- _curAudioChunk = 0;
- _audStream = Audio::makeQueuingAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels == 2);
- }
- startAudio();
-}
-
-Graphics::Codec *QTPlayer::createCodec(uint32 codecTag, byte bitsPerPixel) {
- if (codecTag == MKID_BE('cvid')) {
- // Cinepak: As used by most Myst and all Riven videos as well as some Myst ME videos. "The Chief" videos also use this.
- return new CinepakDecoder();
- } else if (codecTag == MKID_BE('rpza')) {
- // Apple Video ("Road Pizza"): Used by some Myst videos.
- return new RPZADecoder(getWidth(), getHeight());
- } else if (codecTag == MKID_BE('rle ')) {
- // QuickTime RLE: Used by some Myst ME videos.
- return new QTRLEDecoder(getWidth(), getHeight(), bitsPerPixel);
- } else if (codecTag == MKID_BE('smc ')) {
- // Apple SMC: Used by some Myst videos.
- return new SMCDecoder(getWidth(), getHeight());
- } else if (codecTag == MKID_BE('SVQ1')) {
- // Sorenson Video 1: Used by some Myst ME videos.
- warning ("Sorenson Video 1 not yet supported");
- } else if (codecTag == MKID_BE('SVQ3')) {
- // Sorenson Video 3: Used by some Myst ME videos.
- warning ("Sorenson Video 3 not yet supported");
- } else if (codecTag == MKID_BE('jpeg')) {
- // Motion JPEG: Used by some Myst ME 10th Anniversary videos.
- return new JPEGDecoder(true);
- } else if (codecTag == MKID_BE('QkBk')) {
- // CDToons: Used by most of the Broderbund games. This is an unknown format so far.
- warning ("CDToons not yet supported");
- } else {
- warning ("Unsupported codec \'%s\'", tag2str(codecTag));
- }
-
- return NULL;
-}
-
-void QTPlayer::startAudio() {
- if (_audStream) // No audio/audio not supported
- g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream);
-}
-
-void QTPlayer::stopAudio() {
- if (_audStream) {
- g_system->getMixer()->stopHandle(_audHandle);
- _audStream = NULL; // the mixer automatically frees the stream
- }
-}
-
-void QTPlayer::pauseVideoIntern(bool pause) {
- if (_audStream)
- g_system->getMixer()->pauseHandle(_audHandle, pause);
-}
-
-Graphics::Surface *QTPlayer::decodeNextFrame() {
- if (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1)
- return NULL;
-
- if (_startTime == 0)
- _startTime = g_system->getMillis();
-
- _curFrame++;
- _nextFrameStartTime += getFrameDuration();
-
- Common::SeekableReadStream *frameData = getNextFramePacket();
-
- if (frameData) {
- Graphics::Surface *frame = _videoCodec->decodeImage(frameData);
- delete frameData;
- return scaleSurface(frame);
- }
-
- return NULL;
-}
-
-Graphics::Surface *QTPlayer::scaleSurface(Graphics::Surface *frame) {
- if (getScaleMode() == kScaleNormal)
- return frame;
-
- assert(_scaledSurface);
-
- for (uint32 j = 0; j < _scaledSurface->h; j++)
- for (uint32 k = 0; k < _scaledSurface->w; k++)
- memcpy(_scaledSurface->getBasePtr(k, j), frame->getBasePtr(k * getScaleMode(), j * getScaleMode()), frame->bytesPerPixel);
-
- return _scaledSurface;
-}
-
-bool QTPlayer::endOfVideo() const {
- return (!_audStream || _audStream->endOfData()) && (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1);
-}
-
-bool QTPlayer::needsUpdate() const {
- return !endOfVideo() && getTimeToNextFrame() == 0;
-}
-
-uint32 QTPlayer::getElapsedTime() const {
- if (_audStream)
- return g_system->getMixer()->getSoundElapsedTime(_audHandle);
-
- return g_system->getMillis() - _startTime;
-}
-
-uint32 QTPlayer::getTimeToNextFrame() const {
- if (endOfVideo() || _curFrame < 0)
- return 0;
-
- // Convert from the Sega FILM base to 1000
- uint32 nextFrameStartTime = _nextFrameStartTime * 1000 / _streams[_videoStreamIndex]->time_scale;
- uint32 elapsedTime = getElapsedTime();
-
- if (nextFrameStartTime <= elapsedTime)
- return 0;
-
- return nextFrameStartTime - elapsedTime;
-}
-
-bool QTPlayer::load(Common::SeekableReadStream &stream) {
- _fd = &stream;
- _foundMOOV = _foundMDAT = false;
- _numStreams = 0;
- _partial = 0;
- _videoStreamIndex = _audioStreamIndex = -1;
- _startTime = 0;
-
- initParseTable();
-
- MOVatom atom = { 0, 0, 0xffffffff };
-
- if (readDefault(atom) < 0 || (!_foundMOOV && !_foundMDAT))
- return false;
-
- debug(0, "on_parse_exit_offset=%d", _fd->pos());
-
- // some cleanup : make sure we are on the mdat atom
- if((uint32)_fd->pos() != _mdatOffset)
- _fd->seek(_mdatOffset, SEEK_SET);
-
- _next_chunk_offset = _mdatOffset; // initialise reading
-
- for (uint32 i = 0; i < _numStreams;) {
- if (_streams[i]->codec_type == CODEC_TYPE_MOV_OTHER) {// not audio, not video, delete
- delete _streams[i];
- for (uint32 j = i + 1; j < _numStreams; j++)
- _streams[j - 1] = _streams[j];
- _numStreams--;
- } else
- i++;
- }
-
- for (uint32 i = 0; i < _numStreams; i++) {
- MOVStreamContext *sc = _streams[i];
-
- if(!sc->time_rate)
- sc->time_rate = 1;
-
- if(!sc->time_scale)
- sc->time_scale = _timeScale;
-
- //av_set_pts_info(s->streams[i], 64, sc->time_rate, sc->time_scale);
-
- sc->duration /= sc->time_rate;
-
- sc->ffindex = i;
- sc->is_ff_stream = 1;
-
- if (sc->codec_type == CODEC_TYPE_VIDEO && _videoStreamIndex < 0)
- _videoStreamIndex = i;
- else if (sc->codec_type == CODEC_TYPE_AUDIO && _audioStreamIndex < 0)
- _audioStreamIndex = i;
- }
-
- if (_audioStreamIndex >= 0 && checkAudioCodecSupport(_streams[_audioStreamIndex]->codec_tag)) {
- _audStream = Audio::makeQueuingAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels == 2);
- _curAudioChunk = 0;
-
- // Make sure the bits per sample transfers to the sample size
- if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('raw ') || _streams[_audioStreamIndex]->codec_tag == MKID_BE('twos'))
- _streams[_audioStreamIndex]->sample_size = (_streams[_audioStreamIndex]->bits_per_sample / 8) * _streams[_audioStreamIndex]->channels;
-
- startAudio();
- }
-
- if (_videoStreamIndex >= 0) {
- _videoCodec = createCodec(getCodecTag(), getBitsPerPixel());
-
- if (getScaleMode() != kScaleNormal) {
- // We have to initialize the scaled surface
- _scaledSurface = new Graphics::Surface();
- _scaledSurface->create(getWidth(), getHeight(), getPixelFormat().bytesPerPixel);
- }
- }
-
- return true;
-}
-
-void QTPlayer::initParseTable() {
- static const ParseTable p[] = {
- { MKID_BE('dinf'), &QTPlayer::readDefault },
- { MKID_BE('dref'), &QTPlayer::readLeaf },
- { MKID_BE('edts'), &QTPlayer::readDefault },
- { MKID_BE('elst'), &QTPlayer::readELST },
- { MKID_BE('hdlr'), &QTPlayer::readHDLR },
- { MKID_BE('mdat'), &QTPlayer::readMDAT },
- { MKID_BE('mdhd'), &QTPlayer::readMDHD },
- { MKID_BE('mdia'), &QTPlayer::readDefault },
- { MKID_BE('minf'), &QTPlayer::readDefault },
- { MKID_BE('moov'), &QTPlayer::readMOOV },
- { MKID_BE('mvhd'), &QTPlayer::readMVHD },
- { MKID_BE('smhd'), &QTPlayer::readLeaf },
- { MKID_BE('stbl'), &QTPlayer::readDefault },
- { MKID_BE('stco'), &QTPlayer::readSTCO },
- { MKID_BE('stsc'), &QTPlayer::readSTSC },
- { MKID_BE('stsd'), &QTPlayer::readSTSD },
- { MKID_BE('stss'), &QTPlayer::readSTSS },
- { MKID_BE('stsz'), &QTPlayer::readSTSZ },
- { MKID_BE('stts'), &QTPlayer::readSTTS },
- { MKID_BE('tkhd'), &QTPlayer::readTKHD },
- { MKID_BE('trak'), &QTPlayer::readTRAK },
- { MKID_BE('udta'), &QTPlayer::readLeaf },
- { MKID_BE('vmhd'), &QTPlayer::readLeaf },
- { MKID_BE('cmov'), &QTPlayer::readCMOV },
- { MKID_BE('wave'), &QTPlayer::readWAVE },
- { 0, 0 }
- };
-
- _parseTable = p;
-}
-
-int QTPlayer::readDefault(MOVatom atom) {
- uint32 total_size = 0;
- MOVatom a;
- int err = 0;
-
- a.offset = atom.offset;
-
- while(((total_size + 8) < atom.size) && !_fd->eos() && !err) {
- a.size = atom.size;
- a.type = 0;
-
- if (atom.size >= 8) {
- a.size = _fd->readUint32BE();
- a.type = _fd->readUint32BE();
- }
-
- total_size += 8;
- a.offset += 8;
- debug(4, "type: %08x %.4s sz: %x %x %x", a.type, tag2str(a.type), a.size, atom.size, total_size);
-
- if (a.size == 1) { // 64 bit extended size
- warning("64 bit extended size is not supported in QuickTime");
- return -1;
- }
-
- if (a.size == 0) {
- a.size = atom.size - total_size;
- if (a.size <= 8)
- break;
- }
-
- uint32 i = 0;
-
- for (; _parseTable[i].type != 0 && _parseTable[i].type != a.type; i++)
- // empty;
-
- if (a.size < 8)
- break;
-
- a.size -= 8;
-
- if (_parseTable[i].type == 0) { // skip leaf atoms data
- debug(0, ">>> Skipped [%s]", tag2str(a.type));
-
- _fd->seek(a.size, SEEK_CUR);
- } else {
- uint32 start_pos = _fd->pos();
- err = (this->*_parseTable[i].func)(a);
-
- uint32 left = a.size - _fd->pos() + start_pos;
-
- if (left > 0) // skip garbage at atom end
- _fd->seek(left, SEEK_CUR);
- }
-
- a.offset += a.size;
- total_size += a.size;
- }
-
- if (!err && total_size < atom.size)
- _fd->seek(atom.size - total_size, SEEK_SET);
-
- return err;
-}
-
-int QTPlayer::readLeaf(MOVatom atom) {
- if (atom.size > 1)
- _fd->seek(atom.size, SEEK_SET);
-
- return 0;
-}
-
-int QTPlayer::readMOOV(MOVatom atom) {
- if (readDefault(atom) < 0)
- return -1;
-
- // we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat'
- // so we don't parse the whole file if over a network
- _foundMOOV = true;
-
- if(_foundMDAT)
- return 1; // found both, just go
-
- return 0; // now go for mdat
-}
-
-int QTPlayer::readCMOV(MOVatom atom) {
-#ifdef USE_ZLIB
- // Read in the dcom atom
- _fd->readUint32BE();
- if (_fd->readUint32BE() != MKID_BE('dcom'))
- return -1;
- if (_fd->readUint32BE() != MKID_BE('zlib')) {
- warning("Unknown cmov compression type");
- return -1;
- }
-
- // Read in the cmvd atom
- uint32 compressedSize = _fd->readUint32BE() - 12;
- if (_fd->readUint32BE() != MKID_BE('cmvd'))
- return -1;
- uint32 uncompressedSize = _fd->readUint32BE();
-
- // Read in data
- byte *compressedData = (byte *)malloc(compressedSize);
- _fd->read(compressedData, compressedSize);
-
- // Create uncompressed stream
- byte *uncompressedData = (byte *)malloc(uncompressedSize);
-
- // Uncompress the data
- unsigned long dstLen = uncompressedSize;
- if (!Common::uncompress(uncompressedData, &dstLen, compressedData, compressedSize)) {
- warning ("Could not uncompress cmov chunk");
- return -1;
- }
-
- // Load data into a new MemoryReadStream and assign _fd to be that
- Common::SeekableReadStream *oldStream = _fd;
- _fd = new Common::MemoryReadStream(uncompressedData, uncompressedSize, DisposeAfterUse::YES);
-
- // Read the contents of the uncompressed data
- MOVatom a = { MKID_BE('moov'), 0, uncompressedSize };
- int err = readDefault(a);
-
- // Assign the file handle back to the original handle
- free(compressedData);
- delete _fd;
- _fd = oldStream;
-
- return err;
-#else
- warning ("zlib not found, cannot read QuickTime cmov atom");
- return -1;
-#endif
-}
-
-int QTPlayer::readMVHD(MOVatom atom) {
- byte version = _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- if (version == 1) {
- warning("QuickTime version 1");
- _fd->readUint32BE(); _fd->readUint32BE();
- _fd->readUint32BE(); _fd->readUint32BE();
- } else {
- _fd->readUint32BE(); // creation time
- _fd->readUint32BE(); // modification time
- }
-
- _timeScale = _fd->readUint32BE(); // time scale
- debug(0, "time scale = %i\n", _timeScale);
-
- // duration
- _duration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE();
- _fd->readUint32BE(); // preferred scale
-
- _fd->readUint16BE(); // preferred volume
-
- _fd->seek(10, SEEK_CUR); // reserved
-
- // We only need two values from the movie display matrix. Most of the values are just
- // skipped. xMod and yMod are 16:16 fixed point numbers, the last part of the 3x3 matrix
- // is 2:30.
- uint32 xMod = _fd->readUint32BE();
- _fd->skip(12);
- uint32 yMod = _fd->readUint32BE();
- _fd->skip(16);
-
- if (xMod != yMod)
- error("X and Y resolution modifiers differ");
-
- if (xMod == 0x8000)
- _scaleMode = kScaleHalf;
- else if (xMod == 0x4000)
- _scaleMode = kScaleQuarter;
- else
- _scaleMode = kScaleNormal;
-
- debug(1, "readMVHD(): scaleMode = %d", (int)_scaleMode);
-
- _fd->readUint32BE(); // preview time
- _fd->readUint32BE(); // preview duration
- _fd->readUint32BE(); // poster time
- _fd->readUint32BE(); // selection time
- _fd->readUint32BE(); // selection duration
- _fd->readUint32BE(); // current time
- _fd->readUint32BE(); // next track ID
-
- return 0;
-}
-
-int QTPlayer::readTRAK(MOVatom atom) {
- MOVStreamContext *sc = new MOVStreamContext();
-
- if (!sc)
- return -1;
-
- sc->sample_to_chunk_index = -1;
- sc->codec_type = CODEC_TYPE_MOV_OTHER;
- sc->start_time = 0; // XXX: check
- _streams[_numStreams++] = sc;
-
- return readDefault(atom);
-}
-
-// this atom contains actual media data
-int QTPlayer::readMDAT(MOVatom atom) {
- if (atom.size == 0) // wrong one (MP4)
- return 0;
-
- _foundMDAT = true;
-
- _mdatOffset = atom.offset;
- _mdatSize = atom.size;
-
- if (_foundMOOV)
- return 1; // found both, just go
-
- _fd->seek(atom.size, SEEK_CUR);
-
- return 0; // now go for moov
-}
-
-int QTPlayer::readTKHD(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
- byte version = _fd->readByte();
-
- _fd->readByte(); _fd->readByte();
- _fd->readByte(); // flags
- //
- //MOV_TRACK_ENABLED 0x0001
- //MOV_TRACK_IN_MOVIE 0x0002
- //MOV_TRACK_IN_PREVIEW 0x0004
- //MOV_TRACK_IN_POSTER 0x0008
- //
-
- if (version == 1) {
- _fd->readUint32BE(); _fd->readUint32BE();
- _fd->readUint32BE(); _fd->readUint32BE();
- } else {
- _fd->readUint32BE(); // creation time
- _fd->readUint32BE(); // modification time
- }
-
- /* st->id = */_fd->readUint32BE(); // track id (NOT 0 !)
- _fd->readUint32BE(); // reserved
- //st->start_time = 0; // check
- (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // highlevel (considering edits) duration in movie timebase
- _fd->readUint32BE(); // reserved
- _fd->readUint32BE(); // reserved
-
- _fd->readUint16BE(); // layer
- _fd->readUint16BE(); // alternate group
- _fd->readUint16BE(); // volume
- _fd->readUint16BE(); // reserved
-
- // We only need the two values from the displacement matrix for a track.
- // See readMVHD() for more information.
- uint32 xMod = _fd->readUint32BE();
- _fd->skip(12);
- uint32 yMod = _fd->readUint32BE();
- _fd->skip(16);
-
- if (xMod != yMod)
- error("X and Y resolution modifiers differ");
-
- if (xMod == 0x8000)
- st->scaleMode = kScaleHalf;
- else if (xMod == 0x4000)
- st->scaleMode = kScaleQuarter;
- else
- st->scaleMode = kScaleNormal;
-
- debug(1, "readTKHD(): scaleMode = %d", (int)_scaleMode);
-
- // these are fixed-point, 16:16
- // uint32 tkWidth = _fd->readUint32BE() >> 16; // track width
- // uint32 tkHeight = _fd->readUint32BE() >> 16; // track height
-
- return 0;
-}
-
-// edit list atom
-int QTPlayer::readELST(MOVatom atom) {
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
- uint32 editCount = _streams[_numStreams - 1]->edit_count = _fd->readUint32BE(); // entries
-
- for (uint32 i = 0; i < editCount; i++){
- _fd->readUint32BE(); // Track duration
- _fd->readUint32BE(); // Media time
- _fd->readUint32BE(); // Media rate
- }
-
- debug(0, "track[%i].edit_count = %i", _numStreams - 1, _streams[_numStreams - 1]->edit_count);
-
- if (editCount != 1)
- warning("Multiple edit list entries. Things may go awry");
-
- return 0;
-}
-
-int QTPlayer::readHDLR(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- // component type
- uint32 ctype = _fd->readUint32LE();
- uint32 type = _fd->readUint32BE(); // component subtype
-
- debug(0, "ctype= %s (0x%08lx)", tag2str(ctype), (long)ctype);
- debug(0, "stype= %s", tag2str(type));
-
- if(ctype == MKID_BE('mhlr')) // MOV
- debug(0, "MOV detected");
- else if(ctype == 0) {
- warning("MP4 streams are not supported");
- return -1;
- }
-
- if (type == MKID_BE('vide'))
- st->codec_type = CODEC_TYPE_VIDEO;
- else if (type == MKID_BE('soun'))
- st->codec_type = CODEC_TYPE_AUDIO;
-
- _fd->readUint32BE(); // component manufacture
- _fd->readUint32BE(); // component flags
- _fd->readUint32BE(); // component flags mask
-
- if (atom.size <= 24)
- return 0; // nothing left to read
-
- // .mov: PASCAL string
- byte len = _fd->readByte();
- _fd->seek(len, SEEK_CUR);
-
- _fd->seek(atom.size - (_fd->pos() - atom.offset), SEEK_CUR);
-
- return 0;
-}
-
-int QTPlayer::readMDHD(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
- byte version = _fd->readByte();
-
- if (version > 1)
- return 1; // unsupported
-
- _fd->readByte(); _fd->readByte();
- _fd->readByte(); // flags
-
- if (version == 1) {
- _fd->readUint32BE(); _fd->readUint32BE();
- _fd->readUint32BE(); _fd->readUint32BE();
- } else {
- _fd->readUint32BE(); // creation time
- _fd->readUint32BE(); // modification time
- }
-
- st->time_scale = _fd->readUint32BE();
- st->duration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // duration
-
- _fd->readUint16BE(); // language
- _fd->readUint16BE(); // quality
-
- return 0;
-}
-
-int QTPlayer::readSTSD(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- uint32 entries = _fd->readUint32BE();
-
- while (entries--) { //Parsing Sample description table
- MOVatom a = { 0, 0, 0 };
- uint32 start_pos = _fd->pos();
- int size = _fd->readUint32BE(); // size
- uint32 format = _fd->readUint32BE(); // data format
-
- _fd->readUint32BE(); // reserved
- _fd->readUint16BE(); // reserved
- _fd->readUint16BE(); // index
-
- debug(0, "size=%d 4CC= %s codec_type=%d", size, tag2str(format), st->codec_type);
- st->codec_tag = format;
-
- if (st->codec_type == CODEC_TYPE_VIDEO) {
- debug(0, "Video Codec FourCC: \'%s\'", tag2str(format));
-
- _fd->readUint16BE(); // version
- _fd->readUint16BE(); // revision level
- _fd->readUint32BE(); // vendor
- _fd->readUint32BE(); // temporal quality
- _fd->readUint32BE(); // spacial quality
-
- st->width = _fd->readUint16BE(); // width
- st->height = _fd->readUint16BE(); // height
-
- _fd->readUint32BE(); // horiz resolution
- _fd->readUint32BE(); // vert resolution
- _fd->readUint32BE(); // data size, always 0
- uint16 frames_per_sample = _fd->readUint16BE(); // frames per samples
-
- debug(0, "frames/samples = %d", frames_per_sample);
-
- byte codec_name[32];
- _fd->read(codec_name, 32); // codec name, pascal string (FIXME: true for mp4?)
- if (codec_name[0] <= 31) {
- memcpy(st->codec_name, &codec_name[1], codec_name[0]);
- st->codec_name[codec_name[0]] = 0;
- }
-
- st->bits_per_sample = _fd->readUint16BE(); // depth
- st->color_table_id = _fd->readUint16BE(); // colortable id
-
-// These are set in mov_read_stts and might already be set!
-// st->codec->time_base.den = 25;
-// st->codec->time_base.num = 1;
-
-
- // figure out the palette situation
- byte colorDepth = st->bits_per_sample & 0x1F;
- bool colorGreyscale = (st->bits_per_sample & 0x20) != 0;
-
- debug(0, "color depth: %d", colorDepth);
-
- // if the depth is 2, 4, or 8 bpp, file is palettized
- if (colorDepth == 2 || colorDepth == 4 || colorDepth == 8) {
- _dirtyPalette = true;
-
- if (colorGreyscale) {
- debug(0, "Greyscale palette");
-
- // compute the greyscale palette
- uint16 colorCount = 1 << colorDepth;
- int16 colorIndex = 255;
- byte colorDec = 256 / (colorCount - 1);
- for (byte j = 0; j < colorCount; j++) {
- _palette[j * 3] = _palette[j * 3 + 1] = _palette[j * 3 + 2] = colorIndex;
- colorIndex -= colorDec;
- if (colorIndex < 0)
- colorIndex = 0;
- }
- } else if (st->color_table_id & 0x08) {
- // if flag bit 3 is set, use the default palette
- //uint16 colorCount = 1 << colorDepth;
-
- warning("Predefined palette! %dbpp", colorDepth);
-#if 0
- byte *color_table;
- byte r, g, b;
-
- if (colorDepth == 2)
- color_table = ff_qt_default_palette_4;
- else if (colorDepth == 4)
- color_table = ff_qt_default_palette_16;
- else
- color_table = ff_qt_default_palette_256;
-
- for (byte j = 0; j < color_count; j++) {
- r = color_table[j * 4 + 0];
- g = color_table[j * 4 + 1];
- b = color_table[j * 4 + 2];
- _palette_control.palette[j] = (r << 16) | (g << 8) | (b);
- }
-#endif
-
- } else {
- debug(0, "Palette from file");
-
- // load the palette from the file
- uint32 colorStart = _fd->readUint32BE();
- /* uint16 colorCount = */ _fd->readUint16BE();
- uint16 colorEnd = _fd->readUint16BE();
- for (uint32 j = colorStart; j <= colorEnd; j++) {
- // each R, G, or B component is 16 bits;
- // only use the top 8 bits; skip alpha bytes
- // up front
- _fd->readByte();
- _fd->readByte();
- _palette[j * 3] = _fd->readByte();
- _fd->readByte();
- _palette[j * 3 + 1] = _fd->readByte();
- _fd->readByte();
- _palette[j * 3 + 2] = _fd->readByte();
- _fd->readByte();
- }
- }
- st->palettized = true;
- } else
- st->palettized = false;
- } else if (st->codec_type == CODEC_TYPE_AUDIO) {
- debug(0, "Audio Codec FourCC: \'%s\'", tag2str(format));
-
- st->stsd_version = _fd->readUint16BE();
- _fd->readUint16BE(); // revision level
- _fd->readUint32BE(); // vendor
-
- st->channels = _fd->readUint16BE(); // channel count
- st->bits_per_sample = _fd->readUint16BE(); // sample size
- // do we need to force to 16 for AMR ?
-
- // handle specific s8 codec
- _fd->readUint16BE(); // compression id = 0
- _fd->readUint16BE(); // packet size = 0
-
- st->sample_rate = (_fd->readUint32BE() >> 16);
-
- debug(0, "stsd version =%d", st->stsd_version);
- if (st->stsd_version == 0) {
- // Not used, except in special cases. See below.
- st->samples_per_frame = st->bytes_per_frame = 0;
- } else if (st->stsd_version == 1) {
- // Read QT version 1 fields. In version 0 these dont exist.
- st->samples_per_frame = _fd->readUint32BE();
- debug(0, "stsd samples_per_frame =%d", st->samples_per_frame);
- _fd->readUint32BE(); // bytes per packet
- st->bytes_per_frame = _fd->readUint32BE();
- debug(0, "stsd bytes_per_frame =%d", st->bytes_per_frame);
- _fd->readUint32BE(); // bytes per sample
- } else {
- warning("Unsupported QuickTime STSD audio version %d", st->stsd_version);
- return 1;
- }
-
- // Version 0 videos (such as the Riven ones) don't have this set,
- // but we need it later on. Add it in here.
- if (format == MKID_BE('ima4')) {
- st->samples_per_frame = 64;
- st->bytes_per_frame = 34 * st->channels;
- }
- } else {
- // other codec type, just skip (rtp, mp4s, tmcd ...)
- _fd->seek(size - (_fd->pos() - start_pos), SEEK_CUR);
- }
-
- // this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...)
- a.size = size - (_fd->pos() - start_pos);
- if (a.size > 8)
- readDefault(a);
- else if (a.size > 0)
- _fd->seek(a.size, SEEK_CUR);
- }
-
- if (st->codec_type == CODEC_TYPE_AUDIO && st->sample_rate == 0 && st->time_scale > 1)
- st->sample_rate= st->time_scale;
-
- return 0;
-}
-
-int QTPlayer::readSTSC(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- st->sample_to_chunk_sz = _fd->readUint32BE();
-
- debug(0, "track[%i].stsc.entries = %i", _numStreams - 1, st->sample_to_chunk_sz);
-
- st->sample_to_chunk = new MOVstsc[st->sample_to_chunk_sz];
-
- if (!st->sample_to_chunk)
- return -1;
-
- for (uint32 i = 0; i < st->sample_to_chunk_sz; i++) {
- st->sample_to_chunk[i].first = _fd->readUint32BE();
- st->sample_to_chunk[i].count = _fd->readUint32BE();
- st->sample_to_chunk[i].id = _fd->readUint32BE();
- //printf ("Sample to Chunk[%d]: First = %d, Count = %d\n", i, st->sample_to_chunk[i].first, st->sample_to_chunk[i].count);
- }
-
- return 0;
-}
-
-int QTPlayer::readSTSS(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- st->keyframe_count = _fd->readUint32BE();
-
- debug(0, "keyframe_count = %d", st->keyframe_count);
-
- st->keyframes = new uint32[st->keyframe_count];
-
- if (!st->keyframes)
- return -1;
-
- for (uint32 i = 0; i < st->keyframe_count; i++) {
- st->keyframes[i] = _fd->readUint32BE();
- debug(6, "keyframes[%d] = %d", i, st->keyframes[i]);
-
- }
- return 0;
-}
-
-int QTPlayer::readSTSZ(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- st->sample_size = _fd->readUint32BE();
- st->sample_count = _fd->readUint32BE();
-
- debug(5, "sample_size = %d sample_count = %d", st->sample_size, st->sample_count);
-
- if (st->sample_size)
- return 0; // there isn't any table following
-
- st->sample_sizes = new uint32[st->sample_count];
-
- if (!st->sample_sizes)
- return -1;
-
- for(uint32 i = 0; i < st->sample_count; i++) {
- st->sample_sizes[i] = _fd->readUint32BE();
- debug(6, "sample_sizes[%d] = %d", i, st->sample_sizes[i]);
- }
-
- return 0;
-}
-
-static uint32 ff_gcd(uint32 a, uint32 b) {
- if(b) return ff_gcd(b, a%b);
- else return a;
-}
-
-int QTPlayer::readSTTS(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
- uint32 duration = 0;
- uint32 total_sample_count = 0;
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- st->stts_count = _fd->readUint32BE();
- st->stts_data = new MOVstts[st->stts_count];
-
- debug(0, "track[%i].stts.entries = %i", _numStreams - 1, st->stts_count);
-
- st->time_rate = 0;
-
- for (int32 i = 0; i < st->stts_count; i++) {
- int sample_duration;
- int sample_count;
-
- sample_count = _fd->readUint32BE();
- sample_duration = _fd->readUint32BE();
- st->stts_data[i].count = sample_count;
- st->stts_data[i].duration = sample_duration;
-
- st->time_rate = ff_gcd(st->time_rate, sample_duration);
-
- debug(0, "sample_count=%d, sample_duration=%d", sample_count, sample_duration);
-
- duration += sample_duration * sample_count;
- total_sample_count += sample_count;
- }
-
- st->nb_frames = total_sample_count;
-
- if (duration)
- st->duration = duration;
-
- return 0;
-}
-
-int QTPlayer::readSTCO(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- st->chunk_count = _fd->readUint32BE();
- st->chunk_offsets = new uint32[st->chunk_count];
-
- if (!st->chunk_offsets)
- return -1;
-
- for (uint32 i = 0; i < st->chunk_count; i++) {
- // WORKAROUND/HACK: The offsets in Riven videos (ones inside the Mohawk archives themselves)
- // have offsets relative to the archive and not the video. This is quite nasty. We subtract
- // the initial offset of the stream to get the correct value inside of the stream.
- st->chunk_offsets[i] = _fd->readUint32BE() - _beginOffset;
- }
-
- for (uint32 i = 0; i < _numStreams; i++) {
- MOVStreamContext *sc2 = _streams[i];
-
- if(sc2 && sc2->chunk_offsets){
- uint32 first = sc2->chunk_offsets[0];
- uint32 last = sc2->chunk_offsets[sc2->chunk_count - 1];
-
- if(first >= st->chunk_offsets[st->chunk_count - 1] || last <= st->chunk_offsets[0])
- _ni = 1;
- }
- }
-
- return 0;
-}
-
-int QTPlayer::readWAVE(MOVatom atom) {
- if (_numStreams < 1)
- return 0;
-
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- if (atom.size > (1 << 30))
- return -1;
-
- if (st->codec_tag == MKID_BE('QDM2')) // Read extradata for QDM2
- st->extradata = _fd->readStream(atom.size - 8);
- else if (atom.size > 8)
- return readDefault(atom);
- else
- _fd->skip(atom.size);
-
- return 0;
-}
-
-void QTPlayer::close() {
- stopAudio();
-
- delete _videoCodec; _videoCodec = 0;
-
- for (uint32 i = 0; i < _numStreams; i++)
- delete _streams[i];
-
- delete _fd;
-
- if (_scaledSurface) {
- _scaledSurface->free();
- delete _scaledSurface;
- _scaledSurface = 0;
- }
-
- // The audio stream is deleted automatically
- _audStream = NULL;
-
- Graphics::VideoDecoder::reset();
-}
-
-Common::SeekableReadStream *QTPlayer::getNextFramePacket() {
- if (_videoStreamIndex < 0)
- return NULL;
-
- // First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for.
- int32 totalSampleCount = 0;
- int32 sampleInChunk = 0;
- int32 actualChunk = -1;
-
- for (uint32 i = 0; i < _streams[_videoStreamIndex]->chunk_count; i++) {
- int32 sampleToChunkIndex = -1;
-
- for (uint32 j = 0; j < _streams[_videoStreamIndex]->sample_to_chunk_sz; j++)
- if (i >= _streams[_videoStreamIndex]->sample_to_chunk[j].first - 1)
- sampleToChunkIndex = j;
-
- if (sampleToChunkIndex < 0)
- error("This chunk (%d) is imaginary", sampleToChunkIndex);
-
- totalSampleCount += _streams[_videoStreamIndex]->sample_to_chunk[sampleToChunkIndex].count;
-
- if (totalSampleCount > getCurFrame()) {
- actualChunk = i;
- sampleInChunk = _streams[_videoStreamIndex]->sample_to_chunk[sampleToChunkIndex].count - totalSampleCount + getCurFrame();
- break;
- }
- }
-
- if (actualChunk < 0) {
- warning ("Could not find data for frame %d", getCurFrame());
- return NULL;
- }
-
- // Next seek to that frame
- _fd->seek(_streams[_videoStreamIndex]->chunk_offsets[actualChunk]);
-
- // Then, if the chunk holds more than one frame, seek to where the frame we want is located
- for (int32 i = getCurFrame() - sampleInChunk; i < getCurFrame(); i++) {
- if (_streams[_videoStreamIndex]->sample_size != 0)
- _fd->skip(_streams[_videoStreamIndex]->sample_size);
- else
- _fd->skip(_streams[_videoStreamIndex]->sample_sizes[i]);
- }
-
- // Finally, read in the raw data for the frame
- //printf ("Frame Data[%d]: Offset = %d, Size = %d\n", getCurFrame(), _fd->pos(), _streams[_videoStreamIndex]->sample_sizes[getCurFrame()]);
-
- if (_streams[_videoStreamIndex]->sample_size != 0)
- return _fd->readStream(_streams[_videoStreamIndex]->sample_size);
-
- return _fd->readStream(_streams[_videoStreamIndex]->sample_sizes[getCurFrame()]);
-}
-
-bool QTPlayer::checkAudioCodecSupport(uint32 tag) {
- // Check if the codec is a supported codec
- if (tag == MKID_BE('twos') || tag == MKID_BE('raw ') || tag == MKID_BE('ima4') || tag == MKID_BE('QDM2'))
- return true;
-
- warning("Audio Codec Not Supported: \'%s\'", tag2str(tag));
-
- return false;
-}
-
-Audio::AudioStream *QTPlayer::createAudioStream(Common::SeekableReadStream *stream) {
- if (!stream || _audioStreamIndex < 0)
- return NULL;
-
- if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('twos') || _streams[_audioStreamIndex]->codec_tag == MKID_BE('raw ')) {
- // Fortunately, most of the audio used in Myst videos is raw...
- uint16 flags = 0;
- if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('raw '))
- flags |= Audio::FLAG_UNSIGNED;
- if (_streams[_audioStreamIndex]->channels == 2)
- flags |= Audio::FLAG_STEREO;
- if (_streams[_audioStreamIndex]->bits_per_sample == 16)
- flags |= Audio::FLAG_16BITS;
- uint32 dataSize = stream->size();
- byte *data = (byte *)malloc(dataSize);
- stream->read(data, dataSize);
- delete stream;
- return Audio::makeRawStream(data, dataSize, _streams[_audioStreamIndex]->sample_rate, flags);
- } else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('ima4')) {
- // Riven uses this codec (as do some Myst ME videos)
- return Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMApple, _streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels, 34);
- } else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('QDM2')) {
- // Several Myst ME videos use this codec
- return new QDM2Stream(stream, _streams[_audioStreamIndex]->extradata);
- }
-
- error("Unsupported audio codec");
-
- return NULL;
-}
-
-void QTPlayer::updateAudioBuffer() {
- if (!_audStream)
- return;
-
- // Keep two streams in buffer so that when the first ends, it goes right into the next
- for (; _audStream->numQueuedStreams() < 2 && _curAudioChunk < _streams[_audioStreamIndex]->chunk_count; _curAudioChunk++) {
- Common::MemoryWriteStreamDynamic *wStream = new Common::MemoryWriteStreamDynamic();
-
- _fd->seek(_streams[_audioStreamIndex]->chunk_offsets[_curAudioChunk]);
-
- // First, we have to get the sample count
- uint32 sampleCount = 0;
- for (uint32 j = 0; j < _streams[_audioStreamIndex]->sample_to_chunk_sz; j++)
- if (_curAudioChunk >= (_streams[_audioStreamIndex]->sample_to_chunk[j].first - 1))
- sampleCount = _streams[_audioStreamIndex]->sample_to_chunk[j].count;
- assert(sampleCount);
-
- // Then calculate the right sizes
- while (sampleCount > 0) {
- uint32 samples = 0, size = 0;
-
- if (_streams[_audioStreamIndex]->samples_per_frame >= 160) {
- samples = _streams[_audioStreamIndex]->samples_per_frame;
- size = _streams[_audioStreamIndex]->bytes_per_frame;
- } else if (_streams[_audioStreamIndex]->samples_per_frame > 1) {
- samples = MIN<uint32>((1024 / _streams[_audioStreamIndex]->samples_per_frame) * _streams[_audioStreamIndex]->samples_per_frame, sampleCount);
- size = (samples / _streams[_audioStreamIndex]->samples_per_frame) * _streams[_audioStreamIndex]->bytes_per_frame;
- } else {
- samples = MIN<uint32>(1024, sampleCount);
- size = samples * _streams[_audioStreamIndex]->sample_size;
- }
-
- // Now, we read in the data for this data and output it
- byte *data = (byte *)malloc(size);
- _fd->read(data, size);
- wStream->write(data, size);
- free(data);
- sampleCount -= samples;
- }
-
- // Now queue the buffer
- _audStream->queueAudioStream(createAudioStream(new Common::MemoryReadStream(wStream->getData(), wStream->size(), DisposeAfterUse::YES)));
- delete wStream;
- }
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/qt_player.h b/engines/mohawk/video/qt_player.h
deleted file mode 100644
index 6657d3edba..0000000000
--- a/engines/mohawk/video/qt_player.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-//
-// Heavily based on ffmpeg code.
-//
-// Copyright (c) 2001 Fabrice Bellard.
-// First version by Francois Revol revol@free.fr
-// Seek function by Gael Chardon gael.dev@4now.net
-//
-
-#ifndef MOHAWK_QT_PLAYER_H
-#define MOHAWK_QT_PLAYER_H
-
-#include "common/scummsys.h"
-#include "common/queue.h"
-
-#include "graphics/video/video_decoder.h"
-#include "graphics/video/codecs/codec.h"
-
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-
-namespace Common {
- class File;
-}
-
-namespace Mohawk {
-
-enum ScaleMode {
- kScaleNormal = 1,
- kScaleHalf = 2,
- kScaleQuarter = 4
-};
-
-class QTPlayer : public Graphics::RewindableVideoDecoder {
-public:
- QTPlayer();
- virtual ~QTPlayer();
-
- /**
- * Returns the width of the video
- * @return the width of the video
- */
- uint16 getWidth() const;
-
- /**
- * Returns the height of the video
- * @return the height of the video
- */
- uint16 getHeight() const;
-
- /**
- * Returns the amount of frames in the video
- * @return the amount of frames in the video
- */
- uint32 getFrameCount() const;
-
- /**
- * Load a QuickTime video file from a SeekableReadStream
- * @param stream the stream to load
- */
- bool load(Common::SeekableReadStream &stream);
-
- /**
- * Close a QuickTime encoded video file
- */
- void close();
-
- /**
- * Returns the palette of the video
- * @return the palette of the video
- */
- byte *getPalette() { _dirtyPalette = false; return _palette; }
- bool hasDirtyPalette() const { return _dirtyPalette; }
-
- /**
- * Set the beginning offset of the video so we can modify the offsets in the stco
- * atom of videos inside the Mohawk archives
- * @param the beginning offset of the video
- */
- void setChunkBeginOffset(uint32 offset) { _beginOffset = offset; }
-
- bool isVideoLoaded() const { return _fd != 0; }
- Graphics::Surface *decodeNextFrame();
- bool needsUpdate() const;
- bool endOfVideo() const;
- uint32 getElapsedTime() const;
- uint32 getTimeToNextFrame() const;
- Graphics::PixelFormat getPixelFormat() const;
-
- // RewindableVideoDecoder API
- void rewind();
-
- // TODO: This audio function need to be removed from the public and/or added to
- // the VideoDecoder API directly. I plan on replacing this function with something
- // that can figure out how much audio is needed instead of constantly keeping two
- // chunks in memory.
- void updateAudioBuffer();
-
-protected:
- // This is the file handle from which data is read from. It can be the actual file handle or a decompressed stream.
- Common::SeekableReadStream *_fd;
-
- struct MOVatom {
- uint32 type;
- uint32 offset;
- uint32 size;
- };
-
- struct ParseTable {
- uint32 type;
- int (QTPlayer::*func)(MOVatom atom);
- };
-
- struct MOVstts {
- int count;
- int duration;
- };
-
- struct MOVstsc {
- uint32 first;
- uint32 count;
- uint32 id;
- };
-
- enum CodecType {
- CODEC_TYPE_MOV_OTHER,
- CODEC_TYPE_VIDEO,
- CODEC_TYPE_AUDIO
- };
-
- struct MOVStreamContext {
- MOVStreamContext() { memset(this, 0, sizeof(MOVStreamContext)); }
- ~MOVStreamContext() {
- delete[] chunk_offsets;
- delete[] stts_data;
- delete[] ctts_data;
- delete[] sample_to_chunk;
- delete[] sample_sizes;
- delete[] keyframes;
- delete extradata;
- }
-
- int ffindex; /* the ffmpeg stream id */
- int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */
- uint32 next_chunk;
- uint32 chunk_count;
- uint32 *chunk_offsets;
- int stts_count;
- MOVstts *stts_data;
- int ctts_count;
- MOVstts *ctts_data;
- int edit_count; /* number of 'edit' (elst atom) */
- uint32 sample_to_chunk_sz;
- MOVstsc *sample_to_chunk;
- int32 sample_to_chunk_index;
- int sample_to_time_index;
- uint32 sample_to_time_sample;
- uint32 sample_to_time_time;
- int sample_to_ctime_index;
- int sample_to_ctime_sample;
- uint32 sample_size;
- uint32 sample_count;
- uint32 *sample_sizes;
- uint32 keyframe_count;
- uint32 *keyframes;
- int32 time_scale;
- int time_rate;
- uint32 current_sample;
- uint32 left_in_chunk; /* how many samples before next chunk */
-
- uint16 width;
- uint16 height;
- int codec_type;
- uint32 codec_tag;
- char codec_name[32];
- uint16 bits_per_sample;
- uint16 color_table_id;
- bool palettized;
- Common::SeekableReadStream *extradata;
-
- uint16 stsd_version;
- uint16 channels;
- uint16 sample_rate;
- uint32 samples_per_frame;
- uint32 bytes_per_frame;
-
- uint32 nb_frames;
- uint32 duration;
- uint32 start_time;
- ScaleMode scaleMode;
- };
-
- const ParseTable *_parseTable;
- bool _foundMOOV;
- bool _foundMDAT;
- uint32 _timeScale;
- uint32 _duration;
- uint32 _mdatOffset;
- uint32 _mdatSize;
- uint32 _next_chunk_offset;
- MOVStreamContext *_partial;
- uint32 _numStreams;
- int _ni;
- ScaleMode _scaleMode;
- MOVStreamContext *_streams[20];
- byte _palette[256 * 3];
- bool _dirtyPalette;
- uint32 _beginOffset;
-
- void initParseTable();
- Audio::AudioStream *createAudioStream(Common::SeekableReadStream *stream);
- bool checkAudioCodecSupport(uint32 tag);
- Common::SeekableReadStream *getNextFramePacket();
- uint32 getFrameDuration();
- uint32 getCodecTag();
- byte getBitsPerPixel();
-
- Audio::QueuingAudioStream *_audStream;
- void startAudio();
- void stopAudio();
- int8 _audioStreamIndex;
- uint _curAudioChunk;
- Audio::SoundHandle _audHandle;
-
- Graphics::Codec *createCodec(uint32 codecTag, byte bitsPerPixel);
- Graphics::Codec *_videoCodec;
- uint32 _nextFrameStartTime;
- int8 _videoStreamIndex;
-
- Graphics::Surface *_scaledSurface;
- Graphics::Surface *scaleSurface(Graphics::Surface *frame);
- ScaleMode getScaleMode() const;
-
- void pauseVideoIntern(bool pause);
-
- int readDefault(MOVatom atom);
- int readLeaf(MOVatom atom);
- int readELST(MOVatom atom);
- int readHDLR(MOVatom atom);
- int readMDAT(MOVatom atom);
- int readMDHD(MOVatom atom);
- int readMOOV(MOVatom atom);
- int readMVHD(MOVatom atom);
- int readTKHD(MOVatom atom);
- int readTRAK(MOVatom atom);
- int readSTCO(MOVatom atom);
- int readSTSC(MOVatom atom);
- int readSTSD(MOVatom atom);
- int readSTSS(MOVatom atom);
- int readSTSZ(MOVatom atom);
- int readSTTS(MOVatom atom);
- int readCMOV(MOVatom atom);
- int readWAVE(MOVatom atom);
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/video/qtrle.cpp b/engines/mohawk/video/qtrle.cpp
deleted file mode 100644
index c06dbefcb3..0000000000
--- a/engines/mohawk/video/qtrle.cpp
+++ /dev/null
@@ -1,420 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-// QuickTime RLE Decoder
-// Based off ffmpeg's QuickTime RLE decoder (written by Mike Melanson)
-
-#include "mohawk/video/qtrle.h"
-
-#include "common/scummsys.h"
-#include "common/stream.h"
-#include "common/system.h"
-#include "graphics/colormasks.h"
-#include "graphics/surface.h"
-
-namespace Mohawk {
-
-QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Graphics::Codec() {
- _bitsPerPixel = bitsPerPixel;
- _pixelFormat = g_system->getScreenFormat();
-
- // We need to increase the surface size to a multiple of 4
- uint16 wMod = width % 4;
- if(wMod != 0)
- width += 4 - wMod;
-
- debug(2, "QTRLE corrected width: %d", width);
-
- _surface = new Graphics::Surface();
- _surface->create(width, height, _bitsPerPixel <= 8 ? 1 : _pixelFormat.bytesPerPixel);
-}
-
-#define CHECK_STREAM_PTR(n) \
- if ((stream->pos() + n) > stream->size()) { \
- warning ("Problem: stream out of bounds (%d >= %d)", stream->pos() + n, stream->size()); \
- return; \
- }
-
-#define CHECK_PIXEL_PTR(n) \
- if ((int32)pixelPtr + n > _surface->w * _surface->h) { \
- warning ("Problem: pixel ptr = %d, pixel limit = %d", pixelPtr + n, _surface->w * _surface->h); \
- return; \
- } \
-
-void QTRLEDecoder::decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
- uint32 pixelPtr = 0;
- byte *rgb = (byte *)_surface->pixels;
-
- while (linesToChange) {
- CHECK_STREAM_PTR(2);
- byte skip = stream->readByte();
- int8 rleCode = stream->readSByte();
-
- if (rleCode == 0)
- break;
-
- if (skip & 0x80) {
- linesToChange--;
- rowPtr += _surface->w;
- pixelPtr = rowPtr + 2 * (skip & 0x7f);
- } else
- pixelPtr += 2 * skip;
-
- if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
- // get the next 2 bytes from the stream, treat them as groups of 8 pixels, and output them rleCode times */
- CHECK_STREAM_PTR(2);
- byte pi0 = stream->readByte();
- byte pi1 = stream->readByte();
- CHECK_PIXEL_PTR(rleCode * 2);
-
- while (rleCode--) {
- rgb[pixelPtr++] = pi0;
- rgb[pixelPtr++] = pi1;
- }
- } else {
- // copy the same pixel directly to output 2 times
- rleCode *= 2;
- CHECK_STREAM_PTR(rleCode);
- CHECK_PIXEL_PTR(rleCode);
-
- while (rleCode--)
- rgb[pixelPtr++] = stream->readByte();
- }
- }
-}
-
-void QTRLEDecoder::decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp) {
- uint32 pixelPtr = 0;
- byte *rgb = (byte *)_surface->pixels;
- byte numPixels = (bpp == 4) ? 8 : 16;
-
- while (linesToChange--) {
- CHECK_STREAM_PTR(2);
- pixelPtr = rowPtr + (numPixels * (stream->readByte() - 1));
-
- for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
- if (rleCode == 0) {
- // there's another skip code in the stream
- CHECK_STREAM_PTR(1);
- pixelPtr += (numPixels * (stream->readByte() - 1));
- } else if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
-
- // get the next 4 bytes from the stream, treat them as palette indices, and output them rleCode times */
- CHECK_STREAM_PTR(4);
-
- byte pi[16]; // 16 palette indices
-
- for (int8 i = numPixels - 1; i >= 0; i--) {
- pi[numPixels - 1 - i] = (stream->readByte() >> ((i * bpp) & 0x07)) & ((1 << bpp) - 1);
-
- // FIXME: Is this right?
- //stream_ptr += ((i & ((num_pixels>>2)-1)) == 0);
- if ((i & ((numPixels >> 2) - 1)) == 0)
- stream->readByte();
- }
-
- CHECK_PIXEL_PTR(rleCode * numPixels);
-
- while (rleCode--)
- for (byte i = 0; i < numPixels; i++)
- rgb[pixelPtr++] = pi[i];
- } else {
- // copy the same pixel directly to output 4 times
- rleCode *= 4;
- CHECK_STREAM_PTR(rleCode);
- CHECK_PIXEL_PTR(rleCode * (numPixels >> 2));
-
- while (rleCode--) {
- byte temp = stream->readByte();
- if (bpp == 4) {
- rgb[pixelPtr++] = (temp >> 4) & 0x0f;
- rgb[pixelPtr++] = temp & 0x0f;
- } else {
- rgb[pixelPtr++] = (temp >> 6) & 0x03;
- rgb[pixelPtr++] = (temp >> 4) & 0x03;
- rgb[pixelPtr++] = (temp >> 2) & 0x03;
- rgb[pixelPtr++] = temp & 0x03;
- }
- }
- }
- }
-
- rowPtr += _surface->w;
- }
-}
-
-void QTRLEDecoder::decode8(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
- uint32 pixelPtr = 0;
- byte *rgb = (byte *)_surface->pixels;
-
- while (linesToChange--) {
- CHECK_STREAM_PTR(2);
- pixelPtr = rowPtr + 4 * (stream->readByte() - 1);
-
- for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
- if (rleCode == 0) {
- // there's another skip code in the stream
- CHECK_STREAM_PTR(1);
- pixelPtr += 4 * (stream->readByte() - 1);
- } else if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
-
- // get the next 4 bytes from the stream, treat them as palette indices, and output them rleCode times
- CHECK_STREAM_PTR(4);
-
- byte pi[4]; // 4 palette indexes
-
- for (byte i = 0; i < 4; i++)
- pi[i] = stream->readByte();
-
- CHECK_PIXEL_PTR(rleCode * 4);
-
- while (rleCode--)
- for (byte i = 0; i < 4; i++)
- rgb[pixelPtr++] = pi[i];
- } else {
- // copy the same pixel directly to output 4 times
- rleCode *= 4;
- CHECK_STREAM_PTR(rleCode);
- CHECK_PIXEL_PTR(rleCode);
-
- while (rleCode--)
- rgb[pixelPtr++] = stream->readByte();
- }
- }
-
- rowPtr += _surface->w;
- }
-}
-
-void QTRLEDecoder::decode16(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
- uint32 pixelPtr = 0;
- OverlayColor *rgb = (OverlayColor *)_surface->pixels;
-
- while (linesToChange--) {
- CHECK_STREAM_PTR(2);
- pixelPtr = rowPtr + stream->readByte() - 1;
-
- for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
- if (rleCode == 0) {
- // there's another skip code in the stream
- CHECK_STREAM_PTR(1);
- pixelPtr += stream->readByte() - 1;
- } else if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
- CHECK_STREAM_PTR(2);
-
- uint16 rgb16 = stream->readUint16BE();
-
- CHECK_PIXEL_PTR(rleCode);
-
- while (rleCode--) {
- // Convert from RGB555 to the format specified by the Overlay
- byte r = 0, g = 0, b = 0;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(rgb16, r, g, b);
- rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
- }
- } else {
- CHECK_STREAM_PTR(rleCode * 2);
- CHECK_PIXEL_PTR(rleCode);
-
- // copy pixels directly to output
- while (rleCode--) {
- uint16 rgb16 = stream->readUint16BE();
-
- // Convert from RGB555 to the format specified by the Overlay
- byte r = 0, g = 0, b = 0;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(rgb16, r, g, b);
- rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
- }
- }
- }
-
- rowPtr += _surface->w;
- }
-}
-
-void QTRLEDecoder::decode24(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
- uint32 pixelPtr = 0;
- OverlayColor *rgb = (OverlayColor *)_surface->pixels;
-
- while (linesToChange--) {
- CHECK_STREAM_PTR(2);
- pixelPtr = rowPtr + stream->readByte() - 1;
-
- for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
- if (rleCode == 0) {
- // there's another skip code in the stream
- CHECK_STREAM_PTR(1);
- pixelPtr += stream->readByte() - 1;
- } else if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
-
- CHECK_STREAM_PTR(3);
-
- byte r = stream->readByte();
- byte g = stream->readByte();
- byte b = stream->readByte();
-
- CHECK_PIXEL_PTR(rleCode);
-
- while (rleCode--)
- rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
- } else {
- CHECK_STREAM_PTR(rleCode * 3);
- CHECK_PIXEL_PTR(rleCode);
-
- // copy pixels directly to output
- while (rleCode--) {
- byte r = stream->readByte();
- byte g = stream->readByte();
- byte b = stream->readByte();
- rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
- }
- }
- }
-
- rowPtr += _surface->w;
- }
-}
-
-void QTRLEDecoder::decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
- uint32 pixelPtr = 0;
- OverlayColor *rgb = (OverlayColor *)_surface->pixels;
-
- while (linesToChange--) {
- CHECK_STREAM_PTR(2);
- pixelPtr = rowPtr + stream->readByte() - 1;
-
- for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
- if (rleCode == 0) {
- // there's another skip code in the stream
- CHECK_STREAM_PTR(1);
- pixelPtr += stream->readByte() - 1;
- } else if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
-
- CHECK_STREAM_PTR(4);
-
- byte a = stream->readByte();
- byte r = stream->readByte();
- byte g = stream->readByte();
- byte b = stream->readByte();
-
- CHECK_PIXEL_PTR(rleCode);
-
- while (rleCode--)
- rgb[pixelPtr++] = _pixelFormat.ARGBToColor(a, r, g, b);
- } else {
- CHECK_STREAM_PTR(rleCode * 4);
- CHECK_PIXEL_PTR(rleCode);
-
- // copy pixels directly to output
- while (rleCode--) {
- byte a = stream->readByte();
- byte r = stream->readByte();
- byte g = stream->readByte();
- byte b = stream->readByte();
- rgb[pixelPtr++] = _pixelFormat.ARGBToColor(a, r, g, b);
- }
- }
- }
-
- rowPtr += _surface->w;
- }
-}
-
-Graphics::Surface *QTRLEDecoder::decodeImage(Common::SeekableReadStream *stream) {
- uint16 start_line = 0;
- uint16 height = _surface->h;
-
- // check if this frame is even supposed to change
- if (stream->size() < 8)
- return _surface;
-
- // start after the chunk size
- stream->readUint32BE();
-
- // fetch the header
- uint16 header = stream->readUint16BE();
-
- // if a header is present, fetch additional decoding parameters
- if (header & 8) {
- if(stream->size() < 14)
- return _surface;
- start_line = stream->readUint16BE();
- stream->readUint16BE(); // Unknown
- height = stream->readUint16BE();
- stream->readUint16BE(); // Unknown
- }
-
- uint32 row_ptr = _surface->w * start_line;
-
- switch (_bitsPerPixel) {
- case 1:
- case 33:
- decode1(stream, row_ptr, height);
- break;
- case 2:
- case 34:
- decode2_4(stream, row_ptr, height, 2);
- break;
- case 4:
- case 36:
- decode2_4(stream, row_ptr, height, 4);
- break;
- case 8:
- case 40:
- decode8(stream, row_ptr, height);
- break;
- case 16:
- decode16(stream, row_ptr, height);
- break;
- case 24:
- decode24(stream, row_ptr, height);
- break;
- case 32:
- decode32(stream, row_ptr, height);
- break;
- default:
- error ("Unsupported bits per pixel %d", _bitsPerPixel);
- }
-
- return _surface;
-}
-
-QTRLEDecoder::~QTRLEDecoder() {
- _surface->free();
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/qtrle.h b/engines/mohawk/video/qtrle.h
deleted file mode 100644
index 2832bd6b24..0000000000
--- a/engines/mohawk/video/qtrle.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_QTRLE_H
-#define MOHAWK_QTRLE_H
-
-#include "graphics/pixelformat.h"
-#include "graphics/video/codecs/codec.h"
-
-namespace Mohawk {
-
-class QTRLEDecoder : public Graphics::Codec {
-public:
- QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel);
- ~QTRLEDecoder();
-
- Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
- Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
-
-private:
- byte _bitsPerPixel;
-
- Graphics::Surface *_surface;
- Graphics::PixelFormat _pixelFormat;
-
- void decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
- void decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp);
- void decode8(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
- void decode16(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
- void decode24(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
- void decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/video/rpza.cpp b/engines/mohawk/video/rpza.cpp
deleted file mode 100644
index f48c055ae2..0000000000
--- a/engines/mohawk/video/rpza.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
- // Based off ffmpeg's RPZA decoder
-
-#include "mohawk/video/rpza.h"
-
-#include "common/system.h"
-#include "graphics/colormasks.h"
-
-namespace Mohawk {
-
-RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Graphics::Codec() {
- _pixelFormat = g_system->getScreenFormat();
-
- // We need to increase the surface size to a multiple of 4
- uint16 wMod = width % 4;
- if(wMod != 0)
- width += 4 - wMod;
-
- debug(2, "RPZA corrected width: %d", width);
-
- _surface = new Graphics::Surface();
- _surface->create(width, height, _pixelFormat.bytesPerPixel);
-}
-
-#define ADVANCE_BLOCK() \
- pixelPtr += 4; \
- if (pixelPtr >= _surface->w) { \
- pixelPtr = 0; \
- rowPtr += _surface->w * 4; \
- } \
- totalBlocks--; \
- if (totalBlocks < 0) \
- error("block counter just went negative (this should not happen)") \
-
-// Convert from RGB555 to the format specified by the screen
-#define PUT_PIXEL(color) \
- if ((int32)blockPtr < _surface->w * _surface->h) { \
- byte r = 0, g = 0, b = 0; \
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(color, r, g, b); \
- if (_pixelFormat.bytesPerPixel == 2) \
- *((uint16 *)_surface->pixels + blockPtr) = _pixelFormat.RGBToColor(r, g, b); \
- else \
- *((uint32 *)_surface->pixels + blockPtr) = _pixelFormat.RGBToColor(r, g, b); \
- } \
- blockPtr++
-
-Graphics::Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) {
- uint16 colorA = 0, colorB = 0;
- uint16 color4[4];
-
- uint32 rowPtr = 0;
- uint32 pixelPtr = 0;
- uint32 blockPtr = 0;
- uint32 rowInc = _surface->w - 4;
- uint16 ta;
- uint16 tb;
-
- // First byte is always 0xe1. Warn if it's different
- byte firstByte = stream->readByte();
- if (firstByte != 0xe1)
- warning("First RPZA chunk byte is 0x%02x instead of 0xe1", firstByte);
-
- // Get chunk size, ingnoring first byte
- uint32 chunkSize = stream->readUint16BE() << 8;
- chunkSize += stream->readByte();
-
- // If length mismatch use size from MOV file and try to decode anyway
- if (chunkSize != (uint32)stream->size()) {
- warning("MOV chunk size != encoded chunk size; using MOV chunk size");
- chunkSize = stream->size();
- }
-
- // Number of 4x4 blocks in frame
- int32 totalBlocks = ((_surface->w + 3) / 4) * ((_surface->h + 3) / 4);
-
- // Process chunk data
- while ((uint32)stream->pos() < chunkSize) {
- byte opcode = stream->readByte(); // Get opcode
- byte numBlocks = (opcode & 0x1f) + 1; // Extract block counter from opcode
-
- // If opcode MSbit is 0, we need more data to decide what to do
- if ((opcode & 0x80) == 0) {
- colorA = (opcode << 8) | stream->readByte();
- opcode = 0;
- if (stream->readByte() & 0x80) {
- // Must behave as opcode 110xxxxx, using colorA computed
- // above. Use fake opcode 0x20 to enter switch block at
- // the right place
- opcode = 0x20;
- numBlocks = 1;
- }
- stream->seek(-1, SEEK_CUR);
- }
-
- switch (opcode & 0xe0) {
- case 0x80: // Skip blocks
- while (numBlocks--) {
- ADVANCE_BLOCK();
- }
- break;
- case 0xa0: // Fill blocks with one color
- colorA = stream->readUint16BE();
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
- for (byte pixel_x = 0; pixel_x < 4; pixel_x++) {
- PUT_PIXEL(colorA);
- }
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // Fill blocks with 4 colors
- case 0xc0:
- colorA = stream->readUint16BE();
- case 0x20:
- colorB = stream->readUint16BE();
-
- // Sort out the colors
- color4[0] = colorB;
- color4[1] = 0;
- color4[2] = 0;
- color4[3] = colorA;
-
- // Red components
- ta = (colorA >> 10) & 0x1F;
- tb = (colorB >> 10) & 0x1F;
- color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10;
- color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10;
-
- // Green components
- ta = (colorA >> 5) & 0x1F;
- tb = (colorB >> 5) & 0x1F;
- color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5;
- color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5;
-
- // Blue components
- ta = colorA & 0x1F;
- tb = colorB & 0x1F;
- color4[1] |= ((11 * ta + 21 * tb) >> 5);
- color4[2] |= ((21 * ta + 11 * tb) >> 5);
-
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
- byte index = stream->readByte();
- for (byte pixel_x = 0; pixel_x < 4; pixel_x++){
- byte idx = (index >> (2 * (3 - pixel_x))) & 0x03;
- PUT_PIXEL(color4[idx]);
- }
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // Fill block with 16 colors
- case 0x00:
- blockPtr = rowPtr + pixelPtr;
- for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
- for (byte pixel_x = 0; pixel_x < 4; pixel_x++){
- // We already have color of upper left pixel
- if (pixel_y != 0 || pixel_x != 0)
- colorA = stream->readUint16BE();
-
- PUT_PIXEL(colorA);
- }
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- break;
-
- // Unknown opcode
- default:
- error("Unknown opcode %02x in rpza chunk", opcode);
- }
- }
-
- return _surface;
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/smc.cpp b/engines/mohawk/video/smc.cpp
deleted file mode 100644
index 4a0d16dfcc..0000000000
--- a/engines/mohawk/video/smc.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-// Based off ffmpeg's SMC decoder
-
-#include "mohawk/video/smc.h"
-
-namespace Mohawk {
-
-#define GET_BLOCK_COUNT() \
- (opcode & 0x10) ? (1 + stream->readByte()) : 1 + (opcode & 0x0F);
-
-#define ADVANCE_BLOCK() \
-{ \
- pixelPtr += 4; \
- if (pixelPtr >= _surface->w) { \
- pixelPtr = 0; \
- rowPtr += _surface->w * 4; \
- } \
- totalBlocks--; \
- if (totalBlocks < 0) { \
- warning("block counter just went negative (this should not happen)"); \
- return _surface; \
- } \
-}
-
-SMCDecoder::SMCDecoder(uint16 width, uint16 height) {
- _surface = new Graphics::Surface();
- _surface->create(width, height, 1);
-}
-
-Graphics::Surface *SMCDecoder::decodeImage(Common::SeekableReadStream *stream) {
- byte *pixels = (byte *)_surface->pixels;
-
- uint32 numBlocks = 0;
- uint32 colorFlags = 0;
- uint32 colorFlagsA = 0;
- uint32 colorFlagsB = 0;
-
- const uint16 rowInc = _surface->w - 4;
- int32 rowPtr = 0;
- int32 pixelPtr = 0;
- uint32 blockPtr = 0;
- uint32 prevBlockPtr = 0;
- uint32 prevBlockPtr1 = 0, prevBlockPtr2 = 0;
- byte prevBlockFlag = false;
- byte pixel = 0;
-
- uint32 colorPairIndex = 0;
- uint32 colorQuadIndex = 0;
- uint32 colorOctetIndex = 0;
- uint32 colorTableIndex = 0; // indices to color pair, quad, or octet tables
-
- int32 chunkSize = stream->readUint32BE() & 0x00FFFFFF;
- if (chunkSize != stream->size())
- warning("MOV chunk size != SMC chunk size (%d != %d); ignoring SMC chunk size", chunkSize, stream->size());
-
- int32 totalBlocks = ((_surface->w + 3) / 4) * ((_surface->h + 3) / 4);
-
- // traverse through the blocks
- while (totalBlocks != 0) {
- // sanity checks
-
- // make sure stream ptr hasn't gone out of bounds
- if (stream->pos() > stream->size()) {
- warning("SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)", stream->pos(), stream->size());
- return _surface;
- }
-
- // make sure the row pointer hasn't gone wild
- if (rowPtr >= _surface->w * _surface->h) {
- warning("SMC decoder just went out of bounds (row ptr = %d, size = %d)", rowPtr, _surface->w * _surface->h);
- return _surface;
- }
-
- byte opcode = stream->readByte();
-
- switch (opcode & 0xF0) {
- // skip n blocks
- case 0x00:
- case 0x10:
- numBlocks = GET_BLOCK_COUNT();
- while (numBlocks--) {
- ADVANCE_BLOCK();
- }
- break;
-
- // repeat last block n times
- case 0x20:
- case 0x30:
- numBlocks = GET_BLOCK_COUNT();
-
- // sanity check
- if (rowPtr == 0 && pixelPtr == 0) {
- warning("encountered repeat block opcode (%02X) but no blocks rendered yet", opcode & 0xF0);
- break;
- }
-
- // figure out where the previous block started
- if (pixelPtr == 0)
- prevBlockPtr1 = (rowPtr - _surface->w * 4) + _surface->w - 4;
- else
- prevBlockPtr1 = rowPtr + pixelPtr - 4;
-
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- prevBlockPtr = prevBlockPtr1;
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++)
- pixels[blockPtr++] = pixels[prevBlockPtr++];
- blockPtr += rowInc;
- prevBlockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // repeat previous pair of blocks n times
- case 0x40:
- case 0x50:
- numBlocks = GET_BLOCK_COUNT();
- numBlocks *= 2;
-
- // sanity check
- if (rowPtr == 0 && pixelPtr < 2 * 4) {
- warning("encountered repeat block opcode (%02X) but not enough blocks rendered yet", opcode & 0xF0);
- break;
- }
-
- // figure out where the previous 2 blocks started
- if (pixelPtr == 0)
- prevBlockPtr1 = (rowPtr - _surface->w * 4) + _surface->w - 4 * 2;
- else if (pixelPtr == 4)
- prevBlockPtr1 = (rowPtr - _surface->w * 4) + rowInc;
- else
- prevBlockPtr1 = rowPtr + pixelPtr - 4 * 2;
-
- if (pixelPtr == 0)
- prevBlockPtr2 = (rowPtr - _surface->w * 4) + rowInc;
- else
- prevBlockPtr2 = rowPtr + pixelPtr - 4;
-
- prevBlockFlag = 0;
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
-
- if (prevBlockFlag)
- prevBlockPtr = prevBlockPtr2;
- else
- prevBlockPtr = prevBlockPtr1;
-
- prevBlockFlag = !prevBlockFlag;
-
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++)
- pixels[blockPtr++] = pixels[prevBlockPtr++];
-
- blockPtr += rowInc;
- prevBlockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // 1-color block encoding
- case 0x60:
- case 0x70:
- numBlocks = GET_BLOCK_COUNT();
- pixel = stream->readByte();
-
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++)
- pixels[blockPtr++] = pixel;
-
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // 2-color block encoding
- case 0x80:
- case 0x90:
- numBlocks = (opcode & 0x0F) + 1;
-
- // figure out which color pair to use to paint the 2-color block
- if ((opcode & 0xF0) == 0x80) {
- // fetch the next 2 colors from bytestream and store in next
- // available entry in the color pair table
- for (byte i = 0; i < CPAIR; i++) {
- pixel = stream->readByte();
- colorTableIndex = CPAIR * colorPairIndex + i;
- _colorPairs[colorTableIndex] = pixel;
- }
-
- // this is the base index to use for this block
- colorTableIndex = CPAIR * colorPairIndex;
- colorPairIndex++;
-
- // wraparound
- if (colorPairIndex == COLORS_PER_TABLE)
- colorPairIndex = 0;
- } else
- colorTableIndex = CPAIR * stream->readByte();
-
- while (numBlocks--) {
- colorFlags = stream->readUint16BE();
- uint16 flagMask = 0x8000;
- blockPtr = rowPtr + pixelPtr;
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++) {
- if (colorFlags & flagMask)
- pixel = colorTableIndex + 1;
- else
- pixel = colorTableIndex;
-
- flagMask >>= 1;
- pixels[blockPtr++] = _colorPairs[pixel];
- }
-
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // 4-color block encoding
- case 0xA0:
- case 0xB0:
- numBlocks = (opcode & 0x0F) + 1;
-
- // figure out which color quad to use to paint the 4-color block
- if ((opcode & 0xF0) == 0xA0) {
- // fetch the next 4 colors from bytestream and store in next
- // available entry in the color quad table
- for (byte i = 0; i < CQUAD; i++) {
- pixel = stream->readByte();
- colorTableIndex = CQUAD * colorQuadIndex + i;
- _colorQuads[colorTableIndex] = pixel;
- }
-
- // this is the base index to use for this block
- colorTableIndex = CQUAD * colorQuadIndex;
- colorQuadIndex++;
-
- // wraparound
- if (colorQuadIndex == COLORS_PER_TABLE)
- colorQuadIndex = 0;
- } else
- colorTableIndex = CQUAD * stream->readByte();
-
- while (numBlocks--) {
- colorFlags = stream->readUint32BE();
-
- // flag mask actually acts as a bit shift count here
- byte flagMask = 30;
- blockPtr = rowPtr + pixelPtr;
-
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++) {
- pixel = colorTableIndex + ((colorFlags >> flagMask) & 0x03);
- flagMask -= 2;
- pixels[blockPtr++] = _colorQuads[pixel];
- }
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // 8-color block encoding
- case 0xC0:
- case 0xD0:
- numBlocks = (opcode & 0x0F) + 1;
-
- // figure out which color octet to use to paint the 8-color block
- if ((opcode & 0xF0) == 0xC0) {
- // fetch the next 8 colors from bytestream and store in next
- // available entry in the color octet table
- for (byte i = 0; i < COCTET; i++) {
- pixel = stream->readByte();
- colorTableIndex = COCTET * colorOctetIndex + i;
- _colorOctets[colorTableIndex] = pixel;
- }
-
- // this is the base index to use for this block
- colorTableIndex = COCTET * colorOctetIndex;
- colorOctetIndex++;
-
- // wraparound
- if (colorOctetIndex == COLORS_PER_TABLE)
- colorOctetIndex = 0;
- } else
- colorTableIndex = COCTET * stream->readByte();
-
- while (numBlocks--) {
- /*
- For this input of 6 hex bytes:
- 01 23 45 67 89 AB
- Mangle it to this output:
- flags_a = xx012456, flags_b = xx89A37B
- */
-
- // build the color flags
- byte flagData[6];
- stream->read(flagData, 6);
-
- colorFlagsA = ((READ_BE_UINT16(flagData) & 0xFFF0) << 8) | (READ_BE_UINT16(flagData + 2) >> 4);
- colorFlagsB = ((READ_BE_UINT16(flagData + 4) & 0xFFF0) << 8) | ((flagData[1] & 0xF) << 8) |
- ((flagData[3] & 0xF) << 4) | (flagData[5] & 0xf);
-
- colorFlags = colorFlagsA;
-
- // flag mask actually acts as a bit shift count here
- byte flagMask = 21;
- blockPtr = rowPtr + pixelPtr;
- for (byte y = 0; y < 4; y++) {
- // reload flags at third row (iteration y == 2)
- if (y == 2) {
- colorFlags = colorFlagsB;
- flagMask = 21;
- }
-
- for (byte x = 0; x < 4; x++) {
- pixel = colorTableIndex + ((colorFlags >> flagMask) & 0x07);
- flagMask -= 3;
- pixels[blockPtr++] = _colorOctets[pixel];
- }
-
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // 16-color block encoding (every pixel is a different color)
- case 0xE0:
- numBlocks = (opcode & 0x0F) + 1;
-
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++)
- pixels[blockPtr++] = stream->readByte();
-
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- case 0xF0:
- warning("0xF0 opcode seen in SMC chunk (contact the developers)");
- break;
- }
- }
-
- return _surface;
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/smc.h b/engines/mohawk/video/smc.h
deleted file mode 100644
index c52226100e..0000000000
--- a/engines/mohawk/video/smc.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_VIDEO_SMC_H
-#define MOHAWK_VIDEO_SMC_H
-
-#include "graphics/video/codecs/codec.h"
-
-namespace Mohawk {
-
-enum {
- CPAIR = 2,
- CQUAD = 4,
- COCTET = 8,
- COLORS_PER_TABLE = 256
-};
-
-class SMCDecoder : public Graphics::Codec {
-public:
- SMCDecoder(uint16 width, uint16 height);
- ~SMCDecoder() { delete _surface; }
-
- Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
- Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
-
-private:
- Graphics::Surface *_surface;
-
- // SMC color tables
- byte _colorPairs[COLORS_PER_TABLE * CPAIR];
- byte _colorQuads[COLORS_PER_TABLE * CQUAD];
- byte _colorOctets[COLORS_PER_TABLE * COCTET];
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index 17254cf424..d6dd9feb19 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -329,7 +329,7 @@ bool Input::translateGameInput() {
bool noWalk = z->_flags & kFlagsNoWalk; // check the explicit no-walk flag
if (_gameType == GType_BRA) {
// action performed on object marked for self-use do not need walk in BRA
- noWalk |= z->_flags & kFlagsYourself;
+ noWalk |= ((z->_flags & kFlagsYourself) != 0);
}
if (noWalk) {
diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp
index be72cf73a1..ff24a06ceb 100644
--- a/engines/parallaction/parser_ns.cpp
+++ b/engines/parallaction/parser_ns.cpp
@@ -286,6 +286,7 @@ void LocationParser_ns::parseAnimation(AnimationList &list, char *name) {
debugC(5, kDebugParser, "parseAnimation(name: %s)", name);
if (_vm->_location.findAnimation(name)) {
+ _zoneProg++;
_script->skip("endanimation");
return;
}
@@ -1305,6 +1306,7 @@ void LocationParser_ns::parseZone(ZoneList &list, char *name) {
debugC(5, kDebugParser, "parseZone(name: %s)", name);
if (_vm->_location.findZone(name)) {
+ _zoneProg++;
_script->skip("endzone");
return;
}
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index 2911d9c451..ed8a9055ba 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -330,20 +330,6 @@ Common::Error SagaEngine::run() {
syncSoundSettings();
-
-#if 0
- // FIXME: Disabled this code for now. We want to get rid of OSystem::kFeatureAutoComputeDirtyRects
- // and this is the last place to make use of it. We need to find out whether doing
- // so causes any regressions. If it does, we can reenable it, if not, we can remove
- // this code in 0.13.0.
-
- // FIXME: This is the ugly way of reducing redraw overhead. It works
- // well for 320x200 but it's unclear how well it will work for
- // 640x480.
- if (getGameId() == GID_ITE)
- _system->setFeatureState(OSystem::kFeatureAutoComputeDirtyRects, true);
-#endif
-
int msec = 0;
_previousTicks = _system->getMillis();
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 540b7c84d8..2549be9403 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -47,6 +47,7 @@
#include "sci/graphics/cursor.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/paint.h"
+#include "sci/graphics/paint16.h"
#include "sci/graphics/palette.h"
#include "sci/parser/vocabulary.h"
@@ -74,10 +75,10 @@ Console::Console(SciEngine *engine) : GUI::Debugger() {
// Variables
DVar_Register("sleeptime_factor", &g_debug_sleeptime_factor, DVAR_INT, 0);
- DVar_Register("gc_interval", &script_gc_interval, DVAR_INT, 0);
+ DVar_Register("gc_interval", &engine->_gamestate->script_gc_interval, DVAR_INT, 0);
DVar_Register("simulated_key", &g_debug_simulated_key, DVAR_INT, 0);
DVar_Register("track_mouse_clicks", &g_debug_track_mouse_clicks, DVAR_BOOL, 0);
- DVar_Register("script_abort_flag", &script_abort_flag, DVAR_INT, 0);
+ DVar_Register("script_abort_flag", &_engine->_gamestate->script_abort_flag, DVAR_INT, 0);
// General
DCmd_Register("help", WRAP_METHOD(Console, cmdHelp));
@@ -104,6 +105,7 @@ Console::Console(SciEngine *engine) : GUI::Debugger() {
DCmd_Register("resource_types", WRAP_METHOD(Console, cmdResourceTypes));
DCmd_Register("list", WRAP_METHOD(Console, cmdList));
DCmd_Register("hexgrep", WRAP_METHOD(Console, cmdHexgrep));
+ DCmd_Register("verify_scripts", WRAP_METHOD(Console, cmdVerifyScripts));
// Game
DCmd_Register("save_game", WRAP_METHOD(Console, cmdSaveGame));
DCmd_Register("restore_game", WRAP_METHOD(Console, cmdRestoreGame));
@@ -276,8 +278,8 @@ void Console::postEnter() {
#if 0
// Unused
#define LOOKUP_SPECIES(species) (\
- (species >= 1000) ? species : *(s->_classtable[species].scriptposp) \
- + s->_classtable[species].class_offset)
+ (species >= 1000) ? species : *(s->_classTable[species].scriptposp) \
+ + s->_classTable[species].class_offset)
#endif
bool Console::cmdHelp(int argc, const char **argv) {
@@ -323,6 +325,7 @@ bool Console::cmdHelp(int argc, const char **argv) {
DebugPrintf(" resource_types - Shows the valid resource types\n");
DebugPrintf(" list - Lists all the resources of a given type\n");
DebugPrintf(" hexgrep - Searches some resources for a particular sequence of bytes, represented as hexadecimal numbers\n");
+ DebugPrintf(" verify_scripts - Performs sanity checks on SCI1.1-SCI2.1 game scripts (e.g. if they're up to 64KB in total)\n");
DebugPrintf("\n");
DebugPrintf("Game:\n");
DebugPrintf(" save_game - Saves the current game state to the hard disk\n");
@@ -421,10 +424,9 @@ const char *selector_name(EngineState *s, int selector) {
bool Console::cmdGetVersion(int argc, const char **argv) {
const char *viewTypeDesc[] = { "Unknown", "EGA", "VGA", "VGA SCI1.1", "Amiga" };
- EngineState *s = _engine->_gamestate;
bool hasVocab997 = g_sci->getResMan()->testResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SELECTORS)) ? true : false;
- DebugPrintf("Game ID: %s\n", s->_gameId.c_str());
+ DebugPrintf("Game ID: %s\n", _engine->getGameID());
DebugPrintf("Emulated interpreter version: %s\n", getSciVersionDesc(getSciVersion()));
DebugPrintf("\n");
DebugPrintf("Detected features:\n");
@@ -593,14 +595,14 @@ bool Console::cmdSetParseNodes(int argc, const char **argv) {
}
bool Console::cmdRegisters(int argc, const char **argv) {
+ EngineState *s = _engine->_gamestate;
DebugPrintf("Current register values:\n");
- DebugPrintf("acc=%04x:%04x prev=%04x:%04x &rest=%x\n", PRINT_REG(_engine->_gamestate->r_acc), PRINT_REG(_engine->_gamestate->r_prev), scriptState.restAdjust);
+ DebugPrintf("acc=%04x:%04x prev=%04x:%04x &rest=%x\n", PRINT_REG(s->r_acc), PRINT_REG(s->r_prev), s->restAdjust);
- if (!_engine->_gamestate->_executionStack.empty()) {
- EngineState *s = _engine->_gamestate; // for PRINT_STK
+ if (!s->_executionStack.empty()) {
DebugPrintf("pc=%04x:%04x obj=%04x:%04x fp=ST:%04x sp=ST:%04x\n",
- PRINT_REG(scriptState.xs->addr.pc), PRINT_REG(scriptState.xs->objp),
- (unsigned)(scriptState.xs->fp - s->stack_base), (unsigned)(scriptState.xs->sp - s->stack_base));
+ PRINT_REG(s->xs->addr.pc), PRINT_REG(s->xs->objp),
+ (unsigned)(s->xs->fp - s->stack_base), (unsigned)(s->xs->sp - s->stack_base));
} else
DebugPrintf("<no execution stack: pc,obj,fp omitted>\n");
@@ -811,6 +813,40 @@ bool Console::cmdHexgrep(int argc, const char **argv) {
return true;
}
+bool Console::cmdVerifyScripts(int argc, const char **argv) {
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ DebugPrintf("This script check is only meant for SCI1.1-SCI2.1 games\n");
+ return true;
+ }
+
+ Common::List<ResourceId> *resources = _engine->getResMan()->listResources(kResourceTypeScript);
+ sort(resources->begin(), resources->end(), ResourceIdLess());
+ Common::List<ResourceId>::iterator itr = resources->begin();
+
+ DebugPrintf("%d SCI1.1-SCI2.1 scripts found, performing sanity checks...\n", resources->size());
+
+ Resource *script, *heap;
+ while (itr != resources->end()) {
+ script = _engine->getResMan()->findResource(*itr, false);
+ if (!script)
+ DebugPrintf("Error: script %d couldn't be loaded\n", itr->number);
+
+ heap = _engine->getResMan()->findResource(*itr, false);
+ if (!heap)
+ DebugPrintf("Error: script %d doesn't have a corresponding heap\n", itr->number);
+
+ if (script && heap && (script->size + heap->size > 65535))
+ DebugPrintf("Error: script and heap %d together are larger than 64KB (%d bytes)\n",
+ itr->number, script->size + heap->size);
+
+ ++itr;
+ }
+
+ DebugPrintf("SCI1.1-SCI2.1 script check finished\n");
+
+ return true;
+}
+
bool Console::cmdList(int argc, const char **argv) {
if (argc < 2) {
DebugPrintf("Lists all the resources of a given type\n");
@@ -921,35 +957,19 @@ bool Console::cmdRestoreGame(int argc, const char **argv) {
}
bool Console::cmdRestartGame(int argc, const char **argv) {
- if (argc != 2) {
- DebugPrintf("Restarts the game. There are two ways to restart a SCI game:\n");
- DebugPrintf("%s play - calls the game object's play() method\n", argv[0]);
- DebugPrintf("%s replay - calls the replay() methody\n", argv[0]);
- return true;
- }
-
- if (!scumm_stricmp(argv[1], "play")) {
- _engine->_gamestate->restarting_flags |= SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE;
- } else if (!scumm_stricmp(argv[1], "replay")) {
- _engine->_gamestate->restarting_flags &= ~SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE;
- } else {
- DebugPrintf("Invalid usage of %s\n", argv[0]);
- return true;
- }
-
_engine->_gamestate->restarting_flags |= SCI_GAME_IS_RESTARTING_NOW;
- script_abort_flag = 1;
+ _engine->_gamestate->script_abort_flag = 1;
return false;
}
bool Console::cmdClassTable(int argc, const char **argv) {
DebugPrintf("Available classes:\n");
- for (uint i = 0; i < _engine->_gamestate->_segMan->_classtable.size(); i++) {
- if (_engine->_gamestate->_segMan->_classtable[i].reg.segment) {
+ for (uint i = 0; i < _engine->_gamestate->_segMan->classTableSize(); i++) {
+ if (_engine->_gamestate->_segMan->_classTable[i].reg.segment) {
DebugPrintf(" Class 0x%x at %04x:%04x (script 0x%x)\n", i,
- PRINT_REG(_engine->_gamestate->_segMan->_classtable[i].reg),
- _engine->_gamestate->_segMan->_classtable[i].script);
+ PRINT_REG(_engine->_gamestate->_segMan->_classTable[i].reg),
+ _engine->_gamestate->_segMan->_classTable[i].script);
}
}
@@ -1129,7 +1149,11 @@ bool Console::cmdUndither(int argc, const char **argv) {
bool flag = atoi(argv[1]) ? true : false;
_engine->_gfxScreen->debugUnditherSetState(flag);
- return false;
+ if (flag)
+ DebugPrintf("undithering ENABLED\n");
+ else
+ DebugPrintf("undithering DISABLED\n");
+ return true;
}
bool Console::cmdPicVisualize(int argc, const char **argv) {
@@ -1141,7 +1165,16 @@ bool Console::cmdPicVisualize(int argc, const char **argv) {
bool state = atoi(argv[1]) ? true : false;
- return _engine->_gui->debugEGAdrawingVisualize(state);
+ if (_engine->_resMan->getViewType() == kViewEga) {
+ _engine->_gfxPaint16->debugSetEGAdrawingVisualize(state);
+ if (state)
+ DebugPrintf("picture visualization ENABLED\n");
+ else
+ DebugPrintf("picture visualization DISABLED\n");
+ } else {
+ DebugPrintf("picture visualization only available for EGA games\n");
+ }
+ return true;
}
bool Console::cmdPlayVideo(int argc, const char **argv) {
@@ -1248,13 +1281,13 @@ bool Console::segmentInfo(int nr) {
case SEG_TYPE_SCRIPT: {
Script *scr = (Script *)mobj;
- DebugPrintf("script.%03d locked by %d, bufsize=%d (%x)\n", scr->_nr, scr->getLockers(), (uint)scr->_bufSize, (uint)scr->_bufSize);
- if (scr->_exportTable)
- DebugPrintf(" Exports: %4d at %d\n", scr->_numExports, (int)(((byte *)scr->_exportTable) - ((byte *)scr->_buf)));
+ DebugPrintf("script.%03d locked by %d, bufsize=%d (%x)\n", scr->_nr, scr->getLockers(), (uint)scr->getBufSize(), (uint)scr->getBufSize());
+ if (scr->getExportTable())
+ DebugPrintf(" Exports: %4d at %d\n", scr->getExportsNr(), (int)(((const byte *)scr->getExportTable()) - ((const byte *)scr->_buf)));
else
DebugPrintf(" Exports: none\n");
- DebugPrintf(" Synonyms: %4d\n", scr->_numSynonyms);
+ DebugPrintf(" Synonyms: %4d\n", scr->getSynonymsNr());
if (scr->_localsBlock)
DebugPrintf(" Locals : %4d in segment 0x%x\n", scr->_localsBlock->_locals.size(), scr->_localsSegment);
@@ -1268,7 +1301,7 @@ bool Console::segmentInfo(int nr) {
for (it = scr->_objects.begin(); it != end; ++it) {
DebugPrintf(" ");
// Object header
- Object *obj = _engine->_gamestate->_segMan->getObject(it->_value.getPos());
+ const Object *obj = _engine->_gamestate->_segMan->getObject(it->_value.getPos());
if (obj)
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(it->_value.getPos()),
_engine->_gamestate->_segMan->getObjectName(it->_value.getPos()),
@@ -1315,7 +1348,7 @@ bool Console::segmentInfo(int nr) {
objpos.segment = nr;
DebugPrintf(" [%04x] %s; copy of ", i, _engine->_gamestate->_segMan->getObjectName(objpos));
// Object header
- Object *obj = _engine->_gamestate->_segMan->getObject(ct->_table[i].getPos());
+ const Object *obj = _engine->_gamestate->_segMan->getObject(ct->_table[i].getPos());
if (obj)
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(ct->_table[i].getPos()),
_engine->_gamestate->_segMan->getObjectName(ct->_table[i].getPos()),
@@ -1523,12 +1556,12 @@ bool Console::cmdToggleSound(int argc, const char **argv) {
int handle = id.segment << 16 | id.offset; // frobnicate handle
if (id.segment) {
- SegManager *segMan = _engine->_gamestate->_segMan; // for PUT_SEL32V
+ SegManager *segMan = _engine->_gamestate->_segMan; // for writeSelectorValue
_engine->_gamestate->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
_engine->_gamestate->_sound.sfx_remove_song(handle);
- PUT_SEL32V(segMan, id, SELECTOR(signal), SIGNAL_OFFSET);
- PUT_SEL32V(segMan, id, SELECTOR(nodePtr), 0);
- PUT_SEL32V(segMan, id, SELECTOR(handle), 0);
+ writeSelectorValue(segMan, id, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(segMan, id, SELECTOR(nodePtr), 0);
+ writeSelectorValue(segMan, id, SELECTOR(handle), 0);
}
#else
@@ -1733,14 +1766,15 @@ bool Console::cmdGCNormalize(int argc, const char **argv) {
}
bool Console::cmdVMVarlist(int argc, const char **argv) {
+ EngineState *s = _engine->_gamestate;
const char *varnames[] = {"global", "local", "temp", "param"};
DebugPrintf("Addresses of variables in the VM:\n");
for (int i = 0; i < 4; i++) {
- DebugPrintf("%s vars at %04x:%04x ", varnames[i], PRINT_REG(make_reg(scriptState.variables_seg[i], scriptState.variables[i] - scriptState.variables_base[i])));
- if (scriptState.variables_max)
- DebugPrintf(" total %d", scriptState.variables_max[i]);
+ DebugPrintf("%s vars at %04x:%04x ", varnames[i], PRINT_REG(make_reg(s->variables_seg[i], s->variables[i] - s->variables_base[i])));
+ if (s->variables_max)
+ DebugPrintf(" total %d", s->variables_max[i]);
DebugPrintf("\n");
}
@@ -1758,6 +1792,7 @@ bool Console::cmdVMVars(int argc, const char **argv) {
return true;
}
+ EngineState *s = _engine->_gamestate;
const char *varnames[] = {"global", "local", "temp", "param"};
const char *varabbrev = "gltp";
const char *vartype_pre = strchr(varabbrev, *argv[1]);
@@ -1796,17 +1831,17 @@ bool Console::cmdVMVars(int argc, const char **argv) {
return true;
}
- if ((scriptState.variables_max) && (scriptState.variables_max[vartype] <= idx)) {
- DebugPrintf("Max. index is %d (0x%x)\n", scriptState.variables_max[vartype], scriptState.variables_max[vartype]);
+ if ((s->variables_max) && (s->variables_max[vartype] <= idx)) {
+ DebugPrintf("Max. index is %d (0x%x)\n", s->variables_max[vartype], s->variables_max[vartype]);
return true;
}
switch (argc) {
case 3:
- DebugPrintf("%s var %d == %04x:%04x\n", varnames[vartype], idx, PRINT_REG(scriptState.variables[vartype][idx]));
+ DebugPrintf("%s var %d == %04x:%04x\n", varnames[vartype], idx, PRINT_REG(s->variables[vartype][idx]));
break;
case 4:
- if (parse_reg_t(_engine->_gamestate, argv[3], &scriptState.variables[vartype][idx], true)) {
+ if (parse_reg_t(_engine->_gamestate, argv[3], &s->variables[vartype][idx], true)) {
DebugPrintf("Invalid value/address passed.\n");
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
DebugPrintf("Or pass a decimal or hexadecimal value directly (e.g. 12, 1Ah)\n");
@@ -2039,7 +2074,7 @@ bool Console::cmdViewObject(int argc, const char **argv) {
bool Console::cmdViewActiveObject(int argc, const char **argv) {
DebugPrintf("Information on the currently active object or class:\n");
- printObject(scriptState.xs->objp);
+ printObject(_engine->_gamestate->xs->objp);
return true;
}
@@ -2052,7 +2087,7 @@ bool Console::cmdViewAccumulatorObject(int argc, const char **argv) {
}
bool Console::cmdScriptSteps(int argc, const char **argv) {
- DebugPrintf("Number of executed SCI operations: %d\n", script_step_counter);
+ DebugPrintf("Number of executed SCI operations: %d\n", _engine->_gamestate->script_step_counter);
return true;
}
@@ -2229,8 +2264,8 @@ bool Console::cmdDisassemble(int argc, const char **argv) {
return true;
}
- Object *obj = _engine->_gamestate->_segMan->getObject(objAddr);
- int selector_id = _engine->getKernel()->findSelector(argv[2]);
+ const Object *obj = _engine->_gamestate->_segMan->getObject(objAddr);
+ int selectorId = _engine->getKernel()->findSelector(argv[2]);
reg_t addr;
if (!obj) {
@@ -2238,12 +2273,12 @@ bool Console::cmdDisassemble(int argc, const char **argv) {
return true;
}
- if (selector_id < 0) {
+ if (selectorId < 0) {
DebugPrintf("Not a valid selector name.");
return true;
}
- if (lookup_selector(_engine->_gamestate->_segMan, objAddr, selector_id, NULL, &addr) != kSelectorMethod) {
+ if (lookupSelector(_engine->_gamestate->_segMan, objAddr, selectorId, NULL, &addr) != kSelectorMethod) {
DebugPrintf("Not a method.");
return true;
}
@@ -2323,20 +2358,20 @@ bool Console::cmdSend(int argc, const char **argv) {
}
const char *selector_name = argv[2];
- int selector_id = _engine->getKernel()->findSelector(selector_name);
+ int selectorId = _engine->getKernel()->findSelector(selector_name);
- if (selector_id < 0) {
+ if (selectorId < 0) {
DebugPrintf("Unknown selector: \"%s\"\n", selector_name);
return true;
}
- Object *o = _engine->_gamestate->_segMan->getObject(object);
+ const Object *o = _engine->_gamestate->_segMan->getObject(object);
if (o == NULL) {
DebugPrintf("Address \"%04x:%04x\" is not an object\n", PRINT_REG(object));
return true;
}
- SelectorType selector_type = lookup_selector(_engine->_gamestate->_segMan, object, selector_id, 0, 0);
+ SelectorType selector_type = lookupSelector(_engine->_gamestate->_segMan, object, selectorId, 0, 0);
if (selector_type == kSelectorNone) {
DebugPrintf("Object does not support selector: \"%s\"\n", selector_name);
@@ -2349,7 +2384,7 @@ bool Console::cmdSend(int argc, const char **argv) {
// Create the data block for send_selecor() at the top of the stack:
// [selector_number][argument_counter][arguments...]
StackPtr stackframe = _engine->_gamestate->_executionStack.back().sp;
- stackframe[0] = make_reg(0, selector_id);
+ stackframe[0] = make_reg(0, selectorId);
stackframe[1] = make_reg(0, send_argc);
for (int i = 0; i < send_argc; i++) {
if (parse_reg_t(_engine->_gamestate, argv[3+i], &stackframe[2+i], false)) {
@@ -2696,7 +2731,7 @@ bool Console::cmdQuit(int argc, const char **argv) {
if (!scumm_stricmp(argv[1], "game")) {
// Quit gracefully
- script_abort_flag = 1; // Terminate VM
+ _engine->_gamestate->script_abort_flag = 1; // Terminate VM
g_debugState.seeking = kDebugSeekNothing;
g_debugState.runningStep = 0;
@@ -3021,8 +3056,8 @@ int Console::printNode(reg_t addr) {
int Console::printObject(reg_t pos) {
EngineState *s = _engine->_gamestate; // for the several defines in this function
- Object *obj = s->_segMan->getObject(pos);
- Object *var_container = obj;
+ const Object *obj = s->_segMan->getObject(pos);
+ const Object *var_container = obj;
uint i;
if (!obj) {
@@ -3034,7 +3069,7 @@ int Console::printObject(reg_t pos) {
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(pos), s->_segMan->getObjectName(pos),
obj->getVarCount(), obj->getMethodCount());
- if (!(obj->getInfoSelector().offset & SCRIPT_INFO_CLASS))
+ if (!obj->isClass())
var_container = s->_segMan->getObject(obj->getSuperClassSelector());
DebugPrintf(" -- member variables:\n");
for (i = 0; (uint)i < obj->getVarCount(); i++) {
@@ -3051,7 +3086,7 @@ int Console::printObject(reg_t pos) {
if (!val.segment)
DebugPrintf(" (%d)", val.offset);
- Object *ref = s->_segMan->getObject(val);
+ const Object *ref = s->_segMan->getObject(val);
if (ref)
DebugPrintf(" (%s)", s->_segMan->getObjectName(val));
@@ -3063,7 +3098,7 @@ int Console::printObject(reg_t pos) {
DebugPrintf(" [%03x] %s = %04x:%04x\n", obj->getFuncSelector(i), selector_name(s, obj->getFuncSelector(i)), PRINT_REG(fptr));
}
if (s->_segMan->_heap[pos.segment]->getType() == SEG_TYPE_SCRIPT)
- DebugPrintf("\nOwner script:\t%d\n", s->_segMan->getScript(pos.segment)->_nr);
+ DebugPrintf("\nOwner script: %d\n", s->_segMan->getScript(pos.segment)->_nr);
return 0;
}
diff --git a/engines/sci/console.h b/engines/sci/console.h
index c88795ae26..2b13e03ef6 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -73,6 +73,7 @@ private:
bool cmdResourceTypes(int argc, const char **argv);
bool cmdList(int argc, const char **argv);
bool cmdHexgrep(int argc, const char **argv);
+ bool cmdVerifyScripts(int argc, const char **argv);
// Game
bool cmdSaveGame(int argc, const char **argv);
bool cmdRestoreGame(int argc, const char **argv);
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index beea025aea..1ccfc6bf02 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -120,6 +120,154 @@ static const PlainGameDescriptor SciGameTitles[] = {
{0, 0}
};
+struct OldNewIdTableEntry {
+ const char *oldId;
+ const char *newId;
+ SciVersion version;
+};
+
+static const OldNewIdTableEntry s_oldNewTable[] = {
+ { "arthur", "camelot", SCI_VERSION_NONE },
+ { "brain", "castlebrain", SCI_VERSION_1_MIDDLE }, // Amiga
+ { "brain", "castlebrain", SCI_VERSION_1_LATE },
+ { "demo", "christmas1988", SCI_VERSION_NONE },
+ { "card", "christmas1990", SCI_VERSION_1_EARLY, },
+ { "card", "christmas1992", SCI_VERSION_1_1 },
+ { "RH Budget", "cnick-longbow", SCI_VERSION_NONE },
+ // iceman is the same
+ { "icedemo", "iceman", SCI_VERSION_NONE },
+ // longbow is the same
+ { "eco", "ecoquest", SCI_VERSION_NONE },
+ { "eco2", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 demo
+ { "rain", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 full
+ { "tales", "fairytales", SCI_VERSION_NONE },
+ { "fp", "freddypharkas", SCI_VERSION_NONE },
+ { "emc", "funseeker", SCI_VERSION_NONE },
+ { "gk", "gk1", SCI_VERSION_NONE },
+ // gk2 is the same
+ { "hoyledemo", "hoyle1", SCI_VERSION_NONE },
+ { "cardgames", "hoyle1", SCI_VERSION_NONE },
+ { "solitare", "hoyle2", SCI_VERSION_NONE },
+ // hoyle3 is the same
+ // hoyle4 is the same
+ { "brain", "islandbrain", SCI_VERSION_1_1 },
+ { "demo000", "kq1sci", SCI_VERSION_NONE },
+ { "kq1", "kq1sci", SCI_VERSION_NONE },
+ { "kq4", "kq4sci", SCI_VERSION_NONE },
+ // kq5 is the same
+ // kq6 is the same
+ // kq7 is the same
+ { "mm1", "laurabow", SCI_VERSION_NONE },
+ { "cb1", "laurabow", SCI_VERSION_NONE },
+ { "lb2", "laurabow2", SCI_VERSION_NONE },
+ { "rh", "longbow", SCI_VERSION_NONE },
+ { "ll1", "lsl1sci", SCI_VERSION_NONE },
+ { "lsl1", "lsl1sci", SCI_VERSION_NONE },
+ // lsl2 is the same
+ { "lsl3", "lsl3", SCI_VERSION_NONE },
+ { "ll5", "lsl5", SCI_VERSION_NONE },
+ // lsl5 is the same
+ // lsl6 is the same
+ { "mg", "mothergoose", SCI_VERSION_NONE },
+ { "twisty", "pepper", SCI_VERSION_NONE },
+ { "scary", "phantasmagoria", SCI_VERSION_NONE },
+ // TODO: distinguish the full version of Phantasmagoria from the demo
+ { "pq1", "pq1sci", SCI_VERSION_NONE },
+ { "pq", "pq2", SCI_VERSION_NONE },
+ // pq3 is the same
+ // pq4 is the same
+ { "hq", "qfg1", SCI_VERSION_NONE }, // QFG1 SCI0/EGA
+ { "glory", "qfg1", SCI_VERSION_0_LATE }, // QFG1 SCI0/EGA
+ { "trial", "qfg2", SCI_VERSION_NONE },
+ { "hq2demo", "qfg2", SCI_VERSION_NONE },
+ // rama is the same
+ // TODO: distinguish the full version of rama from the demo
+ { "thegame", "slater", SCI_VERSION_NONE },
+ { "sq1demo", "sq1sci", SCI_VERSION_NONE },
+ { "sq1", "sq1sci", SCI_VERSION_NONE },
+ // sq3 is the same
+ // sq4 is the same
+ // sq5 is the same
+ // sq6 is the same
+ // TODO: distinguish the full version of SQ6 from the demo
+ // torin is the same
+
+
+ // TODO: SCI3 IDs
+
+ { "", "", SCI_VERSION_NONE }
+};
+
+Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, ResourceManager *resMan) {
+ // Convert the id to lower case, so that we match all upper/lower case variants.
+ sierraId.toLowercase();
+
+ // If the game has less than the expected scripts, it's a demo
+ uint32 demoThreshold = 100;
+ // ...but there are some exceptions
+ if (sierraId == "brain" || sierraId == "lsl1" ||
+ sierraId == "mg" || sierraId == "pq" ||
+ sierraId == "jones" ||
+ sierraId == "cardgames" || sierraId == "solitare" ||
+ sierraId == "hoyle3" || sierraId == "hoyle4")
+ demoThreshold = 40;
+ if (sierraId == "fp" || sierraId == "gk" || sierraId == "pq4")
+ demoThreshold = 150;
+
+ Common::List<ResourceId> *resources = resMan->listResources(kResourceTypeScript, -1);
+ if (resources->size() < demoThreshold) {
+ *gameFlags |= ADGF_DEMO;
+
+ // Crazy Nick's Picks
+ if (sierraId == "lsl1" && resources->size() == 34)
+ return "cnick-lsl";
+ if (sierraId == "sq4" && resources->size() == 34)
+ return "cnick-sq";
+
+ // TODO: cnick-kq, cnick-laurabow and cnick-longbow (their resources can't be read)
+
+ // Handle Astrochicken 1 (SQ3) and 2 (SQ4)
+ if (sierraId == "sq3" && resources->size() == 20)
+ return "astrochicken";
+ if (sierraId == "sq4")
+ return "msastrochicken";
+ }
+
+ if (sierraId == "torin" && resources->size() == 226) // Torin's Passage demo
+ *gameFlags |= ADGF_DEMO;
+
+ for (const OldNewIdTableEntry *cur = s_oldNewTable; cur->oldId[0]; ++cur) {
+ if (sierraId == cur->oldId) {
+ // Distinguish same IDs from the SCI version
+ if (cur->version != SCI_VERSION_NONE && cur->version != getSciVersion())
+ continue;
+
+ return cur->newId;
+ }
+ }
+
+ if (sierraId == "glory") {
+ // This could either be qfg1 VGA, qfg3 or qfg4 demo (all SCI1.1),
+ // or qfg4 full (SCI2)
+ // qfg1 VGA doesn't have view 1
+ if (!resMan->testResource(ResourceId(kResourceTypeView, 1)))
+ return "qfg1";
+
+ // qfg4 full is SCI2
+ if (getSciVersion() == SCI_VERSION_2)
+ return "qfg4";
+
+ // qfg4 demo has less than 50 scripts
+ if (resources->size() < 50)
+ return "qfg4";
+
+ // Otherwise it's qfg3
+ return "qfg3";
+ }
+
+ return sierraId;
+}
+
#include "sci/detection_tables.h"
/**
@@ -205,42 +353,6 @@ Common::Language charToScummVMLanguage(const char c) {
}
}
-#define READ_UINT16(ptr) (!resMan->isSci11Mac() ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr))
-
-// Finds the internal ID of the current game from script 0
-Common::String getSierraGameId(ResourceManager *resMan) {
- Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, 0), false);
- // In SCI0-SCI1, the heap is embedded in the script. In SCI1.1+, it's separated
- Resource *heap = 0;
- byte *seeker = 0;
-
- // Seek to the name selector of the first export
- if (getSciVersion() < SCI_VERSION_1_1) {
- const int nameSelector = 3;
- int extraSci0EarlyBytes = (getSciVersion() == SCI_VERSION_0_EARLY) ? 2 : 0;
- byte *exportPtr = script->data + extraSci0EarlyBytes + 4 + 2;
- seeker = script->data + READ_UINT16(script->data + READ_UINT16(exportPtr) + nameSelector * 2);
- } else {
- const int nameSelector = 5 + 3;
- heap = resMan->findResource(ResourceId(kResourceTypeHeap, 0), false);
- byte *exportPtr = script->data + 4 + 2 + 2;
- seeker = heap->data + READ_UINT16(heap->data + READ_UINT16(exportPtr) + nameSelector * 2);
- }
-
- char sierraId[20];
- int i = 0;
- byte curChar = 0;
-
- do {
- curChar = *(seeker + i);
- sierraId[i++] = curChar;
- } while (curChar != 0);
-
- return sierraId;
-}
-
-#undef READ_UINT16
-
const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fslist) const {
bool foundResMap = false;
bool foundRes000 = false;
@@ -261,19 +373,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
filename.toLowercase();
if (filename.contains("resource.map") || filename.contains("resmap.00") || filename.contains("Data1")) {
- // HACK: resource.map is located in the same directory as the other resource files,
- // therefore add the directory here, so that the game files can be opened later on
- // We now add the parent directory temporary to our SearchMan so the engine code
- // used in the detection can access all files via Common::File without any problems.
- // In all branches returning from this function, we need to have a call to
- // SearchMan.remove to remove it from the default directory pool again.
- //
- // A proper solution to remove this hack would be to have the code, which is needed
- // for detection, to operate on Stream objects, so they can be easily called from
- // the detection code. This might be easily to achieve through refactoring the
- // code needed for detection.
- assert(!SearchMan.hasArchive("SCI_detection"));
- SearchMan.addDirectory("SCI_detection", file->getParent());
foundResMap = true;
}
@@ -317,7 +416,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
// If these files aren't found, it can't be SCI
if (!foundResMap && !foundRes000) {
- SearchMan.remove("SCI_detection");
return 0;
}
@@ -325,11 +423,10 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
ViewType gameViews = resMan->getViewType();
// Have we identified the game views? If not, stop here
+ // Can't be SCI (or unsupported SCI views). Pinball Creep by sierra also uses resource.map/resource.000 files
+ // but doesnt share sci format at all, if we dont return 0 here we will detect this game as SCI
if (gameViews == kViewUnknown) {
- SearchMan.remove("SCI_detection");
delete resMan;
- // Can't be SCI (or unsupported SCI views). Pinball Creep by sierra also uses resource.map/resource.000 files
- // but doesnt share sci format at all, if we dont return 0 here we will detect this game as SCI
return 0;
}
@@ -337,7 +434,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
// Is SCI32 compiled in? If not, and this is a SCI32 game,
// stop here
if (getSciVersion() >= SCI_VERSION_2) {
- SearchMan.remove("SCI_detection");
delete resMan;
return (const ADGameDescription *)&s_fallbackDesc;
}
@@ -352,7 +448,15 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
s_fallbackDesc.platform = Common::kPlatformAmiga;
// Determine the game id
- Common::String gameId = convertSierraGameId(getSierraGameId(resMan).c_str(), &s_fallbackDesc.flags, resMan);
+ Common::String sierraGameId = resMan->findSierraGameId();
+
+ // If we don't have a game id, the game is not SCI
+ if (sierraGameId.empty()) {
+ delete resMan;
+ return 0;
+ }
+
+ Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan);
strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
s_fallbackGameIdBuf[sizeof(s_fallbackGameIdBuf) - 1] = 0; // Make sure string is NULL terminated
s_fallbackDesc.gameid = s_fallbackGameIdBuf;
@@ -386,7 +490,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
}
}
- delete resMan;
// Fill in extras field
if (!strcmp(s_fallbackDesc.gameid, "lsl1sci") ||
@@ -394,14 +497,14 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
!strcmp(s_fallbackDesc.gameid, "sq1sci"))
s_fallbackDesc.extra = "VGA Remake";
- if (!strcmp(s_fallbackDesc.gameid, "qfg1") && !Common::File::exists("resource.001"))
+ if (!strcmp(s_fallbackDesc.gameid, "qfg1") && getSciVersion() == SCI_VERSION_1_1)
s_fallbackDesc.extra = "VGA Remake";
// Add "demo" to the description for demos
if (s_fallbackDesc.flags & ADGF_DEMO)
s_fallbackDesc.extra = "demo";
- SearchMan.remove("SCI_detection");
+ delete resMan;
return (const ADGameDescription *)&s_fallbackDesc;
}
@@ -427,8 +530,8 @@ bool SciMetaEngine::hasFeature(MetaEngineFeature f) const {
bool SciEngine::hasFeature(EngineFeature f) const {
return
//(f == kSupportsRTL) ||
- (f == kSupportsLoadingDuringRuntime);
- //(f == kSupportsSavingDuringRuntime);
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
}
SaveStateList SciMetaEngine::listSaves(const char *target) const {
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index e51867332a..48f7c2d64f 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -56,7 +56,7 @@ reg_t GameFeatures::getDetectionAddr(const Common::String &objName, Selector slc
}
if (methodNum == -1) {
- if (lookup_selector(_segMan, objAddr, slc, NULL, &addr) != kSelectorMethod) {
+ if (lookupSelector(_segMan, objAddr, slc, NULL, &addr) != kSelectorMethod) {
warning("getDetectionAddr: target selector is not a method of object %s", objName.c_str());
return NULL_REG;
}
@@ -87,7 +87,7 @@ bool GameFeatures::autoDetectSoundType() {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->_bufSize)
+ if (opcode == op_ret || offset >= script->getBufSize())
break;
// The play method of the Sound object pushes the DoSound command
@@ -189,7 +189,7 @@ SciVersion GameFeatures::detectSetCursorType() {
}
// Now we check what the number variable holds in the handCursor object.
- uint16 number = GET_SEL32V(_segMan, objAddr, SELECTOR(number));
+ uint16 number = readSelectorValue(_segMan, objAddr, SELECTOR(number));
// If the number is 0, it uses views and therefore the SCI1.1 kSetCursor semantics,
// otherwise it uses the SCI0 early kSetCursor semantics.
@@ -223,7 +223,7 @@ bool GameFeatures::autoDetectLofsType(int methodNum) {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->_bufSize)
+ if (opcode == op_ret || offset >= script->getBufSize())
break;
if (opcode == op_lofsa || opcode == op_lofss) {
@@ -231,13 +231,13 @@ bool GameFeatures::autoDetectLofsType(int methodNum) {
uint16 lofs = opparams[0];
// Check for going out of bounds when interpreting as abs/rel
- if (lofs >= script->_bufSize)
+ if (lofs >= script->getBufSize())
_lofsType = SCI_VERSION_0_EARLY;
if ((signed)offset + (int16)lofs < 0)
_lofsType = SCI_VERSION_1_MIDDLE;
- if ((signed)offset + (int16)lofs >= (signed)script->_bufSize)
+ if ((signed)offset + (int16)lofs >= (signed)script->getBufSize())
_lofsType = SCI_VERSION_1_MIDDLE;
if (_lofsType != SCI_VERSION_NONE)
@@ -266,7 +266,7 @@ SciVersion GameFeatures::detectLofsType() {
// Find a function of the game object which invokes lofsa/lofss
reg_t gameClass = _segMan->findObjectByName("Game");
- Object *obj = _segMan->getObject(gameClass);
+ const Object *obj = _segMan->getObject(gameClass);
bool found = false;
for (uint m = 0; m < obj->getMethodCount(); m++) {
@@ -309,7 +309,7 @@ bool GameFeatures::autoDetectGfxFunctionsType(int methodNum) {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->_bufSize)
+ if (opcode == op_ret || offset >= script->getBufSize())
break;
if (opcode == op_callk) {
@@ -332,18 +332,47 @@ bool GameFeatures::autoDetectGfxFunctionsType(int methodNum) {
SciVersion GameFeatures::detectGfxFunctionsType() {
if (_gfxFunctionsType == SCI_VERSION_NONE) {
- // This detection only works (and is only needed) for SCI0 games
- if (getSciVersion() >= SCI_VERSION_01) {
+ if (getSciVersion() == SCI_VERSION_0_EARLY) {
+ // Old SCI0 games always used old graphics functions
+ _gfxFunctionsType = SCI_VERSION_0_EARLY;
+ } else if (getSciVersion() >= SCI_VERSION_01) {
+ // SCI01 and newer games always used new graphics functions
_gfxFunctionsType = SCI_VERSION_0_LATE;
- } else if (getSciVersion() > SCI_VERSION_0_EARLY) {
+ } else { // SCI0 late
// Check if the game is using an overlay
- bool found = false;
+ bool searchRoomObj = false;
+ reg_t rmObjAddr = _segMan->findObjectByName("Rm");
+
+ if (_kernel->_selectorCache.overlay != -1) {
+ // The game has an overlay selector, check how it calls kDrawPicto determine
+ // the graphics functions type used
+ if (lookupSelector(_segMan, rmObjAddr, _kernel->_selectorCache.overlay, NULL, NULL) == kSelectorMethod) {
+ if (!autoDetectGfxFunctionsType()) {
+ warning("Graphics functions detection failed, taking an educated guess");
+
+ // Try detecting the graphics function types from the existence of the motionCue
+ // selector (which is a bit of a hack)
+ if (_kernel->findSelector("motionCue") != -1)
+ _gfxFunctionsType = SCI_VERSION_0_LATE;
+ else
+ _gfxFunctionsType = SCI_VERSION_0_EARLY;
+ }
+ } else {
+ // The game has an overlay selector, but it's not a method of the Rm object
+ // (like in Hoyle 1 and 2), so search for other methods
+ searchRoomObj = true;
+ }
+ } else {
+ // The game doesn't have an overlay selector, so search for it manually
+ searchRoomObj = true;
+ }
- if (_kernel->_selectorCache.overlay == -1) {
- // No overlay selector found, check if any method of the Rm object
- // is calling kDrawPic, as the overlay selector might be missing in demos
+ if (searchRoomObj) {
+ // If requested, check if any method of the Rm object is calling kDrawPic,
+ // as the overlay selector might be missing in demos
+ bool found = false;
- Object *obj = _segMan->getObject(_segMan->findObjectByName("Rm"));
+ const Object *obj = _segMan->getObject(rmObjAddr);
for (uint m = 0; m < obj->getMethodCount(); m++) {
found = autoDetectGfxFunctionsType(m);
if (found)
@@ -351,30 +380,11 @@ SciVersion GameFeatures::detectGfxFunctionsType() {
}
if (!found) {
- // No overlay selector found, therefore the game is definitely
- // using old graphics functions
+ // No method of the Rm object is calling kDrawPic, thus the game
+ // doesn't have overlays and is using older graphics functions
_gfxFunctionsType = SCI_VERSION_0_EARLY;
}
- } else { // _kernel->_selectorCache.overlay != -1
- // An in-between case: The game does not have a shiftParser
- // selector, but it does have an overlay selector, so it uses an
- // overlay. Therefore, check it to see how it calls kDrawPic to
- // determine the graphics functions type used
-
- if (!autoDetectGfxFunctionsType()) {
- warning("Graphics functions detection failed, taking an educated guess");
-
- // Try detecting the graphics function types from the existence of the motionCue
- // selector (which is a bit of a hack)
- if (_kernel->findSelector("motionCue") != -1)
- _gfxFunctionsType = SCI_VERSION_0_LATE;
- else
- _gfxFunctionsType = SCI_VERSION_0_EARLY;
- }
}
- } else { // (getSciVersion() == SCI_VERSION_0_EARLY)
- // Old SCI0 games always used old graphics functions
- _gfxFunctionsType = SCI_VERSION_0_EARLY;
}
debugC(1, kDebugLevelVM, "Detected graphics functions type: %s", getSciVersionDesc(_gfxFunctionsType));
@@ -402,7 +412,7 @@ bool GameFeatures::autoDetectSci21KernelType() {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->_bufSize)
+ if (opcode == op_ret || offset >= script->getBufSize())
break;
if (opcode == op_callk) {
@@ -455,7 +465,7 @@ bool GameFeatures::autoDetectMoveCountType() {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->_bufSize)
+ if (opcode == op_ret || offset >= script->getBufSize())
break;
if (opcode == op_callk) {
diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp
index 4ac2a22531..bc10099e52 100644
--- a/engines/sci/engine/game.cpp
+++ b/engines/sci/engine/game.cpp
@@ -41,141 +41,6 @@
namespace Sci {
-struct OldNewIdTableEntry {
- const char *oldId;
- const char *newId;
- SciVersion version;
-};
-
-static const OldNewIdTableEntry s_oldNewTable[] = {
- { "arthur", "camelot", SCI_VERSION_NONE },
- { "brain", "castlebrain", SCI_VERSION_1_MIDDLE }, // Amiga
- { "brain", "castlebrain", SCI_VERSION_1_LATE },
- { "demo", "christmas1988", SCI_VERSION_NONE },
- { "card", "christmas1990", SCI_VERSION_1_EARLY, },
- { "card", "christmas1992", SCI_VERSION_1_1 },
- { "RH Budget", "cnick-longbow", SCI_VERSION_NONE },
- // iceman is the same
- { "icedemo", "iceman", SCI_VERSION_NONE },
- // longbow is the same
- { "eco", "ecoquest", SCI_VERSION_NONE },
- { "eco2", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 demo
- { "rain", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 full
- { "fp", "freddypharkas", SCI_VERSION_NONE },
- { "emc", "funseeker", SCI_VERSION_NONE },
- { "gk", "gk1", SCI_VERSION_NONE },
- { "hoyledemo", "hoyle1", SCI_VERSION_NONE },
- { "cardgames", "hoyle1", SCI_VERSION_NONE },
- { "solitare", "hoyle2", SCI_VERSION_NONE },
- // hoyle3 is the same
- // hoyle4 is the same
- { "brain", "islandbrain", SCI_VERSION_1_1 },
- { "demo000", "kq1sci", SCI_VERSION_NONE },
- { "kq1", "kq1sci", SCI_VERSION_NONE },
- { "kq4", "kq4sci", SCI_VERSION_NONE },
- { "mm1", "laurabow", SCI_VERSION_NONE },
- { "cb1", "laurabow", SCI_VERSION_NONE },
- { "lb2", "laurabow2", SCI_VERSION_NONE },
- { "rh", "longbow", SCI_VERSION_NONE },
- { "ll1", "lsl1sci", SCI_VERSION_NONE },
- { "lsl1", "lsl1sci", SCI_VERSION_NONE },
- // lsl2 is the same
- { "lsl3", "lsl3", SCI_VERSION_NONE },
- { "ll5", "lsl5", SCI_VERSION_NONE },
- // lsl5 is the same
- // lsl6 is the same
- { "mg", "mothergoose", SCI_VERSION_NONE },
- { "twisty", "pepper", SCI_VERSION_NONE },
- { "pq1", "pq1sci", SCI_VERSION_NONE },
- { "pq", "pq2", SCI_VERSION_NONE },
- // pq3 is the same
- // pq4 is the same
- { "tales", "fairytales", SCI_VERSION_NONE },
- { "hq", "qfg1", SCI_VERSION_NONE }, // QFG1 SCI0/EGA
- { "glory", "qfg1", SCI_VERSION_0_LATE }, // QFG1 SCI0/EGA
- { "trial", "qfg2", SCI_VERSION_NONE },
- { "hq2demo", "qfg2", SCI_VERSION_NONE },
- { "thegame", "slater", SCI_VERSION_NONE },
- { "sq1demo", "sq1sci", SCI_VERSION_NONE },
- { "sq1", "sq1sci", SCI_VERSION_NONE },
- // sq3 is the same
- // sq4 is the same
- // sq5 is the same
- // torin is the same
-
- // TODO: SCI2.1, SCI3 IDs
-
- { "", "", SCI_VERSION_NONE }
-};
-
-Common::String convertSierraGameId(const char *gameId, uint32 *gameFlags, ResourceManager *resMan) {
- // Convert the id to lower case, so that we match all upper/lower case variants.
- Common::String sierraId = gameId;
- sierraId.toLowercase();
-
- // If the game has less than the expected scripts, it's a demo
- uint32 demoThreshold = 100;
- // ...but there are some exceptions
- if (sierraId == "brain" || sierraId == "lsl1" ||
- sierraId == "mg" || sierraId == "pq" ||
- sierraId == "jones" ||
- sierraId == "cardgames" || sierraId == "solitare" ||
- sierraId == "hoyle3" || sierraId == "hoyle4")
- demoThreshold = 40;
- if (sierraId == "fp" || sierraId == "gk" || sierraId == "pq4")
- demoThreshold = 150;
-
- Common::List<ResourceId> *resources = resMan->listResources(kResourceTypeScript, -1);
- if (resources->size() < demoThreshold) {
- *gameFlags |= ADGF_DEMO;
-
- // Crazy Nick's Picks
- if (sierraId == "lsl1" && resources->size() == 34)
- return "cnick-lsl";
- if (sierraId == "sq4" && resources->size() == 34)
- return "cnick-sq";
-
- // TODO: cnick-kq, cnick-laurabow and cnick-longbow (their resources can't be read)
-
- // Handle Astrochicken 1 (SQ3) and 2 (SQ4)
- if (sierraId == "sq3" && resources->size() == 20)
- return "astrochicken";
- if (sierraId == "sq4")
- return "msastrochicken";
- }
-
- for (const OldNewIdTableEntry *cur = s_oldNewTable; cur->oldId[0]; ++cur) {
- if (sierraId == cur->oldId) {
- // Distinguish same IDs from the SCI version
- if (cur->version != SCI_VERSION_NONE && cur->version != getSciVersion())
- continue;
-
- return cur->newId;
- }
- }
-
- if (sierraId == "glory") {
- // This could either be qfg1 VGA, qfg3 or qfg4 demo (all SCI1.1),
- // or qfg4 full (SCI2)
- // qfg1 VGA doesn't have view 1
- if (!resMan->testResource(ResourceId(kResourceTypeView, 1)))
- return "qfg1";
-
- // qfg4 full is SCI2
- if (getSciVersion() == SCI_VERSION_2)
- return "qfg4";
-
- // qfg4 demo has less than 50 scripts
- if (resources->size() < 50)
- return "qfg4";
-
- // Otherwise it's qfg3
- return "qfg3";
- }
-
- return sierraId;
-}
-
#ifdef USE_OLD_MUSIC_FUNCTIONS
int game_init_sound(EngineState *s, int sound_flags, SciVersion soundVersion) {
if (getSciVersion() > SCI_VERSION_0_LATE)
@@ -202,13 +67,7 @@ int script_init_engine(EngineState *s) {
s->script_000 = s->_segMan->getScript(script_000_segment);
- s->sys_strings = s->_segMan->allocateSysStrings(&s->sys_strings_segment);
-
- // Allocate static buffer for savegame and CWD directories
- SystemString *str = &s->sys_strings->_strings[SYS_STRING_SAVEDIR];
- str->_name = "savedir";
- str->_maxSize = MAX_SAVE_DIR_SIZE;
- str->_value = (char *)calloc(MAX_SAVE_DIR_SIZE, sizeof(char));
+ s->_segMan->initSysStrings();
s->r_acc = s->r_prev = NULL_REG;
s->restAdjust = 0;
@@ -240,35 +99,26 @@ int game_init(EngineState *s) {
return 1;
}
- if (s->_voc) {
- s->_voc->parserIsValid = false; // Invalidate parser
- s->_voc->parser_event = NULL_REG; // Invalidate parser event
- s->_voc->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE);
+ // Reset parser
+ Vocabulary *voc = g_sci->getVocabulary();
+ if (voc) {
+ voc->parserIsValid = false; // Invalidate parser
+ voc->parser_event = NULL_REG; // Invalidate parser event
+ voc->parser_base = make_reg(s->_segMan->getSysStringsSegment(), SYS_STRING_PARSER_BASE);
}
// Initialize menu TODO: Actually this should be another init()
if (g_sci->_gfxMenu)
g_sci->_gfxMenu->reset();
- s->successor = NULL; // No successor
-
- SystemString *str = &s->sys_strings->_strings[SYS_STRING_PARSER_BASE];
- str->_name = "parser-base";
- str->_maxSize = MAX_PARSER_BASE;
- str->_value = (char *)calloc(MAX_PARSER_BASE, sizeof(char));
+ s->restoring = false;
s->game_start_time = g_system->getMillis();
s->last_wait_time = s->game_start_time;
srand(g_system->getMillis()); // Initialize random number generator
-// script_dissect(0, s->_selectorNames);
- // The first entry in the export table of script 0 points to the game object
- s->_gameObj = s->_segMan->lookupScriptExport(0, 0);
- uint32 gameFlags = 0; // unused
- s->_gameId = convertSierraGameId(s->_segMan->getObjectName(s->_gameObj), &gameFlags, g_sci->getResMan());
-
- debug(2, " \"%s\" at %04x:%04x", s->_gameId.c_str(), PRINT_REG(s->_gameObj));
+ s->_gameObj = g_sci->getResMan()->findGameObject();
#ifdef USE_OLD_MUSIC_FUNCTIONS
if (s->sfx_init_flags & SFX_STATE_FLAG_NOSOUND)
@@ -284,9 +134,8 @@ int game_init(EngineState *s) {
}
int game_exit(EngineState *s) {
- s->_executionStack.clear();
-
- if (!s->successor) {
+ if (!s->restoring) {
+ s->_executionStack.clear();
#ifdef USE_OLD_MUSIC_FUNCTIONS
s->_sound.sfx_exit();
// Reinit because some other code depends on having a valid state
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 49266f3a18..6ebee2dfbd 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -332,11 +332,12 @@ SciKernelFunction kfunct_mappers[] = {
DEFUN("DoSync", kDoSync, ".*"),
DEFUN("MemorySegment", kMemorySegment, "iri*"),
DEFUN("Intersections", kIntersections, "iiiiriiiri"),
+ DEFUN("MergePoly", kMergePoly, "rli"),
DEFUN("ResCheck", kResCheck, "iii*"),
DEFUN("SetQuitStr", kSetQuitStr, "r"),
DEFUN("ShowMovie", kShowMovie, ".*"),
DEFUN("SetVideoMode", kSetVideoMode, "i"),
- DEFUN("Platform", kPlatform, "i.*"),
+ DEFUN("Platform", kPlatform, ".*"),
DEFUN("TextColors", kTextColors, ".*"),
DEFUN("TextFonts", kTextFonts, ".*"),
DEFUN("Portrait", kPortrait, ".*"),
@@ -362,7 +363,7 @@ SciKernelFunction kfunct_mappers[] = {
DEFUN("ListIndexOf", kListIndexOf, "lZo"),
DEFUN("OnMe", kOnMe, "iio.*"),
DEFUN("InPolygon", kInPolygon, "iio"),
- DEFUN("CreateTextBitmap", kCreateTextBitmap, "iiio"),
+ DEFUN("CreateTextBitmap", kCreateTextBitmap, "i.*"),
// SCI2.1 Kernel Functions
DEFUN("Save", kSave, ".*"),
@@ -382,7 +383,6 @@ SciKernelFunction kfunct_mappers[] = {
DEFUN("ShiftScreen", kShiftScreen, ".*"),
DEFUN("ListOps", kListOps, ".*"),
DEFUN("ATan", kATan, ".*"),
- DEFUN("MergePoly", kMergePoly, ".*"),
DEFUN("Record", kRecord, ".*"),
DEFUN("PlayBack", kPlayBack, ".*"),
DEFUN("DbugStr", kDbugStr, ".*"),
@@ -628,7 +628,7 @@ int Kernel::findRegType(reg_t reg) {
switch (mobj->getType()) {
case SEG_TYPE_SCRIPT:
- if (reg.offset <= (*(Script *)mobj)._bufSize &&
+ if (reg.offset <= (*(Script *)mobj).getBufSize() &&
reg.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET &&
RAW_IS_OBJECT((*(Script *)mobj)._buf + reg.offset)) {
return ((Script *)mobj)->getObject(reg.offset) ? KSIG_OBJECT : KSIG_REF;
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 7717743e19..8f8f34f74e 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -414,6 +414,7 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv);
reg_t kDoSync(EngineState *s, int argc, reg_t *argv);
reg_t kMemorySegment(EngineState *s, int argc, reg_t *argv);
reg_t kIntersections(EngineState *s, int argc, reg_t *argv);
+reg_t kMergePoly(EngineState *s, int argc, reg_t *argv);
reg_t kResCheck(EngineState *s, int argc, reg_t *argv);
reg_t kSetQuitStr(EngineState *s, int argc, reg_t *argv);
reg_t kShowMovie(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel32.cpp b/engines/sci/engine/kernel32.cpp
index 465e0e92df..0afdc3f2eb 100644
--- a/engines/sci/engine/kernel32.cpp
+++ b/engines/sci/engine/kernel32.cpp
@@ -501,7 +501,7 @@ reg_t kArray(EngineState *s, int argc, reg_t *argv) {
if (!s->_segMan->isHeapObject(argv[1]))
return argv[1];
- return GET_SEL32(s->_segMan, argv[1], SELECTOR(data));
+ return readSelector(s->_segMan, argv[1], SELECTOR(data));
default:
error("Unknown kArray subop %d", argv[0].toUint16());
}
@@ -524,8 +524,12 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
}
case 1: // Size
return make_reg(0, s->_segMan->getString(argv[1]).size());
- case 2: // At (return value at an index)
+ case 2: { // At (return value at an index)
+ if (argv[1].segment == s->_segMan->getStringSegmentId())
+ return make_reg(0, s->_segMan->lookupString(argv[1])->getRawData()[argv[2].toUint16()]);
+
return make_reg(0, s->_segMan->getString(argv[1])[argv[2].toUint16()]);
+ }
case 3: { // Atput (put value at an index)
SciString *string = s->_segMan->lookupString(argv[1]);
@@ -563,28 +567,40 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
return argv[1];
}
case 6: { // Cpy
- Common::String string2 = s->_segMan->getString(argv[3]);
+ const char *string2 = 0;
+ uint32 string2Size = 0;
+
+ if (argv[3].segment == s->_segMan->getStringSegmentId()) {
+ SciString *string = s->_segMan->lookupString(argv[3]);
+ string2 = string->getRawData();
+ string2Size = string->getSize();
+ } else {
+ Common::String string = s->_segMan->getString(argv[3]);
+ string2 = string.c_str();
+ string2Size = string.size() + 1;
+ }
+
uint32 index1 = argv[2].toUint16();
uint32 index2 = argv[4].toUint16();
// The original engine ignores bad copies too
- if (index2 > string2.size())
+ if (index2 > string2Size)
break;
// A count of -1 means fill the rest of the array
- uint32 count = argv[5].toSint16() == -1 ? string2.size() - index2 + 1 : argv[5].toUint16();
+ uint32 count = argv[5].toSint16() == -1 ? string2Size - index2 + 1 : argv[5].toUint16();
// We have a special case here for argv[1] being a system string
- if (argv[1].segment == s->sys_strings_segment) {
+ if (argv[1].segment == s->_segMan->getSysStringsSegment()) {
// Resize if necessary
- if ((uint32)s->sys_strings->_strings[argv[1].toUint16()]._maxSize < index1 + count) {
- delete[] s->sys_strings->_strings[argv[1].toUint16()]._value;
- s->sys_strings->_strings[argv[1].toUint16()]._maxSize = index1 + count;
- s->sys_strings->_strings[argv[1].toUint16()]._value = new char[index1 + count];
- memset(s->sys_strings->_strings[argv[1].toUint16()]._value, 0, index1 + count);
+ const uint16 sysStringId = argv[1].toUint16();
+ if ((uint32)s->_segMan->sysStrings->_strings[sysStringId]._maxSize < index1 + count) {
+ free(s->_segMan->sysStrings->_strings[sysStringId]._value);
+ s->_segMan->sysStrings->_strings[sysStringId]._maxSize = index1 + count;
+ s->_segMan->sysStrings->_strings[sysStringId]._value = (char *)calloc(index1 + count, sizeof(char));
}
- strncpy(s->sys_strings->_strings[argv[1].toUint16()]._value + index1, string2.c_str() + index2, count);
+ strncpy(s->_segMan->sysStrings->_strings[sysStringId]._value + index1, string2 + index2, count);
} else {
SciString *string1 = s->_segMan->lookupString(argv[1]);
@@ -594,7 +610,7 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
// Note: We're accessing from c_str() here because the string's size ignores
// the trailing 0 and therefore triggers an assert when doing string2[i + index2].
for (uint16 i = 0; i < count; i++)
- string1->setValue(i + index1, string2.c_str()[i + index2]);
+ string1->setValue(i + index1, string2[i + index2]);
}
} return argv[1];
@@ -608,15 +624,25 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, strcmp(string1.c_str(), string2.c_str()));
}
case 8: { // Dup
- Common::String string = s->_segMan->getString(argv[1]);
+ const char *rawString = 0;
+ uint32 size = 0;
+
+ if (argv[1].segment == s->_segMan->getStringSegmentId()) {
+ SciString *string = s->_segMan->lookupString(argv[1]);
+ rawString = string->getRawData();
+ size = string->getSize();
+ } else {
+ Common::String string = s->_segMan->getString(argv[1]);
+ rawString = string.c_str();
+ size = string.size() + 1;
+ }
+
reg_t stringHandle;
SciString *dupString = s->_segMan->allocateString(&stringHandle);
- dupString->setSize(string.size() + 1);
+ dupString->setSize(size);
- for (uint32 i = 0; i < string.size(); i++)
- dupString->setValue(i, string.c_str()[i]);
-
- dupString->setValue(dupString->getSize() - 1, 0);
+ for (uint32 i = 0; i < size; i++)
+ dupString->setValue(i, rawString[i]);
return stringHandle;
}
@@ -624,7 +650,7 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
if (!s->_segMan->isHeapObject(argv[1]))
return argv[1];
- return GET_SEL32(s->_segMan, argv[1], SELECTOR(data));
+ return readSelector(s->_segMan, argv[1], SELECTOR(data));
case 10: // Stringlen
return make_reg(0, s->_segMan->strlen(argv[1]));
case 11: { // Printf
@@ -689,12 +715,12 @@ reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) {
/*
reg_t viewObj = argv[0];
- uint16 viewId = GET_SEL32V(s->_segMan, viewObj, SELECTOR(view));
- int16 loopNo = GET_SEL32V(s->_segMan, viewObj, SELECTOR(loop));
- int16 celNo = GET_SEL32V(s->_segMan, viewObj, SELECTOR(cel));
+ uint16 viewId = readSelectorValue(s->_segMan, viewObj, SELECTOR(view));
+ int16 loopNo = readSelectorValue(s->_segMan, viewObj, SELECTOR(loop));
+ int16 celNo = readSelectorValue(s->_segMan, viewObj, SELECTOR(cel));
//int16 leftPos = 0;
//int16 topPos = 0;
- int16 priority = GET_SEL32V(s->_segMan, viewObj, SELECTOR(priority));
+ int16 priority = readSelectorValue(s->_segMan, viewObj, SELECTOR(priority));
//int16 control = 0;
*/
@@ -761,10 +787,10 @@ reg_t kOnMe(EngineState *s, int argc, reg_t *argv) {
Common::Rect nsRect;
// Get the bounding rectangle of the object
- nsRect.left = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsLeft));
- nsRect.top = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsTop));
- nsRect.right = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsRight));
- nsRect.bottom = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsBottom));
+ nsRect.left = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsLeft));
+ nsRect.top = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsTop));
+ nsRect.right = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsRight));
+ nsRect.bottom = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsBottom));
//warning("kOnMe: (%d, %d) on object %04x:%04x, parameter %d", argv[0].toUint16(), argv[1].toUint16(), PRINT_REG(argv[2]), argv[3].toUint16());
@@ -778,9 +804,16 @@ reg_t kInPolygon(EngineState *s, int argc, reg_t *argv) {
reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
// TODO: argument 0 is usually 0, and arguments 1 and 2 are usually 1
- reg_t object = argv[3];
- Common::String text = s->_segMan->getString(GET_SEL32(s->_segMan, object, SELECTOR(text)));
- debug("kCreateTextBitmap: %s", text.c_str());
+ switch (argv[0].toUint16()) {
+ case 0:
+ if (argc != 4) {
+ warning("kCreateTextBitmap(0): expected 4 arguments, got %i", argc);
+ return NULL_REG;
+ }
+ reg_t object = argv[3];
+ Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text)));
+ debug("kCreateTextBitmap: %s", text.c_str());
+ }
return NULL_REG;
}
diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp
index 156035b30d..fd7711f196 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -49,16 +49,18 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
Common::Point mousePos;
+ // Limit the mouse cursor position, if necessary
+ g_sci->_gfxCursor->refreshPosition();
mousePos = g_sci->_gfxCursor->getPosition();
// If there's a simkey pending, and the game wants a keyboard event, use the
// simkey instead of a normal event
if (g_debug_simulated_key && (mask & SCI_EVENT_KEYBOARD)) {
- PUT_SEL32V(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
- PUT_SEL32V(segMan, obj, SELECTOR(message), g_debug_simulated_key);
- PUT_SEL32V(segMan, obj, SELECTOR(modifiers), SCI_KEYMOD_NUMLOCK); // Numlock on
- PUT_SEL32V(segMan, obj, SELECTOR(x), mousePos.x);
- PUT_SEL32V(segMan, obj, SELECTOR(y), mousePos.y);
+ writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
+ writeSelectorValue(segMan, obj, SELECTOR(message), g_debug_simulated_key);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), SCI_KEYMOD_NUMLOCK); // Numlock on
+ writeSelectorValue(segMan, obj, SELECTOR(x), mousePos.x);
+ writeSelectorValue(segMan, obj, SELECTOR(y), mousePos.y);
g_debug_simulated_key = 0;
return make_reg(0, 1);
}
@@ -67,26 +69,26 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
oldy = mousePos.y;
curEvent = s->_event->get(mask);
- if (s->_voc)
- s->_voc->parser_event = NULL_REG; // Invalidate parser event
+ if (g_sci->getVocabulary())
+ g_sci->getVocabulary()->parser_event = NULL_REG; // Invalidate parser event
- PUT_SEL32V(segMan, obj, SELECTOR(x), mousePos.x);
- PUT_SEL32V(segMan, obj, SELECTOR(y), mousePos.y);
+ writeSelectorValue(segMan, obj, SELECTOR(x), mousePos.x);
+ writeSelectorValue(segMan, obj, SELECTOR(y), mousePos.y);
//s->_gui->moveCursor(s->gfx_state->pointer_pos.x, s->gfx_state->pointer_pos.y);
switch (curEvent.type) {
case SCI_EVENT_QUIT:
- quit_vm();
+ quit_vm(s);
break;
case SCI_EVENT_KEYBOARD:
- PUT_SEL32V(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
+ writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
s->r_acc = make_reg(0, 1);
- PUT_SEL32V(segMan, obj, SELECTOR(message), curEvent.character);
+ writeSelectorValue(segMan, obj, SELECTOR(message), curEvent.character);
// We only care about the translated character
- PUT_SEL32V(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
break;
case SCI_EVENT_MOUSE_RELEASE:
@@ -111,9 +113,9 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
break;
}
- PUT_SEL32V(segMan, obj, SELECTOR(type), curEvent.type);
- PUT_SEL32V(segMan, obj, SELECTOR(message), 0);
- PUT_SEL32V(segMan, obj, SELECTOR(modifiers), (curEvent.modifiers | extra_bits) & modifier_mask);
+ writeSelectorValue(segMan, obj, SELECTOR(type), curEvent.type);
+ writeSelectorValue(segMan, obj, SELECTOR(message), 0);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), (curEvent.modifiers | extra_bits) & modifier_mask);
s->r_acc = make_reg(0, 1);
}
break;
@@ -165,9 +167,9 @@ reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[0];
SegManager *segMan = s->_segMan;
- if (GET_SEL32V(segMan, obj, SELECTOR(type)) == SCI_EVENT_KEYBOARD) { // Keyboard
+ if (readSelectorValue(segMan, obj, SELECTOR(type)) == SCI_EVENT_KEYBOARD) { // Keyboard
int mover = -1;
- switch (GET_SEL32V(segMan, obj, SELECTOR(message))) {
+ switch (readSelectorValue(segMan, obj, SELECTOR(message))) {
case SCI_KEY_HOME:
mover = 8;
break;
@@ -201,8 +203,8 @@ reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) {
}
if (mover >= 0) {
- PUT_SEL32V(segMan, obj, SELECTOR(type), SCI_EVENT_JOYSTICK);
- PUT_SEL32V(segMan, obj, SELECTOR(message), mover);
+ writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_JOYSTICK);
+ writeSelectorValue(segMan, obj, SELECTOR(message), mover);
return make_reg(0, 1);
} else
return NULL_REG;
@@ -217,13 +219,13 @@ reg_t kGlobalToLocal(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
if (obj.segment) {
- int16 x = GET_SEL32V(segMan, obj, SELECTOR(x));
- int16 y = GET_SEL32V(segMan, obj, SELECTOR(y));
+ int16 x = readSelectorValue(segMan, obj, SELECTOR(x));
+ int16 y = readSelectorValue(segMan, obj, SELECTOR(y));
g_sci->_gfxCoordAdjuster->kernelGlobalToLocal(x, y, planeObject);
- PUT_SEL32V(segMan, obj, SELECTOR(x), x);
- PUT_SEL32V(segMan, obj, SELECTOR(y), y);
+ writeSelectorValue(segMan, obj, SELECTOR(x), x);
+ writeSelectorValue(segMan, obj, SELECTOR(y), y);
}
return s->r_acc;
@@ -236,13 +238,13 @@ reg_t kLocalToGlobal(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
if (obj.segment) {
- int16 x = GET_SEL32V(segMan, obj, SELECTOR(x));
- int16 y = GET_SEL32V(segMan, obj, SELECTOR(y));
+ int16 x = readSelectorValue(segMan, obj, SELECTOR(x));
+ int16 y = readSelectorValue(segMan, obj, SELECTOR(y));
g_sci->_gfxCoordAdjuster->kernelLocalToGlobal(x, y, planeObject);
- PUT_SEL32V(segMan, obj, SELECTOR(x), x);
- PUT_SEL32V(segMan, obj, SELECTOR(y), y);
+ writeSelectorValue(segMan, obj, SELECTOR(x), x);
+ writeSelectorValue(segMan, obj, SELECTOR(y), y);
}
return s->r_acc;
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index e6b9a5388c..3e0ecd1a28 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -44,6 +44,8 @@ struct SavegameDesc {
int id;
int date;
int time;
+ int version;
+ char name[SCI_MAX_SAVENAME_LENGTH];
};
/*
@@ -245,13 +247,10 @@ static void fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle) {
debugC(2, kDebugLevelFile, "FGets'ed \"%s\"", dest);
}
-static int _savegame_index_struct_compare(const void *a, const void *b) {
- const SavegameDesc *A = (const SavegameDesc *)a;
- const SavegameDesc *B = (const SavegameDesc *)b;
-
- if (B->date != A->date)
- return B->date - A->date;
- return B->time - A->time;
+static bool _savegame_index_struct_compare(const SavegameDesc &l, const SavegameDesc &r) {
+ if (l.date != r.date)
+ return (l.date > r.date);
+ return (l.time > r.time);
}
void listSavegames(Common::Array<SavegameDesc> &saves) {
@@ -265,7 +264,7 @@ void listSavegames(Common::Array<SavegameDesc> &saves) {
Common::SeekableReadStream *in;
if ((in = saveFileMan->openForLoading(filename))) {
SavegameMetadata meta;
- if (!get_savegame_metadata(in, &meta)) {
+ if (!get_savegame_metadata(in, &meta) || meta.savegame_name.empty()) {
// invalid
delete in;
continue;
@@ -278,6 +277,13 @@ void listSavegames(Common::Array<SavegameDesc> &saves) {
// We need to fix date in here, because we save DDMMYYYY instead of YYYYMMDD, so sorting wouldnt work
desc.date = ((desc.date & 0xFFFF) << 16) | ((desc.date & 0xFF0000) >> 8) | ((desc.date & 0xFF000000) >> 24);
desc.time = meta.savegame_time;
+ desc.version = meta.savegame_version;
+
+ if (meta.savegame_name.lastChar() == '\n')
+ meta.savegame_name.deleteLastChar();
+
+ Common::strlcpy(desc.name, meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH);
+
debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id);
saves.push_back(desc);
@@ -285,35 +291,18 @@ void listSavegames(Common::Array<SavegameDesc> &saves) {
}
// Sort the list by creation date of the saves
- qsort(saves.begin(), saves.size(), sizeof(SavegameDesc), _savegame_index_struct_compare);
+ Common::sort(saves.begin(), saves.end(), _savegame_index_struct_compare);
}
bool Console::cmdListSaves(int argc, const char **argv) {
Common::Array<SavegameDesc> saves;
listSavegames(saves);
- Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
-
for (uint i = 0; i < saves.size(); i++) {
Common::String filename = g_sci->getSavegameName(saves[i].id);
- Common::SeekableReadStream *in;
- if ((in = saveFileMan->openForLoading(filename))) {
- SavegameMetadata meta;
- if (!get_savegame_metadata(in, &meta)) {
- // invalid
- delete in;
- continue;
- }
-
- if (!meta.savegame_name.empty()) {
- if (meta.savegame_name.lastChar() == '\n')
- meta.savegame_name.deleteLastChar();
-
- DebugPrintf("%s: '%s'\n", filename.c_str(), meta.savegame_name.c_str());
- }
- delete in;
- }
+ DebugPrintf("%s: '%s'\n", filename.c_str(), saves[i].name);
}
+
return true;
}
@@ -428,7 +417,7 @@ reg_t kGetSaveDir(EngineState *s, int argc, reg_t *argv) {
warning("kGetSaveDir called with %d parameter(s): %04x:%04x", argc, PRINT_REG(argv[0]));
#endif
- return make_reg(s->sys_strings_segment, SYS_STRING_SAVEDIR);
+ return make_reg(s->_segMan->getSysStringsSegment(), SYS_STRING_SAVEDIR);
}
reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) {
@@ -449,90 +438,59 @@ reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) {
reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) {
Common::String game_id = s->_segMan->getString(argv[0]);
- int savedir_nr = argv[1].toUint16();
+ uint16 savedir_nr = argv[1].toUint16();
debug(3, "kCheckSaveGame(%s, %d)", game_id.c_str(), savedir_nr);
Common::Array<SavegameDesc> saves;
listSavegames(saves);
- savedir_nr = saves[savedir_nr].id;
-
- if (savedir_nr > MAX_SAVEGAME_NR - 1) {
+ // Check for savegame slot being out of range
+ if (savedir_nr >= saves.size())
return NULL_REG;
- }
- Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
- Common::String filename = g_sci->getSavegameName(savedir_nr);
- Common::SeekableReadStream *in;
- if ((in = saveFileMan->openForLoading(filename))) {
- // found a savegame file
-
- SavegameMetadata meta;
- if (!get_savegame_metadata(in, &meta)) {
- // invalid
- s->r_acc = make_reg(0, 0);
- } else {
- s->r_acc = make_reg(0, 1);
- }
- delete in;
- } else {
- s->r_acc = make_reg(0, 1);
- }
+ // Check for compatible savegame version
+ int ver = saves[savedir_nr].version;
+ if (ver < MINIMUM_SAVEGAME_VERSION || ver > CURRENT_SAVEGAME_VERSION)
+ return NULL_REG;
- return s->r_acc;
+ // Otherwise we assume the savegame is OK
+ return make_reg(0, 1);
}
reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) {
Common::String game_id = s->_segMan->getString(argv[0]);
- reg_t nametarget = argv[1];
- reg_t *nameoffsets = s->_segMan->derefRegPtr(argv[2], 0);
debug(3, "kGetSaveFiles(%s)", game_id.c_str());
Common::Array<SavegameDesc> saves;
listSavegames(saves);
- s->r_acc = NULL_REG;
- Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
+ uint totalSaves = MIN<uint>(saves.size(), MAX_SAVEGAME_NR);
- for (uint i = 0; i < saves.size(); i++) {
- Common::String filename = g_sci->getSavegameName(saves[i].id);
- Common::SeekableReadStream *in;
- if ((in = saveFileMan->openForLoading(filename))) {
- // found a savegame file
+ reg_t *slot = s->_segMan->derefRegPtr(argv[2], totalSaves);
- SavegameMetadata meta;
- if (!get_savegame_metadata(in, &meta)) {
- // invalid
- delete in;
- continue;
- }
-
- if (!meta.savegame_name.empty()) {
- if (meta.savegame_name.lastChar() == '\n')
- meta.savegame_name.deleteLastChar();
-
- *nameoffsets = s->r_acc; // Store savegame ID
- ++s->r_acc.offset; // Increase number of files found
+ if (!slot) {
+ warning("kGetSaveFiles: %04X:%04X invalid or too small to hold slot data", PRINT_REG(argv[2]));
+ totalSaves = 0;
+ }
- nameoffsets++; // Make sure the next ID string address is written to the next pointer
- Common::String name = meta.savegame_name;
- if (name.size() > SCI_MAX_SAVENAME_LENGTH-1)
- name = Common::String(meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH-1);
- s->_segMan->strcpy(nametarget, name.c_str());
+ const uint bufSize = (totalSaves * SCI_MAX_SAVENAME_LENGTH) + 1;
+ char *saveNames = new char[bufSize];
+ char *saveNamePtr = saveNames;
- // Increase name offset pointer accordingly
- nametarget.offset += SCI_MAX_SAVENAME_LENGTH;
- }
- delete in;
- }
+ for (uint i = 0; i < totalSaves; i++) {
+ *slot++ = make_reg(0, i); // Store slot
+ strcpy(saveNamePtr, saves[i].name);
+ saveNamePtr += SCI_MAX_SAVENAME_LENGTH;
}
- //free(gfname);
- s->_segMan->strcpy(nametarget, ""); // Terminate list
+ *saveNamePtr = 0; // Terminate list
- return s->r_acc;
+ s->_segMan->memcpy(argv[1], (byte *)saveNames, bufSize);
+ delete[] saveNames;
+
+ return make_reg(0, totalSaves);
}
reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) {
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index d587790b6c..abe55455de 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -23,8 +23,10 @@
*
*/
+#include "engines/util.h"
#include "graphics/cursorman.h"
#include "graphics/video/avi_decoder.h"
+#include "graphics/video/qt_decoder.h"
#include "graphics/surface.h"
#include "sci/sci.h"
@@ -51,8 +53,8 @@
namespace Sci {
void _k_dirloop(reg_t object, uint16 angle, EngineState *s, int argc, reg_t *argv) {
- GuiResourceId viewId = GET_SEL32V(s->_segMan, object, SELECTOR(view));
- uint16 signal = GET_SEL32V(s->_segMan, object, SELECTOR(signal));
+ GuiResourceId viewId = readSelectorValue(s->_segMan, object, SELECTOR(view));
+ uint16 signal = readSelectorValue(s->_segMan, object, SELECTOR(signal));
int16 loopNo;
int16 maxLoops;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
@@ -91,7 +93,7 @@ void _k_dirloop(reg_t object, uint16 angle, EngineState *s, int argc, reg_t *arg
if ((loopNo > 1) && (maxLoops < 4))
return;
- PUT_SEL32V(s->_segMan, object, SELECTOR(loop), loopNo);
+ writeSelectorValue(s->_segMan, object, SELECTOR(loop), loopNo);
}
static reg_t kSetCursorSci0(EngineState *s, int argc, reg_t *argv) {
@@ -146,6 +148,10 @@ static reg_t kSetCursorSci11(EngineState *s, int argc, reg_t *argv) {
int16 bottom = argv[2].toSint16();
int16 right = argv[3].toSint16();
+ // In SCI32, the right parameter seems to be divided by 2
+ if (getSciVersion() >= SCI_VERSION_2)
+ right *= 2;
+
if ((right >= left) && (bottom >= top)) {
Common::Rect rect = Common::Rect(left, top, right, bottom);
g_sci->_gfxCursor->kernelSetMoveZone(rect);
@@ -437,7 +443,7 @@ reg_t kCelWide(EngineState *s, int argc, reg_t *argv) {
reg_t kNumLoops(EngineState *s, int argc, reg_t *argv) {
reg_t object = argv[0];
- GuiResourceId viewId = GET_SEL32V(s->_segMan, object, SELECTOR(view));
+ GuiResourceId viewId = readSelectorValue(s->_segMan, object, SELECTOR(view));
int16 loopCount;
loopCount = g_sci->_gfxCache->kernelViewGetLoopCount(viewId);
@@ -449,8 +455,8 @@ reg_t kNumLoops(EngineState *s, int argc, reg_t *argv) {
reg_t kNumCels(EngineState *s, int argc, reg_t *argv) {
reg_t object = argv[0];
- GuiResourceId viewId = GET_SEL32V(s->_segMan, object, SELECTOR(view));
- int16 loopNo = GET_SEL32V(s->_segMan, object, SELECTOR(loop));
+ GuiResourceId viewId = readSelectorValue(s->_segMan, object, SELECTOR(view));
+ int16 loopNo = readSelectorValue(s->_segMan, object, SELECTOR(loop));
int16 celCount;
celCount = g_sci->_gfxCache->kernelViewGetCelCount(viewId, loopNo);
@@ -525,9 +531,9 @@ reg_t kBaseSetter(EngineState *s, int argc, reg_t *argv) {
// WORKAROUND for a problem in LSL1VGA. This allows the casino door to be opened,
// till the actual problem is found
- if (s->_gameId == "lsl1sci" && s->currentRoomNumber() == 300) {
- int top = GET_SEL32V(s->_segMan, object, SELECTOR(brTop));
- PUT_SEL32V(s->_segMan, object, SELECTOR(brTop), top + 2);
+ if (!strcmp(g_sci->getGameID(), "lsl1sci") && s->currentRoomNumber() == 300) {
+ int top = readSelectorValue(s->_segMan, object, SELECTOR(brTop));
+ writeSelectorValue(s->_segMan, object, SELECTOR(brTop), top + 2);
}
return s->r_acc;
@@ -741,12 +747,12 @@ Common::Rect kControlCreateRect(int16 x, int16 y, int16 x1, int16 y1) {
}
void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
- int16 type = GET_SEL32V(s->_segMan, controlObject, SELECTOR(type));
- int16 style = GET_SEL32V(s->_segMan, controlObject, SELECTOR(state));
- int16 x = GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsLeft));
- int16 y = GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsTop));
- GuiResourceId fontId = GET_SEL32V(s->_segMan, controlObject, SELECTOR(font));
- reg_t textReference = GET_SEL32(s->_segMan, controlObject, SELECTOR(text));
+ int16 type = readSelectorValue(s->_segMan, controlObject, SELECTOR(type));
+ int16 style = readSelectorValue(s->_segMan, controlObject, SELECTOR(state));
+ int16 x = readSelectorValue(s->_segMan, controlObject, SELECTOR(nsLeft));
+ int16 y = readSelectorValue(s->_segMan, controlObject, SELECTOR(nsTop));
+ GuiResourceId fontId = readSelectorValue(s->_segMan, controlObject, SELECTOR(font));
+ reg_t textReference = readSelector(s->_segMan, controlObject, SELECTOR(text));
Common::String text;
Common::Rect rect;
TextAlignment alignment;
@@ -762,8 +768,8 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
bool isAlias = false;
rect = kControlCreateRect(x, y,
- GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsRight)),
- GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsBottom)));
+ readSelectorValue(s->_segMan, controlObject, SELECTOR(nsRight)),
+ readSelectorValue(s->_segMan, controlObject, SELECTOR(nsBottom)));
if (!textReference.isNull())
text = s->_segMan->getString(textReference);
@@ -775,32 +781,32 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
return;
case SCI_CONTROLS_TYPE_TEXT:
- alignment = GET_SEL32V(s->_segMan, controlObject, SELECTOR(mode));
+ alignment = readSelectorValue(s->_segMan, controlObject, SELECTOR(mode));
debugC(2, kDebugLevelGraphics, "drawing text %04x:%04x ('%s') to %d,%d, mode=%d", PRINT_REG(controlObject), text.c_str(), x, y, alignment);
g_sci->_gfxControls->kernelDrawText(rect, controlObject, g_sci->strSplit(text.c_str()).c_str(), fontId, alignment, style, hilite);
return;
case SCI_CONTROLS_TYPE_TEXTEDIT:
- mode = GET_SEL32V(s->_segMan, controlObject, SELECTOR(mode));
- maxChars = GET_SEL32V(s->_segMan, controlObject, SELECTOR(max));
- cursorPos = GET_SEL32V(s->_segMan, controlObject, SELECTOR(cursor));
+ mode = readSelectorValue(s->_segMan, controlObject, SELECTOR(mode));
+ maxChars = readSelectorValue(s->_segMan, controlObject, SELECTOR(max));
+ cursorPos = readSelectorValue(s->_segMan, controlObject, SELECTOR(cursor));
debugC(2, kDebugLevelGraphics, "drawing edit control %04x:%04x (text %04x:%04x, '%s') to %d,%d", PRINT_REG(controlObject), PRINT_REG(textReference), text.c_str(), x, y);
g_sci->_gfxControls->kernelDrawTextEdit(rect, controlObject, g_sci->strSplit(text.c_str(), NULL).c_str(), fontId, mode, style, cursorPos, maxChars, hilite);
return;
case SCI_CONTROLS_TYPE_ICON:
- viewId = GET_SEL32V(s->_segMan, controlObject, SELECTOR(view));
+ viewId = readSelectorValue(s->_segMan, controlObject, SELECTOR(view));
{
- int l = GET_SEL32V(s->_segMan, controlObject, SELECTOR(loop));
+ int l = readSelectorValue(s->_segMan, controlObject, SELECTOR(loop));
loopNo = (l & 0x80) ? l - 256 : l;
- int c = GET_SEL32V(s->_segMan, controlObject, SELECTOR(cel));
+ int c = readSelectorValue(s->_segMan, controlObject, SELECTOR(cel));
celNo = (c & 0x80) ? c - 256 : c;
// Game-specific: *ONLY* the jones EGA/VGA sierra interpreter contain code using priority selector
// ALL other games use a hardcoded -1 (madness!)
// We are detecting jones/talkie as "jones" as well, but the sierra interpreter of talkie doesnt have this
// "hack". Hopefully it wont cause regressions (the code causes regressions if used against kq5/floppy)
- if (s->_gameId == "jones")
- priority = GET_SEL32V(s->_segMan, controlObject, SELECTOR(priority));
+ if (!strcmp(g_sci->getGameID(), "jones"))
+ priority = readSelectorValue(s->_segMan, controlObject, SELECTOR(priority));
else
priority = -1;
}
@@ -813,17 +819,17 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
if (type == SCI_CONTROLS_TYPE_LIST_ALIAS)
isAlias = true;
- maxChars = GET_SEL32V(s->_segMan, controlObject, SELECTOR(x)); // max chars per entry
- cursorOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(cursor));
+ maxChars = readSelectorValue(s->_segMan, controlObject, SELECTOR(x)); // max chars per entry
+ cursorOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(cursor));
if (g_sci->getKernel()->_selectorCache.topString != -1) {
// Games from early SCI1 onwards use topString
- upperOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(topString));
+ upperOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(topString));
} else {
// Earlier games use lsTop or brTop
- if (lookup_selector(s->_segMan, controlObject, g_sci->getKernel()->_selectorCache.brTop, NULL, NULL) == kSelectorVariable)
- upperOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(brTop));
+ if (lookupSelector(s->_segMan, controlObject, g_sci->getKernel()->_selectorCache.brTop, NULL, NULL) == kSelectorVariable)
+ upperOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(brTop));
else
- upperOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(lsTop));
+ upperOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(lsTop));
}
// Count string entries in NULL terminated string list
@@ -874,8 +880,8 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) {
// Disable the "Change Directory" button, as we don't allow the game engine to
// change the directory where saved games are placed
if (objName == "changeDirI") {
- int state = GET_SEL32V(s->_segMan, controlObject, SELECTOR(state));
- PUT_SEL32V(s->_segMan, controlObject, SELECTOR(state), (state | SCI_CONTROLS_STYLE_DISABLED) & ~SCI_CONTROLS_STYLE_ENABLED);
+ int state = readSelectorValue(s->_segMan, controlObject, SELECTOR(state));
+ writeSelectorValue(s->_segMan, controlObject, SELECTOR(state), (state | SCI_CONTROLS_STYLE_DISABLED) & ~SCI_CONTROLS_STYLE_ENABLED);
}
_k_GenericDrawControl(s, controlObject, false);
@@ -894,7 +900,7 @@ reg_t kEditControl(EngineState *s, int argc, reg_t *argv) {
reg_t eventObject = argv[1];
if (!controlObject.isNull()) {
- int16 controlType = GET_SEL32V(s->_segMan, controlObject, SELECTOR(type));
+ int16 controlType = readSelectorValue(s->_segMan, controlObject, SELECTOR(type));
switch (controlType) {
case SCI_CONTROLS_TYPE_TEXTEDIT:
@@ -983,7 +989,7 @@ reg_t kDrawCel(EngineState *s, int argc, reg_t *argv) {
bool hiresMode = (argc > 7) ? true : false;
reg_t upscaledHiresHandle = (argc > 7) ? argv[7] : NULL_REG;
- if ((s->_gameId == "freddypharkas") || (s->_gameId == "freddypharkas-demo")) {
+ if (!strcmp(g_sci->getGameID(), "freddypharkas") || !strcmp(g_sci->getGameID(), "freddypharkas-demo")) {
// WORKAROUND
// Script 24 contains code that draws the game menu on screen. It uses a temp variable for setting priority that
// is not set. in Sierra sci this happens to be 8250h. In our sci temporary variables are initialized thus we would
@@ -994,7 +1000,7 @@ reg_t kDrawCel(EngineState *s, int argc, reg_t *argv) {
priority = 15;
}
- if (s->_gameId == "laurabow2") {
+ if (!strcmp(g_sci->getGameID(), "laurabow2")) {
// WORKAROUND
// see the one above
if ((viewId == 995) && (priority == 0))
@@ -1080,11 +1086,12 @@ reg_t kDisplay(EngineState *s, int argc, reg_t *argv) {
reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
// Hide the cursor if it's showing and then show it again if it was
// previously visible.
- bool reshowCursor;
-
- reshowCursor = g_sci->_gfxCursor->isVisible();
+ bool reshowCursor = g_sci->_gfxCursor->isVisible();
if (reshowCursor)
g_sci->_gfxCursor->kernelHide();
+
+ uint16 screenWidth = g_system->getWidth();
+ uint16 screenHeight = g_system->getHeight();
Graphics::VideoDecoder *videoDecoder = 0;
@@ -1094,8 +1101,18 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
if (g_sci->getPlatform() == Common::kPlatformMacintosh) {
// Mac QuickTime
// The only argument is the string for the video
- warning("TODO: Play QuickTime movie '%s'", filename.c_str());
- return s->r_acc;
+
+ // HACK: Switch to 16bpp graphics for Cinepak.
+ initGraphics(screenWidth, screenHeight, screenWidth > 320, NULL);
+
+ if (g_system->getScreenFormat().bytesPerPixel == 1) {
+ warning("This video requires >8bpp color to be displayed, but could not switch to RGB color mode.");
+ return NULL_REG;
+ }
+
+ videoDecoder = new Graphics::QuickTimeDecoder();
+ if (!videoDecoder->loadFile(filename))
+ error("Could not open '%s'", filename.c_str());
} else {
// DOS SEQ
// SEQ's are called with no subops, just the string and delay
@@ -1110,7 +1127,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
}
}
} else {
- // Windows AVI (Macintosh QuickTime? Need to check KQ6 Macintosh)
+ // Windows AVI
// TODO: This appears to be some sort of subop. case 0 contains the string
// for the video, so we'll just play it from there for now.
@@ -1142,10 +1159,10 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
}
if (videoDecoder) {
- uint16 x = (g_system->getWidth() - videoDecoder->getWidth()) / 2;
- uint16 y = (g_system->getHeight() - videoDecoder->getHeight()) / 2;
+ uint16 x = (screenWidth - videoDecoder->getWidth()) / 2;
+ uint16 y = (screenHeight - videoDecoder->getHeight()) / 2;
- while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo()) {
+ while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo()) {
if (videoDecoder->needsUpdate()) {
Graphics::Surface *frame = videoDecoder->decodeNextFrame();
if (frame) {
@@ -1164,9 +1181,15 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
g_system->delayMillis(10);
}
+
+ // HACK: Switch back to 8bpp if we played a QuickTime video.
+ // We also won't be copying the screen to the SCI screen...
+ if (g_system->getScreenFormat().bytesPerPixel != 1)
+ initGraphics(screenWidth, screenHeight, screenWidth > 320);
+ else
+ g_sci->_gfxScreen->kernelSyncWithFramebuffer();
delete videoDecoder;
- g_sci->_gfxScreen->kernelSyncWithFramebuffer();
}
if (reshowCursor)
diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp
index c04454ca3d..f06f3eec77 100644
--- a/engines/sci/engine/klists.cpp
+++ b/engines/sci/engine/klists.cpp
@@ -155,28 +155,10 @@ reg_t kDisposeList(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-static reg_t _k_new_node(EngineState *s, reg_t value, reg_t key) {
- reg_t nodebase;
- Node *n = s->_segMan->allocateNode(&nodebase);
-
- if (!n) {
- error("[Kernel] Out of memory while creating a node");
- return NULL_REG;
- }
-
- n->pred = n->succ = NULL_REG;
- n->key = key;
- n->value = value;
-
- return nodebase;
-}
-
reg_t kNewNode(EngineState *s, int argc, reg_t *argv) {
-
- if (argc == 1)
- s->r_acc = _k_new_node(s, argv[0], argv[0]);
- else
- s->r_acc = _k_new_node(s, argv[0], argv[1]);
+ reg_t nodeValue = argv[0];
+ reg_t nodeKey = (argc == 2) ? argv[1] : NULL_REG;
+ s->r_acc = s->_segMan->newNode(nodeValue, nodeKey);
debugC(2, kDebugLevelNodes, "New nodebase at %04x:%04x", PRINT_REG(s->r_acc));
@@ -415,11 +397,11 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
reg_t dest = argv[1];
reg_t order_func = argv[2];
- int input_size = (int16)GET_SEL32V(segMan, source, SELECTOR(size));
+ int input_size = (int16)readSelectorValue(segMan, source, SELECTOR(size));
int i;
- reg_t input_data = GET_SEL32(segMan, source, SELECTOR(elements));
- reg_t output_data = GET_SEL32(segMan, dest, SELECTOR(elements));
+ reg_t input_data = readSelector(segMan, source, SELECTOR(elements));
+ reg_t output_data = readSelector(segMan, dest, SELECTOR(elements));
List *list;
Node *node;
@@ -430,10 +412,10 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
if (output_data.isNull()) {
list = s->_segMan->allocateList(&output_data);
list->first = list->last = NULL_REG;
- PUT_SEL32(segMan, dest, SELECTOR(elements), output_data);
+ writeSelector(segMan, dest, SELECTOR(elements), output_data);
}
- PUT_SEL32V(segMan, dest, SELECTOR(size), input_size);
+ writeSelectorValue(segMan, dest, SELECTOR(size), input_size);
list = s->_segMan->lookupList(input_data);
node = s->_segMan->lookupNode(list->first);
@@ -442,7 +424,7 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
i = 0;
while (node) {
- invoke_selector(INV_SEL(s, order_func, doit, kStopOnInvalidSelector), 1, node->value);
+ invokeSelector(INV_SEL(s, order_func, doit, kStopOnInvalidSelector), 1, node->value);
temp_array[i].key = node->key;
temp_array[i].value = node->value;
temp_array[i].order = s->r_acc;
@@ -453,7 +435,7 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
qsort(temp_array, input_size, sizeof(sort_temp_t), sort_temp_cmp);
for (i = 0;i < input_size;i++) {
- reg_t lNode = _k_new_node(s, temp_array[i].key, temp_array[i].value);
+ reg_t lNode = s->_segMan->newNode(temp_array[i].value, temp_array[i].key);
_k_add_to_end(s, output_data, lNode);
}
@@ -533,15 +515,15 @@ reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) {
curObject = curNode->value;
// First, check if the target selector is a variable
- if (lookup_selector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
+ if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
// This can only happen with 3 params (list, target selector, variable)
if (argc != 3) {
warning("kListEachElementDo: Attempted to modify a variable selector with %d params", argc);
} else {
- write_selector(s->_segMan, curObject, slc, argv[2]);
+ writeSelector(s->_segMan, curObject, slc, argv[2]);
}
} else {
- invoke_selector_argv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
+ invokeSelectorArgv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
}
curNode = s->_segMan->lookupNode(nextNode);
@@ -566,11 +548,11 @@ reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv) {
curObject = curNode->value;
// First, check if the target selector is a variable
- if (lookup_selector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
+ if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
// Can this happen with variable selectors?
warning("kListFirstTrue: Attempted to access a variable selector");
} else {
- invoke_selector_argv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
+ invokeSelectorArgv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
// Check if the result is true
if (!s->r_acc.isNull())
@@ -600,11 +582,11 @@ reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv) {
curObject = curNode->value;
// First, check if the target selector is a variable
- if (lookup_selector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
+ if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
// Can this happen with variable selectors?
warning("kListAllTrue: Attempted to access a variable selector");
} else {
- invoke_selector_argv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
+ invokeSelectorArgv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
// Check if the result isn't true
if (s->r_acc.isNull())
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 450dca3770..f91ba0fd82 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -32,16 +32,16 @@
#include "sci/engine/kernel.h"
#include "sci/engine/gc.h"
#include "sci/graphics/gui.h"
+#include "sci/graphics/maciconbar.h"
namespace Sci {
reg_t kRestartGame(EngineState *s, int argc, reg_t *argv) {
s->restarting_flags |= SCI_GAME_IS_RESTARTING_NOW;
- s->restarting_flags &= ~SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE; // This appears to help
- shrink_execution_stack(s, s->execution_stack_base + 1);
+ s->shrinkStackToBase();
- script_abort_flag = 1; // Force vm to abort ASAP
+ s->script_abort_flag = 1; // Force vm to abort ASAP
return NULL_REG;
}
@@ -62,9 +62,9 @@ reg_t kGameIsRestarting(EngineState *s, int argc, reg_t *argv) {
// LSL3 calculates a machinespeed variable during game startup (right after the filthy questions)
// This one would go through w/o throttling resulting in having to do 1000 pushups or something
// Another way of handling this would be delaying incrementing of "machineSpeed" selector
- if (s->_gameId == "lsl3" && s->currentRoomNumber() == 290)
+ if (!strcmp(g_sci->getGameID(), "lsl3") && s->currentRoomNumber() == 290)
s->_throttleTrigger = true;
- if (s->_gameId == "iceman" && s->currentRoomNumber() == 27) {
+ if (!strcmp(g_sci->getGameID(), "iceman") && s->currentRoomNumber() == 27) {
s->_throttleTrigger = true;
neededSleep = 60;
}
@@ -252,10 +252,15 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
break;
}
case K_MEMORY_PEEK : {
+ if (!argv[1].segment) {
+ // This occurs in KQ5CD when interacting with certain objects
+ warning("Attempt to peek invalid memory at %04x:%04x", PRINT_REG(argv[1]));
+ return s->r_acc;
+ }
+
SegmentRef ref = s->_segMan->dereference(argv[1]);
if (!ref.isValid() || ref.maxSize < 2) {
- // This occurs in KQ5CD when interacting with certain objects
warning("Attempt to peek invalid memory at %04x:%04x", PRINT_REG(argv[1]));
return s->r_acc;
}
@@ -298,9 +303,12 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
reg_t kIconBar(EngineState *s, int argc, reg_t *argv) {
// TODO...
- if (argv[0].toUint16() == 4 && argv[1].toUint16() == 0)
+ if (argv[0].toUint16() == 4 && argv[1].toUint16() == 0) {
for (int i = 0; i < argv[2].toUint16(); i++)
- warning("kIconBar: Icon Object %d = %04x:%04x", i, PRINT_REG(argv[i + 3]));
+ g_sci->_gfxMacIconBar->addIcon(argv[i + 3]);
+
+ g_sci->_gfxMacIconBar->drawIcons();
+ }
// Other calls seem to handle selecting/deselecting them
diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp
index fcaf0d7ea0..499aeabcc6 100644
--- a/engines/sci/engine/kmovement.cpp
+++ b/engines/sci/engine/kmovement.cpp
@@ -158,8 +158,8 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) {
debugC(2, kDebugLevelBresen, "SetJump for object at %04x:%04x", PRINT_REG(object));
debugC(2, kDebugLevelBresen, "xStep: %d, yStep: %d", vx, vy);
- PUT_SEL32V(segMan, object, SELECTOR(xStep), vx);
- PUT_SEL32V(segMan, object, SELECTOR(yStep), vy);
+ writeSelectorValue(segMan, object, SELECTOR(xStep), vx);
+ writeSelectorValue(segMan, object, SELECTOR(yStep), vy);
return s->r_acc;
}
@@ -168,9 +168,9 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) {
#define _K_BRESEN_AXIS_Y 1
static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t mover, int step_factor, int deltax, int deltay) {
- reg_t client = GET_SEL32(segMan, mover, SELECTOR(client));
- int stepx = (int16)GET_SEL32V(segMan, client, SELECTOR(xStep)) * step_factor;
- int stepy = (int16)GET_SEL32V(segMan, client, SELECTOR(yStep)) * step_factor;
+ reg_t client = readSelector(segMan, mover, SELECTOR(client));
+ int stepx = (int16)readSelectorValue(segMan, client, SELECTOR(xStep)) * step_factor;
+ int stepy = (int16)readSelectorValue(segMan, client, SELECTOR(yStep)) * step_factor;
int numsteps_x = stepx ? (abs(deltax) + stepx - 1) / stepx : 0;
int numsteps_y = stepy ? (abs(deltay) + stepy - 1) / stepy : 0;
int bdi, i1;
@@ -191,15 +191,15 @@ static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t m
/* if (abs(deltax) > abs(deltay)) {*/ // Bresenham on y
if (numsteps_y < numsteps_x) {
- PUT_SEL32V(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_Y);
- PUT_SEL32V(segMan, mover, SELECTOR(b_incr), (deltay < 0) ? -1 : 1);
+ writeSelectorValue(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_Y);
+ writeSelectorValue(segMan, mover, SELECTOR(b_incr), (deltay < 0) ? -1 : 1);
//i1 = 2 * (abs(deltay) - abs(deltay_step * numsteps)) * abs(deltax_step);
//bdi = -abs(deltax);
i1 = 2 * (abs(deltay) - abs(deltay_step * (numsteps - 1))) * abs(deltax_step);
bdi = -abs(deltax);
} else { // Bresenham on x
- PUT_SEL32V(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_X);
- PUT_SEL32V(segMan, mover, SELECTOR(b_incr), (deltax < 0) ? -1 : 1);
+ writeSelectorValue(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_X);
+ writeSelectorValue(segMan, mover, SELECTOR(b_incr), (deltax < 0) ? -1 : 1);
//i1= 2 * (abs(deltax) - abs(deltax_step * numsteps)) * abs(deltay_step);
//bdi = -abs(deltay);
i1 = 2 * (abs(deltax) - abs(deltax_step * (numsteps - 1))) * abs(deltay_step);
@@ -207,26 +207,26 @@ static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t m
}
- PUT_SEL32V(segMan, mover, SELECTOR(dx), deltax_step);
- PUT_SEL32V(segMan, mover, SELECTOR(dy), deltay_step);
+ writeSelectorValue(segMan, mover, SELECTOR(dx), deltax_step);
+ writeSelectorValue(segMan, mover, SELECTOR(dy), deltay_step);
debugC(2, kDebugLevelBresen, "Init bresen for mover %04x:%04x: d=(%d,%d)", PRINT_REG(mover), deltax, deltay);
debugC(2, kDebugLevelBresen, " steps=%d, mv=(%d, %d), i1= %d, i2=%d",
numsteps, deltax_step, deltay_step, i1, bdi*2);
- //PUT_SEL32V(segMan, mover, SELECTOR(b_movCnt), numsteps); // Needed for HQ1/Ogre?
- PUT_SEL32V(segMan, mover, SELECTOR(b_di), bdi);
- PUT_SEL32V(segMan, mover, SELECTOR(b_i1), i1);
- PUT_SEL32V(segMan, mover, SELECTOR(b_i2), bdi * 2);
+ //writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), numsteps); // Needed for HQ1/Ogre?
+ writeSelectorValue(segMan, mover, SELECTOR(b_di), bdi);
+ writeSelectorValue(segMan, mover, SELECTOR(b_i1), i1);
+ writeSelectorValue(segMan, mover, SELECTOR(b_i2), bdi * 2);
}
reg_t kInitBresen(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
reg_t mover = argv[0];
- reg_t client = GET_SEL32(segMan, mover, SELECTOR(client));
+ reg_t client = readSelector(segMan, mover, SELECTOR(client));
- int deltax = (int16)GET_SEL32V(segMan, mover, SELECTOR(x)) - (int16)GET_SEL32V(segMan, client, SELECTOR(x));
- int deltay = (int16)GET_SEL32V(segMan, mover, SELECTOR(y)) - (int16)GET_SEL32V(segMan, client, SELECTOR(y));
+ int deltax = (int16)readSelectorValue(segMan, mover, SELECTOR(x)) - (int16)readSelectorValue(segMan, client, SELECTOR(x));
+ int deltay = (int16)readSelectorValue(segMan, mover, SELECTOR(y)) - (int16)readSelectorValue(segMan, client, SELECTOR(y));
int step_factor = (argc < 1) ? argv[1].toUint16() : 1;
initialize_bresen(s->_segMan, argc, argv, mover, step_factor, deltax, deltay);
@@ -240,42 +240,42 @@ reg_t kInitBresen(EngineState *s, int argc, reg_t *argv) {
reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
reg_t mover = argv[0];
- reg_t client = GET_SEL32(segMan, mover, SELECTOR(client));
+ reg_t client = readSelector(segMan, mover, SELECTOR(client));
- int x = (int16)GET_SEL32V(segMan, client, SELECTOR(x));
- int y = (int16)GET_SEL32V(segMan, client, SELECTOR(y));
+ int x = (int16)readSelectorValue(segMan, client, SELECTOR(x));
+ int y = (int16)readSelectorValue(segMan, client, SELECTOR(y));
int oldx, oldy, destx, desty, dx, dy, bdi, bi1, bi2, movcnt, bdelta, axis;
- uint16 signal = GET_SEL32V(segMan, client, SELECTOR(signal));
+ uint16 signal = readSelectorValue(segMan, client, SELECTOR(signal));
int completed = 0;
- int max_movcnt = GET_SEL32V(segMan, client, SELECTOR(moveSpeed));
+ int max_movcnt = readSelectorValue(segMan, client, SELECTOR(moveSpeed));
if (getSciVersion() > SCI_VERSION_01)
signal &= ~kSignalHitObstacle;
- PUT_SEL32(segMan, client, SELECTOR(signal), make_reg(0, signal)); // This is a NOP for SCI0
+ writeSelector(segMan, client, SELECTOR(signal), make_reg(0, signal)); // This is a NOP for SCI0
oldx = x;
oldy = y;
- destx = (int16)GET_SEL32V(segMan, mover, SELECTOR(x));
- desty = (int16)GET_SEL32V(segMan, mover, SELECTOR(y));
- dx = (int16)GET_SEL32V(segMan, mover, SELECTOR(dx));
- dy = (int16)GET_SEL32V(segMan, mover, SELECTOR(dy));
- bdi = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_di));
- bi1 = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_i1));
- bi2 = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_i2));
- movcnt = GET_SEL32V(segMan, mover, SELECTOR(b_movCnt));
- bdelta = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_incr));
- axis = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_xAxis));
+ destx = (int16)readSelectorValue(segMan, mover, SELECTOR(x));
+ desty = (int16)readSelectorValue(segMan, mover, SELECTOR(y));
+ dx = (int16)readSelectorValue(segMan, mover, SELECTOR(dx));
+ dy = (int16)readSelectorValue(segMan, mover, SELECTOR(dy));
+ bdi = (int16)readSelectorValue(segMan, mover, SELECTOR(b_di));
+ bi1 = (int16)readSelectorValue(segMan, mover, SELECTOR(b_i1));
+ bi2 = (int16)readSelectorValue(segMan, mover, SELECTOR(b_i2));
+ movcnt = readSelectorValue(segMan, mover, SELECTOR(b_movCnt));
+ bdelta = (int16)readSelectorValue(segMan, mover, SELECTOR(b_incr));
+ axis = (int16)readSelectorValue(segMan, mover, SELECTOR(b_xAxis));
//printf("movecnt %d, move speed %d\n", movcnt, max_movcnt);
if (g_sci->_features->handleMoveCount()) {
if (max_movcnt > movcnt) {
++movcnt;
- PUT_SEL32V(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
+ writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
return NULL_REG;
} else {
movcnt = 0;
- PUT_SEL32V(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
+ writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
}
}
@@ -288,7 +288,7 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
dy += bdelta;
}
- PUT_SEL32V(segMan, mover, SELECTOR(b_di), bdi);
+ writeSelectorValue(segMan, mover, SELECTOR(b_di), bdi);
x += dx;
y += dy;
@@ -310,33 +310,32 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
debugC(2, kDebugLevelBresen, "Finished mover %04x:%04x", PRINT_REG(mover));
}
- PUT_SEL32V(segMan, client, SELECTOR(x), x);
- PUT_SEL32V(segMan, client, SELECTOR(y), y);
+ writeSelectorValue(segMan, client, SELECTOR(x), x);
+ writeSelectorValue(segMan, client, SELECTOR(y), y);
debugC(2, kDebugLevelBresen, "New data: (x,y)=(%d,%d), di=%d", x, y, bdi);
if (g_sci->getKernel()->_selectorCache.cantBeHere != -1) {
- invoke_selector(INV_SEL(s, client, cantBeHere, kStopOnInvalidSelector), 0);
+ invokeSelector(INV_SEL(s, client, cantBeHere, kStopOnInvalidSelector), 0);
s->r_acc = make_reg(0, !s->r_acc.offset);
} else {
- invoke_selector(INV_SEL(s, client, canBeHere, kStopOnInvalidSelector), 0);
+ invokeSelector(INV_SEL(s, client, canBeHere, kStopOnInvalidSelector), 0);
}
if (!s->r_acc.offset) { // Contains the return value
- signal = GET_SEL32V(segMan, client, SELECTOR(signal));
+ signal = readSelectorValue(segMan, client, SELECTOR(signal));
- PUT_SEL32V(segMan, client, SELECTOR(x), oldx);
- PUT_SEL32V(segMan, client, SELECTOR(y), oldy);
- PUT_SEL32V(segMan, client, SELECTOR(signal), (signal | kSignalHitObstacle));
+ writeSelectorValue(segMan, client, SELECTOR(x), oldx);
+ writeSelectorValue(segMan, client, SELECTOR(y), oldy);
+ writeSelectorValue(segMan, client, SELECTOR(signal), (signal | kSignalHitObstacle));
debugC(2, kDebugLevelBresen, "Finished mover %04x:%04x by collision", PRINT_REG(mover));
completed = 1;
}
- // FIXME: find out why iceman needs this and we ask for version > SCI01
- if ((getSciVersion() > SCI_VERSION_01) || (s->_gameId == "iceman"))
+ if ((getSciVersion() >= SCI_VERSION_1_EGA))
if (completed)
- invoke_selector(INV_SEL(s, mover, moveDone, kStopOnInvalidSelector), 0);
+ invokeSelector(INV_SEL(s, mover, moveDone, kStopOnInvalidSelector), 0);
return make_reg(0, completed);
}
@@ -378,15 +377,15 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
- client = GET_SEL32(segMan, avoider, SELECTOR(client));
+ client = readSelector(segMan, avoider, SELECTOR(client));
if (!s->_segMan->isHeapObject(client)) {
warning("DoAvoider() where client %04x:%04x is not an object", PRINT_REG(client));
return NULL_REG;
}
- looper = GET_SEL32(segMan, client, SELECTOR(looper));
- mover = GET_SEL32(segMan, client, SELECTOR(mover));
+ looper = readSelector(segMan, client, SELECTOR(looper));
+ mover = readSelector(segMan, client, SELECTOR(mover));
if (!s->_segMan->isHeapObject(mover)) {
if (mover.segment) {
@@ -395,38 +394,38 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
- destx = GET_SEL32V(segMan, mover, SELECTOR(x));
- desty = GET_SEL32V(segMan, mover, SELECTOR(y));
+ destx = readSelectorValue(segMan, mover, SELECTOR(x));
+ desty = readSelectorValue(segMan, mover, SELECTOR(y));
debugC(2, kDebugLevelBresen, "Doing avoider %04x:%04x (dest=%d,%d)", PRINT_REG(avoider), destx, desty);
- if (invoke_selector(INV_SEL(s, mover, doit, kContinueOnInvalidSelector) , 0)) {
+ if (invokeSelector(INV_SEL(s, mover, doit, kContinueOnInvalidSelector) , 0)) {
error("Mover %04x:%04x of avoider %04x:%04x doesn't have a doit() funcselector", PRINT_REG(mover), PRINT_REG(avoider));
return NULL_REG;
}
- mover = GET_SEL32(segMan, client, SELECTOR(mover));
+ mover = readSelector(segMan, client, SELECTOR(mover));
if (!mover.segment) // Mover has been disposed?
return s->r_acc; // Return gracefully.
- if (invoke_selector(INV_SEL(s, client, isBlocked, kContinueOnInvalidSelector) , 0)) {
+ if (invokeSelector(INV_SEL(s, client, isBlocked, kContinueOnInvalidSelector) , 0)) {
error("Client %04x:%04x of avoider %04x:%04x doesn't"
" have an isBlocked() funcselector", PRINT_REG(client), PRINT_REG(avoider));
return NULL_REG;
}
- dx = destx - GET_SEL32V(segMan, client, SELECTOR(x));
- dy = desty - GET_SEL32V(segMan, client, SELECTOR(y));
+ dx = destx - readSelectorValue(segMan, client, SELECTOR(x));
+ dy = desty - readSelectorValue(segMan, client, SELECTOR(y));
angle = getAngle(dx, dy);
debugC(2, kDebugLevelBresen, "Movement (%d,%d), angle %d is %sblocked", dx, dy, angle, (s->r_acc.offset) ? " " : "not ");
if (s->r_acc.offset) { // isBlocked() returned non-zero
int rotation = (rand() & 1) ? 45 : (360 - 45); // Clockwise/counterclockwise
- int oldx = GET_SEL32V(segMan, client, SELECTOR(x));
- int oldy = GET_SEL32V(segMan, client, SELECTOR(y));
- int xstep = GET_SEL32V(segMan, client, SELECTOR(xStep));
- int ystep = GET_SEL32V(segMan, client, SELECTOR(yStep));
+ int oldx = readSelectorValue(segMan, client, SELECTOR(x));
+ int oldy = readSelectorValue(segMan, client, SELECTOR(y));
+ int xstep = readSelectorValue(segMan, client, SELECTOR(xStep));
+ int ystep = readSelectorValue(segMan, client, SELECTOR(yStep));
int moves;
debugC(2, kDebugLevelBresen, " avoider %04x:%04x", PRINT_REG(avoider));
@@ -435,23 +434,23 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
int move_x = (int)(sin(angle * PI / 180.0) * (xstep));
int move_y = (int)(-cos(angle * PI / 180.0) * (ystep));
- PUT_SEL32V(segMan, client, SELECTOR(x), oldx + move_x);
- PUT_SEL32V(segMan, client, SELECTOR(y), oldy + move_y);
+ writeSelectorValue(segMan, client, SELECTOR(x), oldx + move_x);
+ writeSelectorValue(segMan, client, SELECTOR(y), oldy + move_y);
debugC(2, kDebugLevelBresen, "Pos (%d,%d): Trying angle %d; delta=(%d,%d)", oldx, oldy, angle, move_x, move_y);
- if (invoke_selector(INV_SEL(s, client, canBeHere, kContinueOnInvalidSelector) , 0)) {
+ if (invokeSelector(INV_SEL(s, client, canBeHere, kContinueOnInvalidSelector) , 0)) {
error("Client %04x:%04x of avoider %04x:%04x doesn't"
" have a canBeHere() funcselector", PRINT_REG(client), PRINT_REG(avoider));
return NULL_REG;
}
- PUT_SEL32V(segMan, client, SELECTOR(x), oldx);
- PUT_SEL32V(segMan, client, SELECTOR(y), oldy);
+ writeSelectorValue(segMan, client, SELECTOR(x), oldx);
+ writeSelectorValue(segMan, client, SELECTOR(y), oldy);
if (s->r_acc.offset) { // We can be here
debugC(2, kDebugLevelBresen, "Success");
- PUT_SEL32V(segMan, client, SELECTOR(heading), angle);
+ writeSelectorValue(segMan, client, SELECTOR(heading), angle);
return make_reg(0, angle);
}
@@ -464,17 +463,17 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
warning("DoAvoider failed for avoider %04x:%04x", PRINT_REG(avoider));
} else {
- int heading = GET_SEL32V(segMan, client, SELECTOR(heading));
+ int heading = readSelectorValue(segMan, client, SELECTOR(heading));
if (heading == -1)
return s->r_acc; // No change
- PUT_SEL32V(segMan, client, SELECTOR(heading), angle);
+ writeSelectorValue(segMan, client, SELECTOR(heading), angle);
s->r_acc = make_reg(0, angle);
if (looper.segment) {
- if (invoke_selector(INV_SEL(s, looper, doit, kContinueOnInvalidSelector), 2, angle, client)) {
+ if (invokeSelector(INV_SEL(s, looper, doit, kContinueOnInvalidSelector), 2, angle, client)) {
error("Looper %04x:%04x of avoider %04x:%04x doesn't"
" have a doit() funcselector", PRINT_REG(looper), PRINT_REG(avoider));
} else
diff --git a/engines/sci/engine/kparse.cpp b/engines/sci/engine/kparse.cpp
index 0254d21642..785ff39d22 100644
--- a/engines/sci/engine/kparse.cpp
+++ b/engines/sci/engine/kparse.cpp
@@ -42,6 +42,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
reg_t heap_said_block = argv[0];
byte *said_block;
int new_lastmatch;
+ Vocabulary *voc = g_sci->getVocabulary();
#ifdef DEBUG_PARSER
const int debug_parser = 1;
#else
@@ -63,7 +64,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
s->_voc->decipherSaidBlock(said_block);
#endif
- if (s->_voc->parser_event.isNull() || (GET_SEL32V(s->_segMan, s->_voc->parser_event, SELECTOR(claimed)))) {
+ if (voc->parser_event.isNull() || (readSelectorValue(s->_segMan, voc->parser_event, SELECTOR(claimed)))) {
return NULL_REG;
}
@@ -77,7 +78,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
s->r_acc = make_reg(0, 1);
if (new_lastmatch != SAID_PARTIAL_MATCH)
- PUT_SEL32V(s->_segMan, s->_voc->parser_event, SELECTOR(claimed), 1);
+ writeSelectorValue(s->_segMan, voc->parser_event, SELECTOR(claimed), 1);
} else {
return NULL_REG;
@@ -92,15 +93,15 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) {
char *error;
ResultWordList words;
reg_t event = argv[1];
- Vocabulary *voc = s->_voc;
+ Vocabulary *voc = g_sci->getVocabulary();
- s->_voc->parser_event = event;
+ voc->parser_event = event;
bool res = voc->tokenizeString(words, string.c_str(), &error);
- s->_voc->parserIsValid = false; /* not valid */
+ voc->parserIsValid = false; /* not valid */
if (res && !words.empty()) {
- s->_voc->synonymizeTokens(words);
+ voc->synonymizeTokens(words);
s->r_acc = make_reg(0, 1);
@@ -115,32 +116,32 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) {
if (syntax_fail) {
s->r_acc = make_reg(0, 1);
- PUT_SEL32V(segMan, event, SELECTOR(claimed), 1);
+ writeSelectorValue(segMan, event, SELECTOR(claimed), 1);
- invoke_selector(INV_SEL(s, s->_gameObj, syntaxFail, kStopOnInvalidSelector), 2, s->_voc->parser_base, stringpos);
+ invokeSelector(INV_SEL(s, s->_gameObj, syntaxFail, kStopOnInvalidSelector), 2, voc->parser_base, stringpos);
/* Issue warning */
debugC(2, kDebugLevelParser, "Tree building failed");
} else {
- s->_voc->parserIsValid = true;
- PUT_SEL32V(segMan, event, SELECTOR(claimed), 0);
+ voc->parserIsValid = true;
+ writeSelectorValue(segMan, event, SELECTOR(claimed), 0);
#ifdef DEBUG_PARSER
- s->_voc->dumpParseTree();
+ voc->dumpParseTree();
#endif
}
} else {
s->r_acc = make_reg(0, 0);
- PUT_SEL32V(segMan, event, SELECTOR(claimed), 1);
+ writeSelectorValue(segMan, event, SELECTOR(claimed), 1);
if (error) {
- s->_segMan->strcpy(s->_voc->parser_base, error);
+ s->_segMan->strcpy(voc->parser_base, error);
debugC(2, kDebugLevelParser, "Word unknown: %s", error);
/* Issue warning: */
- invoke_selector(INV_SEL(s, s->_gameObj, wordFail, kStopOnInvalidSelector), 2, s->_voc->parser_base, stringpos);
+ invokeSelector(INV_SEL(s, s->_gameObj, wordFail, kStopOnInvalidSelector), 2, voc->parser_base, stringpos);
free(error);
return make_reg(0, 1); /* Tell them that it didn't work */
}
@@ -156,28 +157,29 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) {
Node *node;
int script;
int numSynonyms = 0;
+ Vocabulary *voc = g_sci->getVocabulary();
// Only SCI0-SCI1 EGA games had a parser. In newer versions, this is a stub
if (getSciVersion() > SCI_VERSION_1_EGA)
return s->r_acc;
- s->_voc->clearSynonyms();
+ voc->clearSynonyms();
- list = s->_segMan->lookupList(GET_SEL32(segMan, object, SELECTOR(elements)));
+ list = s->_segMan->lookupList(readSelector(segMan, object, SELECTOR(elements)));
node = s->_segMan->lookupNode(list->first);
while (node) {
reg_t objpos = node->value;
int seg;
- script = GET_SEL32V(segMan, objpos, SELECTOR(number));
+ script = readSelectorValue(segMan, objpos, SELECTOR(number));
seg = s->_segMan->getScriptSegment(script);
if (seg > 0)
numSynonyms = s->_segMan->getScript(seg)->getSynonymsNr();
if (numSynonyms) {
- byte *synonyms = s->_segMan->getScript(seg)->getSynonyms();
+ const byte *synonyms = s->_segMan->getScript(seg)->getSynonyms();
if (synonyms) {
debugC(2, kDebugLevelParser, "Setting %d synonyms for script.%d",
@@ -193,7 +195,7 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) {
synonym_t tmp;
tmp.replaceant = (int16)READ_LE_UINT16(synonyms + i * 4);
tmp.replacement = (int16)READ_LE_UINT16(synonyms + i * 4 + 2);
- s->_voc->addSynonym(tmp);
+ voc->addSynonym(tmp);
}
} else
warning("Synonyms of script.%03d were requested, but script is not available", script);
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index 25d967c247..857ccc2a08 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -337,15 +337,15 @@ static void draw_point(EngineState *s, Common::Point p, int start, int width, in
static void draw_polygon(EngineState *s, reg_t polygon, int width, int height) {
SegManager *segMan = s->_segMan;
- reg_t points = GET_SEL32(segMan, polygon, SELECTOR(points));
+ reg_t points = readSelector(segMan, polygon, SELECTOR(points));
#ifdef ENABLE_SCI32
if (segMan->isHeapObject(points))
- points = GET_SEL32(segMan, points, SELECTOR(data));
+ points = readSelector(segMan, points, SELECTOR(data));
#endif
- int size = GET_SEL32V(segMan, polygon, SELECTOR(size));
- int type = GET_SEL32V(segMan, polygon, SELECTOR(type));
+ int size = readSelectorValue(segMan, polygon, SELECTOR(size));
+ int type = readSelectorValue(segMan, polygon, SELECTOR(type));
Common::Point first, prev;
int i;
@@ -386,15 +386,15 @@ static void draw_input(EngineState *s, reg_t poly_list, Common::Point start, Com
}
static void print_polygon(SegManager *segMan, reg_t polygon) {
- reg_t points = GET_SEL32(segMan, polygon, SELECTOR(points));
+ reg_t points = readSelector(segMan, polygon, SELECTOR(points));
#ifdef ENABLE_SCI32
if (segMan->isHeapObject(points))
- points = GET_SEL32(segMan, points, SELECTOR(data));
+ points = readSelector(segMan, points, SELECTOR(data));
#endif
- int size = GET_SEL32V(segMan, polygon, SELECTOR(size));
- int type = GET_SEL32V(segMan, polygon, SELECTOR(type));
+ int size = readSelectorValue(segMan, polygon, SELECTOR(size));
+ int type = readSelectorValue(segMan, polygon, SELECTOR(type));
int i;
Common::Point point;
@@ -1036,13 +1036,13 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) {
// Returns : (Polygon *) The converted polygon, or NULL on error
SegManager *segMan = s->_segMan;
int i;
- reg_t points = GET_SEL32(segMan, polygon, SELECTOR(points));
- int size = GET_SEL32V(segMan, polygon, SELECTOR(size));
+ reg_t points = readSelector(segMan, polygon, SELECTOR(points));
+ int size = readSelectorValue(segMan, polygon, SELECTOR(size));
#ifdef ENABLE_SCI32
// SCI32 stores the actual points in the data property of points (in a new array)
if (segMan->isHeapObject(points))
- points = GET_SEL32(segMan, points, SELECTOR(data));
+ points = readSelector(segMan, points, SELECTOR(data));
#endif
if (size == 0) {
@@ -1050,13 +1050,13 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) {
return NULL;
}
- Polygon *poly = new Polygon(GET_SEL32V(segMan, polygon, SELECTOR(type)));
+ Polygon *poly = new Polygon(readSelectorValue(segMan, polygon, SELECTOR(type)));
int skip = 0;
// WORKAROUND: broken polygon in lsl1sci, room 350, after opening elevator
// Polygon has 17 points but size is set to 19
- if ((size == 19) && (s->_gameId == "lsl1sci")) {
+ if ((size == 19) && !strcmp(g_sci->getGameID(), "lsl1sci")) {
if ((s->currentRoomNumber() == 350)
&& (read_point(segMan, points, 18) == Common::Point(108, 137))) {
debug(1, "Applying fix for broken polygon in lsl1sci, room 350");
@@ -1121,7 +1121,7 @@ static PathfindingState *convert_polygon_set(EngineState *s, reg_t poly_list, Co
if (polygon) {
pf_s->polygons.push_back(polygon);
- count += GET_SEL32V(segMan, node->value, SELECTOR(size));
+ count += readSelectorValue(segMan, node->value, SELECTOR(size));
}
node = s->_segMan->lookupNode(node->succ);
@@ -1174,7 +1174,7 @@ static PathfindingState *convert_polygon_set(EngineState *s, reg_t poly_list, Co
// WORKAROUND LSL5 room 660. Priority glitch due to us choosing a different path
// than SSCI. Happens when Patti walks to the control room.
- if ((s->_gameId == "lsl5") && (s->currentRoomNumber() == 660) && (Common::Point(67, 131) == *new_start) && (Common::Point(229, 101) == *new_end)) {
+ if (!strcmp(g_sci->getGameID(), "lsl5") && (s->currentRoomNumber() == 660) && (Common::Point(67, 131) == *new_start) && (Common::Point(229, 101) == *new_end)) {
debug(1, "[avoidpath] Applying fix for priority problem in LSL5, room 660");
pf_s->_prependPoint = new_start;
new_start = new Common::Point(77, 107);
@@ -1394,7 +1394,7 @@ reg_t kAvoidPath(EngineState *s, int argc, reg_t *argv) {
if (argc < 7)
error("[avoidpath] Not enough arguments");
- poly_list = (!argv[4].isNull() ? GET_SEL32(s->_segMan, argv[4], SELECTOR(elements)) : NULL_REG);
+ poly_list = (!argv[4].isNull() ? readSelector(s->_segMan, argv[4], SELECTOR(elements)) : NULL_REG);
width = argv[5].toUint16();
height = argv[6].toUint16();
if (argc > 7)
@@ -1694,4 +1694,38 @@ reg_t kIntersections(EngineState *s, int argc, reg_t *argv) {
}
}
+// This is a quite rare kernel function. An example of when it's called
+// is in QFG1VGA, after killing any monster.
+reg_t kMergePoly(EngineState *s, int argc, reg_t *argv) {
+ // 3 parameters: raw polygon data, polygon list, list size
+ reg_t polygonData = argv[0];
+
+ // TODO: actually merge the polygon
+ // In QFG1VGA, there are no immediately visible side-effects
+ // of this being a stub.
+
+#if 0
+ List *list = s->_segMan->lookupList(argv[1]);
+ Node *node = s->_segMan->lookupNode(list->first);
+ // List size is not needed
+
+ Polygon *polygon;
+ int count = 0;
+
+ while (node) {
+ polygon = convert_polygon(s, node->value);
+
+ if (polygon) {
+ count += readSelectorValue(s->_segMan, node->value, SELECTOR(size));
+ }
+
+ node = s->_segMan->lookupNode(node->succ);
+ }
+#endif
+
+ warning("Stub: kMergePoly");
+
+ return polygonData;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index ba29f64966..722d0175d1 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -111,7 +111,7 @@ reg_t kResCheck(EngineState *s, int argc, reg_t *argv) {
reg_t kClone(EngineState *s, int argc, reg_t *argv) {
reg_t parent_addr = argv[0];
- Object *parent_obj = s->_segMan->getObject(parent_addr);
+ const Object *parent_obj = s->_segMan->getObject(parent_addr);
reg_t clone_addr;
Clone *clone_obj; // same as Object*
@@ -132,7 +132,7 @@ reg_t kClone(EngineState *s, int argc, reg_t *argv) {
*clone_obj = *parent_obj;
// Mark as clone
- clone_obj->setInfoSelector(make_reg(0, SCRIPT_INFO_CLONE));
+ clone_obj->markAsClone();
clone_obj->setSpeciesSelector(clone_obj->getPos());
if (parent_obj->isClass())
clone_obj->setSuperClassSelector(parent_obj->getPos());
@@ -154,14 +154,14 @@ reg_t kDisposeClone(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
- if (victim_obj->getInfoSelector().offset != SCRIPT_INFO_CLONE) {
+ if (!victim_obj->isClone()) {
//warning("Attempt to dispose something other than a clone at %04x", offset);
// SCI silently ignores this behaviour; some games actually depend on it
return s->r_acc;
}
// QFG3 clears clones with underbits set
- //if (GET_SEL32V(victim_addr, underBits))
+ //if (readSelectorValue(victim_addr, underBits))
// warning("Clone %04x:%04x was cleared with underBits set", PRINT_REG(victim_addr));
#if 0
@@ -181,7 +181,7 @@ reg_t kDisposeClone(EngineState *s, int argc, reg_t *argv) {
// Returns script dispatch address index in the supplied script
reg_t kScriptID(EngineState *s, int argc, reg_t *argv) {
int script = argv[0].toUint16();
- int index = (argc > 1) ? argv[1].toUint16() : 0;
+ uint16 index = (argc > 1) ? argv[1].toUint16() : 0;
if (argv[0].segment)
return argv[0];
@@ -193,18 +193,30 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) {
Script *scr = s->_segMan->getScript(scriptSeg);
- if (!scr->_numExports) {
- // FIXME: Is this fatal? This occurs in SQ4CD
- warning("Script 0x%x does not have a dispatch table", script);
+ if (!scr->getExportsNr()) {
+ // This is normal. Some scripts don't have a dispatch (exports) table,
+ // and this call is probably used to load them in memory, ignoring
+ // the return value. If only one argument is passed, this call is done
+ // only to load the script in memory. Thus, don't show any warning,
+ // as no return value is expected
+ if (argc == 2)
+ warning("Script 0x%x does not have a dispatch table and export %d "
+ "was requested from it", script, index);
return NULL_REG;
}
- if (index > scr->_numExports) {
- error("Dispatch index too big: %d > %d", index, scr->_numExports);
+ if (index > scr->getExportsNr()) {
+ error("Dispatch index too big: %d > %d", index, scr->getExportsNr());
return NULL_REG;
}
- return make_reg(scriptSeg, scr->validateExportFunc(index));
+ uint16 address = scr->validateExportFunc(index);
+
+ // Point to the heap for SCI1.1+ games
+ if (getSciVersion() >= SCI_VERSION_1_1)
+ address += scr->getScriptSize();
+
+ return make_reg(scriptSeg, address);
}
reg_t kDisposeScript(EngineState *s, int argc, reg_t *argv) {
@@ -244,7 +256,7 @@ reg_t kRespondsTo(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[0];
int selector = argv[1].toUint16();
- return make_reg(0, s->_segMan->isHeapObject(obj) && lookup_selector(s->_segMan, obj, selector, NULL, NULL) != kSelectorNone);
+ return make_reg(0, s->_segMan->isHeapObject(obj) && lookupSelector(s->_segMan, obj, selector, NULL, NULL) != kSelectorNone);
}
} // End of namespace Sci
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 426c682e11..2681b612e9 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -138,10 +138,36 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) {
while (isspace((unsigned char)*source))
source++; /* Skip whitespace */
- if (*source == '$') /* SCI uses this for hex numbers */
- return make_reg(0, (int16)strtol(source + 1, NULL, 16)); /* Hex */
- else
- return make_reg(0, (int16)strtol(source, NULL, 10)); /* Force decimal */
+ int16 result = 0;
+
+ if (*source == '$') {
+ // hexadecimal input
+ result = (int16)strtol(source + 1, NULL, 16);
+ } else {
+ // decimal input, we can not use strtol/atoi in here, because sierra used atoi BUT it was a non standard compliant
+ // atoi, that didnt do clipping. In SQ4 we get the door code in here and that's even larger than uint32!
+ if (*source == '-') {
+ result = -1;
+ source++;
+ }
+ while (*source) {
+ if ((*source < '0') || (*source > '9')) {
+ // Sierras atoi stopped processing at anything different than number
+ // Sometimes the input has a trailing space, that's fine (example: lsl3)
+ if (*source != ' ') {
+ // TODO: this happens in lsl5 right in the intro -> we get '1' '3' 0xCD 0xCD 0xCD 0xCD 0xCD
+ // find out why this happens and fix it
+ warning("Invalid character in kReadNumber input");
+ }
+ break;
+ }
+ result *= 10;
+ result += *source - 0x30;
+ source++;
+ }
+ }
+
+ return make_reg(0, result);
}
@@ -241,7 +267,7 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) {
#ifdef ENABLE_SCI32
// If the string is a string object, get to the actual string in the data selector
if (s->_segMan->isObject(reg))
- reg = GET_SEL32(s->_segMan, reg, SELECTOR(data));
+ reg = readSelector(s->_segMan, reg, SELECTOR(data));
#endif
Common::String tempsource = (reg == NULL_REG) ? "" : g_sci->getKernel()->lookupText(reg,
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index fef2b9a19e..9bf23dedf5 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -383,7 +383,7 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
sync_SegManagerPtr(s, _segMan);
- syncArray<Class>(s, _segMan->_classtable);
+ syncArray<Class>(s, _segMan->_classTable);
#ifdef USE_OLD_MUSIC_FUNCTIONS
sync_songlib(s, _sound._songlib);
@@ -541,8 +541,8 @@ void Script::saveLoadWithSerializer(Common::Serializer &s) {
}
}
- s.syncAsSint32LE(_numExports);
- s.syncAsSint32LE(_numSynonyms);
+ s.skip(4, VER(9), VER(19)); // OBSOLETE: Used to be _numExports
+ s.skip(4, VER(9), VER(19)); // OBSOLETE: Used to be _numSynonyms
s.syncAsSint32LE(_lockers);
// Sync _objects. This is a hashmap, and we use the following on disk format:
@@ -615,7 +615,7 @@ void DynMem::saveLoadWithSerializer(Common::Serializer &s) {
void DataStack::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsUint32LE(_capacity);
if (s.isLoading()) {
- //free(entries);
+ free(_entries);
_entries = (reg_t *)calloc(_capacity, sizeof(reg_t));
}
}
@@ -731,15 +731,6 @@ int gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename
return 1;
}
-/*
- if (s->sound_server) {
- if ((s->sound_server->save)(s, dirname)) {
- warning("Saving failed for the sound subsystem");
- //chdir("..");
- return 1;
- }
- }
-*/
Common::Serializer ser(0, fh);
sync_SavegameMetadata(ser, meta);
Graphics::saveThumbnail(*fh);
@@ -748,26 +739,6 @@ int gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename
return 0;
}
-static byte *find_unique_script_block(EngineState *s, byte *buf, int type) {
- bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
-
- if (oldScriptHeader)
- buf += 2;
-
- do {
- int seeker_type = READ_LE_UINT16(buf);
-
- if (seeker_type == 0) break;
- if (seeker_type == type) return buf;
-
- int seeker_size = READ_LE_UINT16(buf + 2);
- assert(seeker_size > 0);
- buf += seeker_size;
- } while (1);
-
- return NULL;
-}
-
// TODO: This should probably be turned into an EngineState or DataStack method.
static void reconstruct_stack(EngineState *retval) {
SegmentId stack_seg = retval->_segMan->findSegmentByType(SEG_TYPE_STACK);
@@ -777,99 +748,37 @@ static void reconstruct_stack(EngineState *retval) {
retval->stack_top = stack->_entries + stack->_capacity;
}
-static void load_script(EngineState *s, Script *scr) {
- scr->_buf = (byte *)malloc(scr->_bufSize);
- assert(scr->_buf);
-
- Resource *script = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, scr->_nr), 0);
- assert(script != 0);
-
- assert(scr->_bufSize >= script->size);
- memcpy(scr->_buf, script->data, script->size);
-
- if (getSciVersion() >= SCI_VERSION_1_1) {
- Resource *heap = g_sci->getResMan()->findResource(ResourceId(kResourceTypeHeap, scr->_nr), 0);
- assert(heap != 0);
-
- scr->_heapStart = scr->_buf + scr->_scriptSize;
-
- assert(scr->_bufSize - scr->_scriptSize <= heap->size);
- memcpy(scr->_heapStart, heap->data, heap->size);
- }
-}
-
// TODO: Move thie function to a more appropriate place, such as vm.cpp or script.cpp
void SegManager::reconstructScripts(EngineState *s) {
uint i;
- SegmentObj *mobj;
for (i = 0; i < _heap.size(); i++) {
- mobj = _heap[i];
- if (!mobj || mobj->getType() != SEG_TYPE_SCRIPT)
+ if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
continue;
- Script *scr = (Script *)mobj;
-
- // FIXME: Unify this code with script_instantiate_* ?
- load_script(s, scr);
+ Script *scr = (Script *)_heap[i];
+ scr->load(g_sci->getResMan());
scr->_localsBlock = (scr->_localsSegment == 0) ? NULL : (LocalVariables *)(_heap[scr->_localsSegment]);
- if (getSciVersion() >= SCI_VERSION_1_1) {
- scr->_exportTable = 0;
- scr->_synonyms = 0;
- if (READ_LE_UINT16(scr->_buf + 6) > 0) {
- scr->setExportTableOffset(6);
- s->_segMan->scriptRelocateExportsSci11(i);
- }
- } else {
- scr->_exportTable = (uint16 *) find_unique_script_block(s, scr->_buf, SCI_OBJ_EXPORTS);
- scr->_synonyms = find_unique_script_block(s, scr->_buf, SCI_OBJ_SYNONYMS);
- scr->_exportTable += 3;
- }
- scr->_codeBlocks.clear();
- ObjMap::iterator it;
- const ObjMap::iterator end = scr->_objects.end();
- for (it = scr->_objects.begin(); it != end; ++it) {
- byte *data = scr->_buf + it->_value.getPos().offset;
- it->_value._baseObj = data;
- }
+ for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it)
+ it->_value._baseObj = scr->_buf + it->_value.getPos().offset;
}
for (i = 0; i < _heap.size(); i++) {
- mobj = _heap[i];
- if (!mobj || mobj->getType() != SEG_TYPE_SCRIPT)
+ if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
continue;
- Script *scr = (Script *)mobj;
+ Script *scr = (Script *)_heap[i];
- // FIXME: Unify this code with Script::scriptObjInit ?
- ObjMap::iterator it;
- const ObjMap::iterator end = scr->_objects.end();
- for (it = scr->_objects.begin(); it != end; ++it) {
- byte *data = scr->_buf + it->_value.getPos().offset;
-
- if (getSciVersion() >= SCI_VERSION_1_1) {
- uint16 *funct_area = (uint16 *)(scr->_buf + READ_LE_UINT16( data + 6 ));
- uint16 *prop_area = (uint16 *)(scr->_buf + READ_LE_UINT16( data + 4 ));
-
- it->_value._baseMethod = funct_area;
- it->_value._baseVars = prop_area;
- } else {
- int funct_area = READ_LE_UINT16(data + SCRIPT_FUNCTAREAPTR_OFFSET);
- Object *_baseObj;
-
- _baseObj = s->_segMan->getObject(it->_value.getSpeciesSelector());
-
- if (!_baseObj) {
- warning("Object without a base class: Script %d, index %d (reg address %04x:%04x",
- scr->_nr, i, PRINT_REG(it->_value.getSpeciesSelector()));
- continue;
- }
- it->_value.setVarCount(_baseObj->getVarCount());
- it->_value._baseObj = _baseObj->_baseObj;
+ for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) {
+ reg_t addr = it->_value.getPos();
+ Object *obj = scr->scriptObjInit(addr, false);
- it->_value._baseMethod = (uint16 *)(data + funct_area);
- it->_value._baseVars = (uint16 *)(data + it->_value.getVarCount() * 2 + SCRIPT_SELECTOR_OFFSET);
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ if (!obj->initBaseObject(this, addr, false)) {
+ warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
+ scr->scriptObjRemove(addr);
+ }
}
}
}
@@ -912,7 +821,6 @@ static void reconstruct_sounds(EngineState *s) {
#endif
void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
- EngineState *retval;
#ifdef USE_OLD_MUSIC_FUNCTIONS
SongLibrary temp;
#endif
@@ -947,86 +855,68 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
thumbnail = 0;
}
- // Create a new EngineState object
- retval = new EngineState(s->_voc, s->_segMan);
- retval->_event = s->_event;
-
- // Copy some old data
- retval->_soundCmd = s->_soundCmd;
-
- // Copy memory segment
- retval->_memorySegmentSize = s->_memorySegmentSize;
- memcpy(retval->_memorySegment, s->_memorySegment, s->_memorySegmentSize);
-
- retval->saveLoadWithSerializer(ser); // FIXME: Error handling?
+ s->reset(true);
+ s->saveLoadWithSerializer(ser); // FIXME: Error handling?
#ifdef USE_OLD_MUSIC_FUNCTIONS
s->_sound.sfx_exit();
#endif
// Set exec stack base to zero
- retval->execution_stack_base = 0;
+ s->execution_stack_base = 0;
// Now copy all current state information
#ifdef USE_OLD_MUSIC_FUNCTIONS
- temp = retval->_sound._songlib;
- retval->_sound.sfx_init(g_sci->getResMan(), s->sfx_init_flags, g_sci->_features->detectDoSoundType());
- retval->sfx_init_flags = s->sfx_init_flags;
- retval->_sound._songlib.freeSounds();
- retval->_sound._songlib = temp;
- retval->_soundCmd->updateSfxState(&retval->_sound);
+ temp = s->_sound._songlib;
+ s->_sound.sfx_init(g_sci->getResMan(), s->sfx_init_flags, g_sci->_features->detectDoSoundType());
+ s->sfx_init_flags = s->sfx_init_flags;
+ s->_sound._songlib.freeSounds();
+ s->_sound._songlib = temp;
+ s->_soundCmd->updateSfxState(&retval->_sound);
#endif
- reconstruct_stack(retval);
- retval->_segMan->reconstructScripts(retval);
- retval->_segMan->reconstructClones();
- retval->_gameObj = s->_gameObj;
- retval->script_000 = retval->_segMan->getScript(retval->_segMan->getScriptSegment(0, SCRIPT_GET_DONT_LOAD));
- retval->gc_countdown = GC_INTERVAL - 1;
- retval->sys_strings_segment = retval->_segMan->findSegmentByType(SEG_TYPE_SYS_STRINGS);
- retval->sys_strings = (SystemStrings *)(retval->_segMan->_heap[retval->sys_strings_segment]);
+ reconstruct_stack(s);
+ s->_segMan->reconstructScripts(s);
+ s->_segMan->reconstructClones();
+ s->_gameObj = s->_gameObj;
+ s->script_000 = s->_segMan->getScript(s->_segMan->getScriptSegment(0, SCRIPT_GET_DONT_LOAD));
+ s->gc_countdown = GC_INTERVAL - 1;
// Time state:
- retval->last_wait_time = g_system->getMillis();
- retval->game_start_time = g_system->getMillis();
-
- // static parser information:
-
- if (retval->_voc)
- retval->_voc->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE);
+ s->last_wait_time = g_system->getMillis();
+ s->game_start_time = g_system->getMillis();
- retval->successor = NULL;
- retval->_gameId = s->_gameId;
+ s->restoring = false;
#ifdef USE_OLD_MUSIC_FUNCTIONS
- retval->_sound._it = NULL;
- retval->_sound._flags = s->_sound._flags;
- retval->_sound._song = NULL;
- retval->_sound._suspended = s->_sound._suspended;
- reconstruct_sounds(retval);
+ s->_sound._it = NULL;
+ s->_sound._flags = s->_sound._flags;
+ s->_sound._song = NULL;
+ s->_sound._suspended = s->_sound._suspended;
+ reconstruct_sounds(s);
#else
- retval->_soundCmd->reconstructPlayList(meta.savegame_version);
+ s->_soundCmd->reconstructPlayList(meta.savegame_version);
#endif
// Message state:
- retval->_msgState = new MessageState(retval->_segMan);
+ s->_msgState = new MessageState(s->_segMan);
#ifdef ENABLE_SCI32
if (g_sci->_gui32) {
g_sci->_gui32->init();
} else {
#endif
- g_sci->_gui->resetEngineState(retval);
+ g_sci->_gui->resetEngineState(s);
g_sci->_gui->init(g_sci->_features->usesOldGfxFunctions());
#ifdef ENABLE_SCI32
}
#endif
- s->successor = retval; // Set successor
- script_abort_flag = 2; // Abort current game with replay
- shrink_execution_stack(s, s->execution_stack_base + 1);
+ s->restoring = true;
+ s->script_abort_flag = 2; // Abort current game with replay
+ s->shrinkStackToBase();
}
bool get_savegame_metadata(Common::SeekableReadStream *stream, SavegameMetadata *meta) {
diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h
index bad79fca27..7be05381da 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -36,7 +36,7 @@ namespace Sci {
struct EngineState;
enum {
- CURRENT_SAVEGAME_VERSION = 19,
+ CURRENT_SAVEGAME_VERSION = 20,
MINIMUM_SAVEGAME_VERSION = 9
};
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index e9b1ce3f28..1f32e50b67 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -123,13 +123,13 @@ void SegManager::createClassTable() {
error("SegManager: failed to open vocab 996");
int totalClasses = vocab996->size >> 2;
- _classtable.resize(totalClasses);
+ _classTable.resize(totalClasses);
for (uint16 classNr = 0; classNr < totalClasses; classNr++) {
uint16 scriptNr = READ_SCI11ENDIAN_UINT16(vocab996->data + classNr * 4 + 2);
- _classtable[classNr].reg = NULL_REG;
- _classtable[classNr].script = scriptNr;
+ _classTable[classNr].reg = NULL_REG;
+ _classTable[classNr].script = scriptNr;
}
_resMan->unlockResource(vocab996);
@@ -139,11 +139,11 @@ reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, reg_t caller
if (classnr == 0xffff)
return NULL_REG;
- if (classnr < 0 || (int)_classtable.size() <= classnr || _classtable[classnr].script < 0) {
- error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, _classtable.size());
+ if (classnr < 0 || (int)_classTable.size() <= classnr || _classTable[classnr].script < 0) {
+ error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, _classTable.size());
return NULL_REG;
} else {
- Class *the_class = &_classtable[classnr];
+ Class *the_class = &_classTable[classnr];
if (!the_class->reg.segment) {
getScriptSegment(the_class->script, lock);
@@ -175,7 +175,7 @@ void SegManager::scriptInitialiseLocals(reg_t location) {
Script *scr = getScript(location.segment);
unsigned int count;
- VERIFY(location.offset + 1 < (uint16)scr->_bufSize, "Locals beyond end of script\n");
+ VERIFY(location.offset + 1 < (uint16)scr->getBufSize(), "Locals beyond end of script\n");
if (getSciVersion() >= SCI_VERSION_1_1)
count = READ_SCI11ENDIAN_UINT16(scr->_buf + location.offset - 2);
@@ -185,55 +185,38 @@ void SegManager::scriptInitialiseLocals(reg_t location) {
scr->_localsOffset = location.offset;
- if (!(location.offset + count * 2 + 1 < scr->_bufSize)) {
- warning("Locals extend beyond end of script: offset %04x, count %x vs size %x", location.offset, count, (uint)scr->_bufSize);
- count = (scr->_bufSize - location.offset) >> 1;
+ if (!(location.offset + count * 2 + 1 < scr->getBufSize())) {
+ warning("Locals extend beyond end of script: offset %04x, count %x vs size %x", location.offset, count, (uint)scr->getBufSize());
+ count = (scr->getBufSize() - location.offset) >> 1;
}
LocalVariables *locals = allocLocalsSegment(scr, count);
if (locals) {
uint i;
- byte *base = (byte *)(scr->_buf + location.offset);
+ const byte *base = (const byte *)(scr->_buf + location.offset);
for (i = 0; i < count; i++)
locals->_locals[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(base + i * 2));
}
}
-void SegManager::scriptRelocateExportsSci11(SegmentId seg) {
- Script *scr = getScript(seg);
- for (int i = 0; i < scr->_numExports; i++) {
- /* We are forced to use an ugly heuristic here to distinguish function
- exports from object/class exports. The former kind points into the
- script resource, the latter into the heap resource. */
- uint16 location = READ_SCI11ENDIAN_UINT16((byte *)(scr->_exportTable + i));
-
- if ((location < scr->_heapSize - 1) && (READ_SCI11ENDIAN_UINT16(scr->_heapStart + location) == SCRIPT_OBJECT_MAGIC_NUMBER)) {
- WRITE_SCI11ENDIAN_UINT16((byte *)(scr->_exportTable + i), location + scr->_heapStart - scr->_buf);
- } else {
- // Otherwise it's probably a function export,
- // and we don't need to do anything.
- }
- }
-}
-
void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
Script *scr = getScript(seg);
- byte *seeker = scr->_heapStart + 4 + READ_SCI11ENDIAN_UINT16(scr->_heapStart + 2) * 2;
+ const byte *seeker = scr->_heapStart + 4 + READ_SCI11ENDIAN_UINT16(scr->_heapStart + 2) * 2;
while (READ_SCI11ENDIAN_UINT16(seeker) == SCRIPT_OBJECT_MAGIC_NUMBER) {
- if (READ_SCI11ENDIAN_UINT16(seeker + 14) & SCRIPT_INFO_CLASS) {
+ if (READ_SCI11ENDIAN_UINT16(seeker + 14) & kInfoFlagClass) { // -info- selector
int classpos = seeker - scr->_buf;
int species = READ_SCI11ENDIAN_UINT16(seeker + 10);
- if (species < 0 || species >= (int)_classtable.size()) {
+ if (species < 0 || species >= (int)_classTable.size()) {
error("Invalid species %d(0x%x) not in interval [0,%d) while instantiating script %d",
- species, species, _classtable.size(), scr->_nr);
+ species, species, _classTable.size(), scr->_nr);
return;
}
- _classtable[species].reg.segment = seg;
- _classtable[species].reg.offset = classpos;
+ _classTable[species].reg.segment = seg;
+ _classTable[species].reg.offset = classpos;
}
seeker += READ_SCI11ENDIAN_UINT16(seeker + 2) * 2;
}
@@ -243,19 +226,20 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
reg_t reg = make_reg(seg, seeker - scr->_buf);
Object *obj = scr->scriptObjInit(reg);
-#if 0
- if (obj->_variables[5].offset != 0xffff) {
- obj->_variables[5] = INST_LOOKUP_CLASS(obj->_variables[5].offset);
- baseObj = getObject(obj->_variables[5]);
- obj->variable_names_nr = baseObj->variables_nr;
- obj->_baseObj = baseObj->_baseObj;
- }
-#endif
-
// Copy base from species class, as we need its selector IDs
obj->setSuperClassSelector(
getClassAddress(obj->getSuperClassSelector().offset, SCRIPT_GET_LOCK, NULL_REG));
+ // If object is instance, get -propDict- from class and set it for this object
+ // This is needed for ::isMemberOf() to work.
+ // Example testcase - room 381 of sq4cd - if isMemberOf() doesn't work, talk-clicks on the robot will act like
+ // clicking on ego
+ if (!obj->isClass()) {
+ reg_t classObject = obj->getSuperClassSelector();
+ Object *classObj = getObject(classObject);
+ obj->setPropDictSelector(classObj->getPropDictSelector());
+ }
+
// Set the -classScript- selector to the script number.
// FIXME: As this selector is filled in at run-time, it is likely
// that it is supposed to hold a pointer. The Obj::isKindOf method
@@ -268,86 +252,24 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
}
}
-
-
-int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int script_nr, Resource **script, Resource **heap, int *was_new) {
- *was_new = 1;
-
- *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
- if (getSciVersion() >= SCI_VERSION_1_1)
- *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
-
- if (!*script || (getSciVersion() >= SCI_VERSION_1_1 && !heap)) {
- warning("Script 0x%x requested but not found", script_nr);
- if (getSciVersion() >= SCI_VERSION_1_1) {
- if (*heap)
- warning("Inconsistency: heap resource WAS found");
- else if (*script)
- warning("Inconsistency: script resource WAS found");
- }
- return 0;
- }
-
- SegmentId seg_id = segMan->getScriptSegment(script_nr);
- Script *scr = segMan->getScriptIfLoaded(seg_id);
- if (scr) {
- if (!scr->isMarkedAsDeleted()) {
- scr->incrementLockers();
- return seg_id;
- } else {
- scr->freeScript();
- }
- } else {
- scr = segMan->allocateScript(script_nr, &seg_id);
- if (!scr) { // ALL YOUR SCRIPT BASE ARE BELONG TO US
- error("Not enough heap space for script size 0x%x of script 0x%x (Should this happen?)", (*script)->size, script_nr);
- return 0;
- }
- }
-
- scr->init(script_nr, resMan);
-
- // Set heap position (beyond the size word)
- scr->setLockers(1);
- scr->setExportTableOffset(0);
- scr->setSynonymsOffset(0);
- scr->setSynonymsNr(0);
-
- *was_new = 0;
-
- return seg_id;
-}
-
-#define INST_LOOKUP_CLASS(id) ((id == 0xffff)? NULL_REG : segMan->getClassAddress(id, SCRIPT_GET_LOCK, addr))
-
-int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int script_nr) {
+void script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) {
int objType;
uint32 objLength = 0;
- int relocation = -1;
- Resource *script;
- int was_new;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
- const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, NULL, &was_new);
uint16 curOffset = oldScriptHeader ? 2 : 0;
- if (was_new)
- return seg_id;
-
- Script *scr = segMan->getScript(seg_id);
- scr->mcpyInOut(0, script->data, script->size);
-
if (oldScriptHeader) {
// Old script block
// There won't be a localvar block in this case
// Instead, the script starts with a 16 bit int specifying the
// number of locals we need; these are then allocated and zeroed.
- int locals_nr = READ_LE_UINT16(script->data);
- if (locals_nr)
- segMan->scriptInitialiseLocalsZero(seg_id, locals_nr);
+ int localsCount = READ_LE_UINT16(scr->_buf);
+ if (localsCount)
+ segMan->scriptInitialiseLocalsZero(segmentId, localsCount);
}
// Now do a first pass through the script objects to find the
- // export table and local variable block
+ // local variable blocks
do {
objType = scr->getHeap(curOffset);
@@ -355,48 +277,30 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr
break;
objLength = scr->getHeap(curOffset + 2);
-
- // This happens in some demos (e.g. the EcoQuest 1 demo). Not sure what is the
- // actual cause of it, but the scripts of these demos can't be loaded properly
- // and we're stuck forever in this loop, as objLength never changes
- if (!objLength) {
- warning("script_instantiate_sci0: objLength is 0, unable to parse script");
- return 0;
- }
-
curOffset += 4; // skip header
switch (objType) {
- case SCI_OBJ_EXPORTS:
- scr->setExportTableOffset(curOffset);
- break;
- case SCI_OBJ_SYNONYMS:
- scr->setSynonymsOffset(curOffset);
- scr->setSynonymsNr((objLength) / 4);
- break;
case SCI_OBJ_LOCALVARS:
- segMan->scriptInitialiseLocals(make_reg(seg_id, curOffset));
+ segMan->scriptInitialiseLocals(make_reg(segmentId, curOffset));
break;
-
case SCI_OBJ_CLASS: {
int classpos = curOffset - SCRIPT_OBJECT_MAGIC_OFFSET;
int species = scr->getHeap(curOffset - SCRIPT_OBJECT_MAGIC_OFFSET + SCRIPT_SPECIES_OFFSET);
- if (species < 0 || species >= (int)segMan->_classtable.size()) {
- if (species == (int)segMan->_classtable.size()) {
+ if (species < 0 || species >= (int)segMan->classTableSize()) {
+ if (species == (int)segMan->classTableSize()) {
// Happens in the LSL2 demo
warning("Applying workaround for an off-by-one invalid species access");
- segMan->_classtable.resize(segMan->_classtable.size() + 1);
+ segMan->resizeClassTable(segMan->classTableSize() + 1);
} else {
- warning("Invalid species %d(0x%x) not in interval "
- "[0,%d) while instantiating script %d\n",
- species, species, segMan->_classtable.size(),
- script_nr);
- return 0;
+ error("Invalid species %d(0x%x) not in interval "
+ "[0,%d) while instantiating script at segment %d\n",
+ species, species, segMan->classTableSize(),
+ segmentId);
+ return;
}
}
- segMan->_classtable[species].reg.segment = seg_id;
- segMan->_classtable[species].reg.offset = classpos;
+ segMan->setClassOffset(species, make_reg(segmentId, classpos));
// Set technical class position-- into the block allocated for it
}
break;
@@ -406,7 +310,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr
}
curOffset += objLength - 4;
- } while (objType != 0 && curOffset < script->size - 2);
+ } while (objType != 0 && curOffset < scr->getScriptSize() - 2);
// And now a second pass to adjust objects and class pointers, and the general pointers
objLength = 0;
@@ -420,7 +324,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr
objLength = scr->getHeap(curOffset + 2);
curOffset += 4; // skip header
- reg_t addr = make_reg(seg_id, curOffset);
+ reg_t addr = make_reg(segmentId, curOffset);
switch (objType) {
case SCI_OBJ_CODE:
@@ -429,77 +333,52 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr
case SCI_OBJ_OBJECT:
case SCI_OBJ_CLASS: { // object or class?
Object *obj = scr->scriptObjInit(addr);
+ obj->initSpecies(segMan, addr);
- // Instantiate the superclass, if neccessary
- obj->setSpeciesSelector(INST_LOOKUP_CLASS(obj->getSpeciesSelector().offset));
-
- Object *baseObj = segMan->getObject(obj->getSpeciesSelector());
-
- if (baseObj) {
- obj->setVarCount(baseObj->getVarCount());
- // Copy base from species class, as we need its selector IDs
- obj->_baseObj = baseObj->_baseObj;
-
- obj->setSuperClassSelector(INST_LOOKUP_CLASS(obj->getSuperClassSelector().offset));
- } else {
+ if (!obj->initBaseObject(segMan, addr)) {
warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
-
scr->scriptObjRemove(addr);
}
} // if object or class
break;
- case SCI_OBJ_POINTERS: // A relocation table
- relocation = addr.offset;
- break;
-
default:
break;
}
curOffset += objLength - 4;
- } while (objType != 0 && curOffset < script->size - 2);
-
- if (relocation >= 0)
- scr->scriptRelocate(make_reg(seg_id, relocation));
-
- return seg_id; // instantiation successful
+ } while (objType != 0 && curOffset < scr->getScriptSize() - 2);
}
-int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int script_nr) {
- Resource *script, *heap;
- int was_new;
- const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, &heap, &was_new);
-
- if (was_new)
- return seg_id;
-
- Script *scr = segMan->getScript(seg_id);
- int _heapStart = script->size;
-
- if (script->size & 2)
- _heapStart++;
-
- scr->mcpyInOut(0, script->data, script->size);
- scr->mcpyInOut(_heapStart, heap->data, heap->size);
-
- if (READ_SCI11ENDIAN_UINT16(script->data + 6) > 0)
- scr->setExportTableOffset(6);
-
- segMan->scriptInitialiseLocals(make_reg(seg_id, _heapStart + 4));
-
- segMan->scriptRelocateExportsSci11(seg_id);
- segMan->scriptInitialiseObjectsSci11(seg_id);
+int script_instantiate(ResourceManager *resMan, SegManager *segMan, int scriptNum) {
+ SegmentId segmentId = segMan->getScriptSegment(scriptNum);
+ Script *scr = segMan->getScriptIfLoaded(segmentId);
+ if (scr) {
+ if (!scr->isMarkedAsDeleted()) {
+ scr->incrementLockers();
+ return segmentId;
+ } else {
+ scr->freeScript();
+ }
+ } else {
+ scr = segMan->allocateScript(scriptNum, &segmentId);
+ }
- scr->heapRelocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(heap->data)));
+ scr->init(scriptNum, resMan);
+ scr->load(resMan);
- return seg_id;
-}
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ int heapStart = scr->getScriptSize();
+ segMan->scriptInitialiseLocals(make_reg(segmentId, heapStart + 4));
+ segMan->scriptInitialiseObjectsSci11(segmentId);
+ scr->relocate(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(scr->_heapStart)));
+ } else {
+ script_instantiate_sci0(scr, segmentId, segMan);
+ byte *relocationBlock = scr->findBlock(SCI_OBJ_POINTERS);
+ if (relocationBlock)
+ scr->relocate(make_reg(segmentId, relocationBlock - scr->_buf + 4));
+ }
-int script_instantiate(ResourceManager *resMan, SegManager *segMan, int script_nr) {
- if (getSciVersion() >= SCI_VERSION_1_1)
- return script_instantiate_sci11(resMan, segMan, script_nr);
- else
- return script_instantiate_sci0(resMan, segMan, script_nr);
+ return segmentId;
}
void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg) {
@@ -528,7 +407,7 @@ void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg)
superclass = scr->getHeap(reg.offset + SCRIPT_SUPERCLASS_OFFSET); // Get superclass...
if (superclass >= 0) {
- int superclass_script = segMan->_classtable[superclass].script;
+ int superclass_script = segMan->getClass(superclass).script;
if (superclass_script == script_nr) {
if (scr->getLockers())
@@ -562,9 +441,9 @@ void script_uninstantiate(SegManager *segMan, int script_nr) {
return;
// Free all classtable references to this script
- for (uint i = 0; i < segMan->_classtable.size(); i++)
- if (segMan->_classtable[i].reg.segment == segment)
- segMan->_classtable[i].reg = NULL_REG;
+ for (uint i = 0; i < segMan->classTableSize(); i++)
+ if (segMan->getClass(i).reg.segment == segment)
+ segMan->setClassOffset(i, NULL_REG);
if (getSciVersion() < SCI_VERSION_1_1)
script_uninstantiate_sci0(segMan, script_nr, segment);
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 4b60626b2e..159c278e8c 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -67,37 +67,6 @@ extern const char *selector_name(EngineState *s, int selector);
DebugState g_debugState;
-int propertyOffsetToId(SegManager *segMan, int prop_ofs, reg_t objp) {
- Object *obj = segMan->getObject(objp);
- byte *selectoroffset;
- int selectors;
-
- if (!obj) {
- warning("Applied propertyOffsetToId on non-object at %04x:%04x", PRINT_REG(objp));
- return -1;
- }
-
- selectors = obj->getVarCount();
-
- if (getSciVersion() < SCI_VERSION_1_1)
- selectoroffset = ((byte *)(obj->_baseObj)) + SCRIPT_SELECTOR_OFFSET + selectors * 2;
- else {
- if (!(obj->getInfoSelector().offset & SCRIPT_INFO_CLASS)) {
- obj = segMan->getObject(obj->getSuperClassSelector());
- selectoroffset = (byte *)obj->_baseVars;
- } else
- selectoroffset = (byte *)obj->_baseVars;
- }
-
- if (prop_ofs < 0 || (prop_ofs >> 1) >= selectors) {
- warning("Applied propertyOffsetToId to invalid property offset %x (property #%d not in [0..%d]) on object at %04x:%04x",
- prop_ofs, prop_ofs >> 1, selectors - 1, PRINT_REG(objp));
- return -1;
- }
-
- return READ_SCI11ENDIAN_UINT16(selectoroffset + prop_ofs);
-}
-
// Disassembles one command from the heap, returns address of next command or 0 if a ret was encountered.
reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecode) {
SegmentObj *mobj = s->_segMan->getSegment(pos.segment, SEG_TYPE_SCRIPT);
@@ -116,7 +85,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
script_entity = (Script *)mobj;
scr = script_entity->_buf;
- scr_size = script_entity->_bufSize;
+ scr_size = script_entity->getBufSize();
if (pos.offset >= scr_size) {
warning("Trying to disassemble beyond end of script");
@@ -221,51 +190,52 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
}
}
- if (pos == scriptState.xs->addr.pc) { // Extra information if debugging the current opcode
+ if (pos == s->xs->addr.pc) { // Extra information if debugging the current opcode
if ((opcode == op_pTos) || (opcode == op_sTop) || (opcode == op_pToa) || (opcode == op_aTop) ||
(opcode == op_dpToa) || (opcode == op_ipToa) || (opcode == op_dpTos) || (opcode == op_ipTos)) {
- int prop_ofs = scr[pos.offset + 1];
- int prop_id = propertyOffsetToId(s->_segMan, prop_ofs, scriptState.xs->objp);
-
- printf(" (%s)", selector_name(s, prop_id));
+ const Object *obj = s->_segMan->getObject(s->xs->objp);
+ if (!obj)
+ warning("Attempted to reference on non-object at %04x:%04x", PRINT_REG(s->xs->objp));
+ else
+ printf(" (%s)", selector_name(s, obj->propertyOffsetToId(s->_segMan, scr[pos.offset + 1])));
}
}
printf("\n");
- if (pos == scriptState.xs->addr.pc) { // Extra information if debugging the current opcode
+ if (pos == s->xs->addr.pc) { // Extra information if debugging the current opcode
if (opcode == op_callk) {
- int stackframe = (scr[pos.offset + 2] >> 1) + (scriptState.restAdjust);
- int argc = ((scriptState.xs->sp)[- stackframe - 1]).offset;
+ int stackframe = (scr[pos.offset + 2] >> 1) + (s->restAdjust);
+ int argc = ((s->xs->sp)[- stackframe - 1]).offset;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
if (!oldScriptHeader)
- argc += (scriptState.restAdjust);
+ argc += (s->restAdjust);
printf(" Kernel params: (");
for (int j = 0; j < argc; j++) {
- printf("%04x:%04x", PRINT_REG((scriptState.xs->sp)[j - stackframe]));
+ printf("%04x:%04x", PRINT_REG((s->xs->sp)[j - stackframe]));
if (j + 1 < argc)
printf(", ");
}
printf(")\n");
} else if ((opcode == op_send) || (opcode == op_self)) {
- int restmod = scriptState.restAdjust;
+ int restmod = s->restAdjust;
int stackframe = (scr[pos.offset + 1] >> 1) + restmod;
- reg_t *sb = scriptState.xs->sp;
+ reg_t *sb = s->xs->sp;
uint16 selector;
reg_t fun_ref;
while (stackframe > 0) {
int argc = sb[- stackframe + 1].offset;
const char *name = NULL;
- reg_t called_obj_addr = scriptState.xs->objp;
+ reg_t called_obj_addr = s->xs->objp;
if (opcode == op_send)
called_obj_addr = s->r_acc;
else if (opcode == op_self)
- called_obj_addr = scriptState.xs->objp;
+ called_obj_addr = s->xs->objp;
selector = sb[- stackframe].offset;
@@ -276,7 +246,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
printf(" %s::%s[", name, (selector > kernel->getSelectorNamesSize()) ? "<invalid>" : selector_name(s, selector));
- switch (lookup_selector(s->_segMan, called_obj_addr, selector, 0, &fun_ref)) {
+ switch (lookupSelector(s->_segMan, called_obj_addr, selector, 0, &fun_ref)) {
case kSelectorMethod:
printf("FUNCT");
argc += restmod;
@@ -315,10 +285,10 @@ void script_debug(EngineState *s) {
#if 0
if (sci_debug_flags & _DEBUG_FLAG_LOGGING) {
printf("%d: acc=%04x:%04x ", script_step_counter, PRINT_REG(s->r_acc));
- disassemble(s, scriptState.xs->addr.pc, 0, 1);
- if (scriptState.seeking == kDebugSeekGlobal)
- printf("Global %d (0x%x) = %04x:%04x\n", scriptState.seekSpecial,
- scriptState.seekSpecial, PRINT_REG(s->script_000->_localsBlock->_locals[scriptState.seekSpecial]));
+ disassemble(s, s->xs->addr.pc, 0, 1);
+ if (s->seeking == kDebugSeekGlobal)
+ printf("Global %d (0x%x) = %04x:%04x\n", s->seekSpecial,
+ s->seekSpecial, PRINT_REG(s->script_000->_localsBlock->_locals[s->seekSpecial]));
}
#endif
@@ -328,16 +298,16 @@ void script_debug(EngineState *s) {
#endif
if (g_debugState.seeking && !g_debugState.breakpointWasHit) { // Are we looking for something special?
- SegmentObj *mobj = s->_segMan->getSegment(scriptState.xs->addr.pc.segment, SEG_TYPE_SCRIPT);
+ SegmentObj *mobj = s->_segMan->getSegment(s->xs->addr.pc.segment, SEG_TYPE_SCRIPT);
if (mobj) {
Script *scr = (Script *)mobj;
byte *code_buf = scr->_buf;
- int code_buf_size = scr->_bufSize;
- int opcode = scriptState.xs->addr.pc.offset >= code_buf_size ? 0 : code_buf[scriptState.xs->addr.pc.offset];
+ int code_buf_size = scr->getBufSize();
+ int opcode = s->xs->addr.pc.offset >= code_buf_size ? 0 : code_buf[s->xs->addr.pc.offset];
int op = opcode >> 1;
- int paramb1 = scriptState.xs->addr.pc.offset + 1 >= code_buf_size ? 0 : code_buf[scriptState.xs->addr.pc.offset + 1];
- int paramf1 = (opcode & 1) ? paramb1 : (scriptState.xs->addr.pc.offset + 2 >= code_buf_size ? 0 : (int16)READ_SCI11ENDIAN_UINT16(code_buf + scriptState.xs->addr.pc.offset + 1));
+ int paramb1 = s->xs->addr.pc.offset + 1 >= code_buf_size ? 0 : code_buf[s->xs->addr.pc.offset + 1];
+ int paramf1 = (opcode & 1) ? paramb1 : (s->xs->addr.pc.offset + 2 >= code_buf_size ? 0 : (int16)READ_SCI11ENDIAN_UINT16(code_buf + s->xs->addr.pc.offset + 1));
switch (g_debugState.seeking) {
case kDebugSeekSpecialCallk:
@@ -381,8 +351,8 @@ void script_debug(EngineState *s) {
}
}
- printf("Step #%d\n", script_step_counter);
- disassemble(s, scriptState.xs->addr.pc, 0, 1);
+ printf("Step #%d\n", s->script_step_counter);
+ disassemble(s, s->xs->addr.pc, 0, 1);
if (g_debugState.runningStep) {
g_debugState.runningStep--;
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index b18d76e1a7..4d3e6f754e 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -54,7 +54,6 @@ SegManager::SegManager(ResourceManager *resMan) {
createClassTable();
}
-// Destroy the object, free the memorys if allocated before
SegManager::~SegManager() {
resetSegMan();
}
@@ -77,10 +76,29 @@ void SegManager::resetSegMan() {
Hunks_seg_id = 0;
// Reinitialize class table
- _classtable.clear();
+ _classTable.clear();
createClassTable();
}
+void SegManager::initSysStrings() {
+ sysStrings = (SystemStrings *)allocSegment(new SystemStrings(), &sysStringsSegment);
+
+ // Allocate static buffer for savegame and CWD directories
+ SystemString *strSaveDir = &sysStrings->_strings[SYS_STRING_SAVEDIR];
+ strSaveDir->_name = "savedir";
+ strSaveDir->_maxSize = MAX_SAVE_DIR_SIZE;
+ strSaveDir->_value = (char *)calloc(MAX_SAVE_DIR_SIZE, sizeof(char));
+ // Set the savegame dir (actually, we set it to a fake value,
+ // since we cannot let the game control where saves are stored)
+ ::strcpy(strSaveDir->_value, "");
+
+ // Allocate static buffer for the parser base
+ SystemString *strParserBase = &sysStrings->_strings[SYS_STRING_PARSER_BASE];
+ strParserBase->_name = "parser-base";
+ strParserBase->_maxSize = MAX_PARSER_BASE;
+ strParserBase->_value = (char *)calloc(MAX_PARSER_BASE, sizeof(char));
+}
+
SegmentId SegManager::findFreeSegment() const {
// FIXME: This is a very crude approach: We find a free segment id by scanning
// from the start. This can be slow if the number of segments becomes large.
@@ -156,7 +174,7 @@ int SegManager::deallocate(SegmentId seg, bool recursive) {
}
bool SegManager::isHeapObject(reg_t pos) {
- Object *obj = getObject(pos);
+ const Object *obj = getObject(pos);
if (obj == NULL || (obj && obj->isFreed()))
return false;
Script *scr = getScriptIfLoaded(pos.segment);
@@ -223,7 +241,7 @@ Object *SegManager::getObject(reg_t pos) {
warning("getObject(): Trying to get an invalid object");
} else if (mobj->getType() == SEG_TYPE_SCRIPT) {
Script *scr = (Script *)mobj;
- if (pos.offset <= scr->_bufSize && pos.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET
+ if (pos.offset <= scr->getBufSize() && pos.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET
&& RAW_IS_OBJECT(scr->_buf + pos.offset)) {
obj = scr->getObject(pos.offset);
}
@@ -234,7 +252,7 @@ Object *SegManager::getObject(reg_t pos) {
}
const char *SegManager::getObjectName(reg_t pos) {
- Object *obj = getObject(pos);
+ const Object *obj = getObject(pos);
if (!obj)
return "<no such object>";
@@ -275,7 +293,7 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) {
// It's a script or a clone table, scan all objects in it
for (; idx < max_index; ++idx) {
- Object *obj = NULL;
+ const Object *obj = NULL;
reg_t objpos;
objpos.offset = 0;
objpos.segment = i;
@@ -393,10 +411,6 @@ DataStack *SegManager::allocateStack(int size, SegmentId *segid) {
return retval;
}
-SystemStrings *SegManager::allocateSysStrings(SegmentId *segid) {
- return (SystemStrings *)allocSegment(new SystemStrings(), segid);
-}
-
void SegManager::freeHunkEntry(reg_t addr) {
if (addr.isNull()) {
warning("Attempt to free a Hunk from a null address");
@@ -485,7 +499,7 @@ void SegManager::reconstructClones() {
continue;
CloneTable::Entry &seeker = ct->_table[j];
- Object *baseObj = getObject(seeker.getSpeciesSelector());
+ const Object *baseObj = getObject(seeker.getSpeciesSelector());
seeker.cloneFromObject(baseObj);
if (!baseObj)
warning("Clone entry without a base class: %d", j);
@@ -523,6 +537,16 @@ Node *SegManager::allocateNode(reg_t *addr) {
return &(table->_table[offset]);
}
+reg_t SegManager::newNode(reg_t value, reg_t key) {
+ reg_t nodebase;
+ Node *n = allocateNode(&nodebase);
+ n->pred = n->succ = NULL_REG;
+ n->key = key;
+ n->value = value;
+
+ return nodebase;
+}
+
List *SegManager::lookupList(reg_t addr) {
if (getSegmentType(addr.segment) != SEG_TYPE_LISTS) {
warning("Attempt to use non-list %04x:%04x as list", PRINT_REG(addr));
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index e8bbdbdb3f..9312f51f9d 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -112,12 +112,6 @@ public:
SegmentId getScriptSegment(int script_nr, ScriptLoadType load);
// TODO: document this
- reg_t lookupScriptExport(int script_nr, int export_index) {
- SegmentId seg = getScriptSegment(script_nr, SCRIPT_GET_DONT_LOAD);
- return make_reg(seg, getScript(seg)->validateExportFunc(export_index));
- }
-
- // TODO: document this
reg_t getClassAddress(int classnr, ScriptLoadType lock, reg_t caller);
/**
@@ -188,15 +182,10 @@ public:
// 5. System Strings
/**
- * Allocates a system string table
- * See also sys_string_acquire();
- * @param[in] segid Segment ID of the stack
- * @returns The physical stack
+ * Initializes the system string table.
*/
- SystemStrings *allocateSysStrings(SegmentId *segid);
-
+ void initSysStrings();
- // 5. System Strings
// 6, 7. Lists and Nodes
@@ -215,6 +204,14 @@ public:
Node *allocateNode(reg_t *addr);
/**
+ * Allocate and initialize a new list node.
+ * @param[in] value The value to set the node to
+ * @param[in] key The key to set
+ * @return Pointer to the newly initialized list node
+ */
+ reg_t newNode(reg_t value, reg_t key);
+
+ /**
* Resolves a list pointer to a list.
* @param addr The address to resolve
* @return The list referenced, or NULL on error
@@ -432,12 +429,22 @@ public:
*/
reg_t findObjectByName(const Common::String &name, int index = -1);
- void scriptRelocateExportsSci11(SegmentId seg);
void scriptInitialiseObjectsSci11(SegmentId seg);
+ uint32 classTableSize() { return _classTable.size(); }
+ Class getClass(int index) { return _classTable[index]; }
+ void setClassOffset(int index, reg_t offset) { _classTable[index].reg = offset; }
+ void resizeClassTable(uint32 size) { _classTable.resize(size); }
+
+ /**
+ * Obtains the system strings segment ID
+ */
+ SegmentId getSysStringsSegment() { return sysStringsSegment; }
+
public: // TODO: make private
Common::Array<SegmentObj *> _heap;
- Common::Array<Class> _classtable; /**< Table of all classes */
+ // Only accessible from saveLoadWithSerializer()
+ Common::Array<Class> _classTable; /**< Table of all classes */
#ifdef ENABLE_SCI32
SciArray<reg_t> *allocateArray(reg_t *addr);
@@ -460,6 +467,13 @@ private:
SegmentId Nodes_seg_id; ///< ID of the (a) node segment
SegmentId Hunks_seg_id; ///< ID of the (a) hunk segment
+ /* System strings */
+ SegmentId sysStringsSegment;
+public: // TODO: make private. Only kString() needs direct access
+ SystemStrings *sysStrings;
+
+private:
+
#ifdef ENABLE_SCI32
SegmentId Arrays_seg_id;
SegmentId String_seg_id;
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index ab1a68d165..0e0a759d4b 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -27,6 +27,7 @@
#include "sci/sci.h"
#include "sci/engine/features.h"
+#include "sci/engine/script.h" // for SCI_OBJ_EXPORTS and SCI_OBJ_SYNONYMS
#include "sci/engine/segment.h"
#include "sci/engine/seg_manager.h"
#include "sci/engine/state.h"
@@ -100,8 +101,7 @@ Script::Script() : SegmentObj(SEG_TYPE_SCRIPT) {
_localsSegment = 0;
_localsBlock = NULL;
- _relocated = false;
- _markedAsDeleted = 0;
+ _markedAsDeleted = false;
}
Script::~Script() {
@@ -117,54 +117,39 @@ void Script::freeScript() {
_codeBlocks.clear();
}
-bool Script::init(int script_nr, ResourceManager *resMan) {
- setScriptSize(script_nr, resMan);
-
- _buf = (byte *)malloc(_bufSize);
-
- if (!_buf) {
- freeScript();
- warning("Not enough memory space for script size");
- _bufSize = 0;
- return false;
- }
+void Script::init(int script_nr, ResourceManager *resMan) {
+ Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
_localsOffset = 0;
_localsBlock = NULL;
_codeBlocks.clear();
- _relocated = false;
_markedAsDeleted = false;
_nr = script_nr;
-
- if (getSciVersion() >= SCI_VERSION_1_1)
- _heapStart = _buf + _scriptSize;
- else
- _heapStart = _buf;
-
- return true;
-}
-
-void Script::setScriptSize(int script_nr, ResourceManager *resMan) {
- Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
- Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
- bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
+ _buf = 0;
+ _heapStart = 0;
_scriptSize = script->size;
- _heapSize = 0; // Set later
+ _bufSize = script->size;
+ _heapSize = 0;
- if (!script || (getSciVersion() >= SCI_VERSION_1_1 && !heap)) {
- error("SegManager::setScriptSize: failed to load %s", !script ? "script" : "heap");
- }
- if (oldScriptHeader) {
- _bufSize = script->size + READ_LE_UINT16(script->data) * 2;
- //locals_size = READ_LE_UINT16(script->data) * 2;
- } else if (getSciVersion() < SCI_VERSION_1_1) {
- _bufSize = script->size;
- } else {
- _bufSize = script->size + heap->size;
+ _lockers = 1;
+
+ if (getSciVersion() == SCI_VERSION_0_EARLY) {
+ _bufSize += READ_LE_UINT16(script->data) * 2;
+ } else if (getSciVersion() >= SCI_VERSION_1_1) {
+ /**
+ * In SCI11, the heap was in a separate space from the script.
+ * We append it to the end of the script, and adjust addressing accordingly.
+ * However, since we address the heap with a 16-bit pointer, the combined
+ * size of the stack and the heap must be 64KB. So far this has worked
+ * for SCI11, SCI2 and SCI21 games. SCI3 games use a different script format,
+ * and theoretically they can exceed the 64KB boundary using relocation.
+ */
+ Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
+ _bufSize += heap->size;
_heapSize = heap->size;
// Ensure that the start of the heap resource can be word-aligned.
@@ -173,12 +158,56 @@ void Script::setScriptSize(int script_nr, ResourceManager *resMan) {
_scriptSize++;
}
- if (_bufSize > 65535) {
- error("Script and heap sizes combined exceed 64K."
- "This means a fundamental design bug was made in SCI\n"
- "regarding SCI1.1 games.\nPlease report this so it can be"
- "fixed in the next major version");
- return;
+ // As mentioned above, the script and the heap together should not exceed 64KB
+ if (_bufSize > 65535)
+ error("Script and heap sizes combined exceed 64K. This means a fundamental "
+ "design bug was made regarding SCI1.1 and newer games.\nPlease "
+ "report this error to the ScummVM team");
+ }
+}
+
+void Script::load(ResourceManager *resMan) {
+ Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0);
+ assert(script != 0);
+
+ _buf = (byte *)malloc(_bufSize);
+ assert(_buf);
+
+ assert(_bufSize >= script->size);
+ memcpy(_buf, script->data, script->size);
+
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
+ assert(heap != 0);
+
+ _heapStart = _buf + _scriptSize;
+
+ assert(_bufSize - _scriptSize <= heap->size);
+ memcpy(_heapStart, heap->data, heap->size);
+ }
+
+ _codeBlocks.clear();
+
+ _exportTable = 0;
+ _numExports = 0;
+ _synonyms = 0;
+ _numSynonyms = 0;
+
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ if (READ_LE_UINT16(_buf + 1 + 5) > 0) {
+ _exportTable = (const uint16 *)(_buf + 1 + 5 + 2);
+ _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1);
+ }
+ } else {
+ _exportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS);
+ if (_exportTable) {
+ _numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
+ _exportTable += 3; // skip header plus 2 bytes (_exportTable is a uint16 pointer)
+ }
+ _synonyms = findBlock(SCI_OBJ_SYNONYMS);
+ if (_synonyms) {
+ _numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
+ _synonyms += 4; // skip header
}
}
}
@@ -194,19 +223,26 @@ Object *Script::getObject(uint16 offset) {
return 0;
}
-Object *Script::scriptObjInit(reg_t obj_pos) {
+const Object *Script::getObject(uint16 offset) const {
+ if (_objects.contains(offset))
+ return &_objects[offset];
+ else
+ return 0;
+}
+
+Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) {
Object *obj;
- if (getSciVersion() < SCI_VERSION_1_1)
+ if (getSciVersion() < SCI_VERSION_1_1 && fullObjectInit)
obj_pos.offset += 8; // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET)
VERIFY(obj_pos.offset < _bufSize, "Attempt to initialize object beyond end of script\n");
obj = allocateObject(obj_pos.offset);
- VERIFY(obj_pos.offset + SCRIPT_FUNCTAREAPTR_OFFSET < (int)_bufSize, "Function area pointer stored beyond end of script\n");
+ VERIFY(obj_pos.offset + kOffsetFunctionArea < (int)_bufSize, "Function area pointer stored beyond end of script\n");
- obj->init(_buf, obj_pos);
+ obj->init(_buf, obj_pos, fullObjectInit);
return obj;
}
@@ -218,37 +254,34 @@ void Script::scriptObjRemove(reg_t obj_pos) {
_objects.erase(obj_pos.toUint16());
}
-int Script::relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location) {
+// This helper function is used by Script::relocateLocal and Object::relocate
+static bool relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location, size_t scriptSize) {
int rel = location - block_location;
if (rel < 0)
- return 0;
+ return false;
uint idx = rel >> 1;
if (idx >= block.size())
- return 0;
+ return false;
if (rel & 1) {
warning("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, block_location);
- return 0;
+ return false;
}
block[idx].segment = segment; // Perform relocation
if (getSciVersion() >= SCI_VERSION_1_1)
- block[idx].offset += _scriptSize;
+ block[idx].offset += scriptSize;
- return 1;
+ return true;
}
-int Script::relocateLocal(SegmentId segment, int location) {
+bool Script::relocateLocal(SegmentId segment, int location) {
if (_localsBlock)
- return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location);
+ return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location, _scriptSize);
else
- return 0; // No hands, no cookies
-}
-
-int Script::relocateObject(Object &obj, SegmentId segment, int location) {
- return relocateBlock(obj._variables, obj.getPos().offset, segment, location);
+ return false;
}
void Script::scriptAddCodeBlock(reg_t location) {
@@ -258,61 +291,35 @@ void Script::scriptAddCodeBlock(reg_t location) {
_codeBlocks.push_back(cb);
}
-void Script::scriptRelocate(reg_t block) {
- VERIFY(block.offset < (uint16)_bufSize && READ_SCI11ENDIAN_UINT16(_buf + block.offset) * 2 + block.offset < (uint16)_bufSize,
- "Relocation block outside of script\n");
-
- int count = READ_SCI11ENDIAN_UINT16(_buf + block.offset);
-
- for (int i = 0; i <= count; i++) {
- int pos = READ_SCI11ENDIAN_UINT16(_buf + block.offset + 2 + (i * 2));
- if (!pos)
- continue; // FIXME: A hack pending investigation
-
- if (!relocateLocal(block.segment, pos)) {
- bool done = false;
- uint k;
-
- ObjMap::iterator it;
- const ObjMap::iterator end = _objects.end();
- for (it = _objects.begin(); !done && it != end; ++it) {
- if (relocateObject(it->_value, block.segment, pos))
- done = true;
- }
-
- for (k = 0; !done && k < _codeBlocks.size(); k++) {
- if (pos >= _codeBlocks[k].pos.offset &&
- pos < _codeBlocks[k].pos.offset + _codeBlocks[k].size)
- done = true;
- }
+void Script::relocate(reg_t block) {
+ byte *heap = _buf;
+ uint16 heapSize = (uint16)_bufSize;
+ uint16 heapOffset = 0;
- if (!done) {
- printf("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
- printf("Relocation failed for index %04x (%d/%d)\n", pos, i + 1, count);
- if (_localsBlock)
- printf("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
- else
- printf("- No locals\n");
- for (it = _objects.begin(), k = 0; it != end; ++it, ++k)
- printf("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
- // SQ3 script 71 has broken relocation entries.
- printf("Trying to continue anyway...\n");
- }
- }
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ heap = _heapStart;
+ heapSize = (uint16)_heapSize;
+ heapOffset = _scriptSize;
}
-}
-void Script::heapRelocate(reg_t block) {
- VERIFY(block.offset < (uint16)_heapSize && READ_SCI11ENDIAN_UINT16(_heapStart + block.offset) * 2 + block.offset < (uint16)_bufSize,
+ VERIFY(block.offset < (uint16)heapSize && READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset < (uint16)heapSize,
"Relocation block outside of script\n");
- if (_relocated)
- return;
- _relocated = true;
- int count = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset);
+ int count = READ_SCI11ENDIAN_UINT16(heap + block.offset);
+ int exportIndex = 0;
for (int i = 0; i < count; i++) {
- int pos = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset + 2 + (i * 2)) + _scriptSize;
+ int pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
+ // This occurs in SCI01/SCI1 games where every usually one export
+ // value is zero. It seems that in this situation, we should skip
+ // the export and move to the next one, though the total count
+ // of valid exports remains the same
+ if (!pos) {
+ exportIndex++;
+ pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
+ if (!pos)
+ error("Script::relocate(): Consecutive zero exports found");
+ }
if (!relocateLocal(block.segment, pos)) {
bool done = false;
@@ -321,22 +328,33 @@ void Script::heapRelocate(reg_t block) {
ObjMap::iterator it;
const ObjMap::iterator end = _objects.end();
for (it = _objects.begin(); !done && it != end; ++it) {
- if (relocateObject(it->_value, block.segment, pos))
+ if (it->_value.relocate(block.segment, pos, _scriptSize))
done = true;
}
+ // Sanity check for SCI0-SCI1
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ for (k = 0; !done && k < _codeBlocks.size(); k++) {
+ if (pos >= _codeBlocks[k].pos.offset &&
+ pos < _codeBlocks[k].pos.offset + _codeBlocks[k].size)
+ done = true;
+ }
+ }
+
if (!done) {
- printf("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
- printf("Relocation failed for index %04x (%d/%d)\n", pos, i + 1, count);
+ debug("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
+ debug("Relocation failed for index %04x (%d/%d)\n", pos, exportIndex + 1, count);
if (_localsBlock)
- printf("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
+ debug("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
else
- printf("- No locals\n");
+ debug("- No locals\n");
for (it = _objects.begin(), k = 0; it != end; ++it, ++k)
- printf("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
- error("Breakpoint in %s, line %d", __FILE__, __LINE__);
+ debug("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
+ debug("Trying to continue anyway...\n");
}
}
+
+ exportIndex++;
}
}
@@ -357,16 +375,6 @@ void Script::setLockers(int lockers) {
_lockers = lockers;
}
-void Script::setExportTableOffset(int offset) {
- if (offset) {
- _exportTable = (uint16 *)(_buf + offset + 2);
- _numExports = READ_SCI11ENDIAN_UINT16((byte *)(_exportTable - 1));
- } else {
- _exportTable = NULL;
- _numExports = 0;
- }
-}
-
uint16 Script::validateExportFunc(int pubfunct) {
bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE);
@@ -377,28 +385,36 @@ uint16 Script::validateExportFunc(int pubfunct) {
if (exportsAreWide)
pubfunct *= 2;
- uint16 offset = READ_SCI11ENDIAN_UINT16((byte *)(_exportTable + pubfunct));
+ uint16 offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct);
VERIFY(offset < _bufSize, "invalid export function pointer");
return offset;
}
-void Script::setSynonymsOffset(int offset) {
- _synonyms = _buf + offset;
-}
+byte *Script::findBlock(int type) {
+ byte *buf = _buf;
+ bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
-byte *Script::getSynonyms() const {
- return _synonyms;
-}
+ if (oldScriptHeader)
+ buf += 2;
-void Script::setSynonymsNr(int n) {
- _numSynonyms = n;
-}
+ do {
+ int seekerType = READ_LE_UINT16(buf);
+
+ if (seekerType == 0)
+ break;
+ if (seekerType == type)
+ return buf;
-int Script::getSynonymsNr() const {
- return _numSynonyms;
+ int seekerSize = READ_LE_UINT16(buf + 2);
+ assert(seekerSize > 0);
+ buf += seekerSize;
+ } while (1);
+
+ return NULL;
}
+
// memory operations
void Script::mcpyInOut(int dst, const void *src, size_t n) {
@@ -511,7 +527,7 @@ SegmentRef SystemStrings::dereference(reg_t pointer) {
//-------------------- script --------------------
-reg_t Script::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t Script::findCanonicAddress(SegManager *segMan, reg_t addr) const {
addr.offset = 0;
return addr;
}
@@ -527,13 +543,13 @@ void Script::freeAtAddress(SegManager *segMan, reg_t addr) {
segMan->deallocateScript(_nr);
}
-void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
(*note)(param, make_reg(segId, 0));
}
-void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (addr.offset <= _bufSize && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(_buf + addr.offset)) {
- Object *obj = getObject(addr.offset);
+ const Object *obj = getObject(addr.offset);
if (obj) {
// Note all local variables, if we have a local variable environment
if (_localsSegment)
@@ -553,16 +569,14 @@ void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback not
//-------------------- clones --------------------
-void CloneTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
- Clone *clone;
-
+void CloneTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
// assert(addr.segment == _segId);
if (!isValidEntry(addr.offset)) {
error("Unexpected request for outgoing references from clone at %04x:%04x", PRINT_REG(addr));
}
- clone = &(_table[addr.offset]);
+ const Clone *clone = &(_table[addr.offset]);
// Emit all member variables (including references to the 'super' delegate)
for (uint i = 0; i < clone->getVarCount(); i++)
@@ -597,7 +611,7 @@ void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) {
//-------------------- locals --------------------
-reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) const {
// Reference the owning script
SegmentId owner_seg = segMan->getScriptSegment(script_id);
@@ -606,7 +620,7 @@ reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) {
return make_reg(owner_seg, 0);
}
-void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
// assert(addr.segment == _segId);
for (uint i = 0; i < _locals.size(); i++)
@@ -615,12 +629,12 @@ void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCall
//-------------------- stack --------------------
-reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) const {
addr.offset = 0;
return addr;
}
-void DataStack::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void DataStack::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
fprintf(stderr, "Emitting %d stack entries\n", _capacity);
for (int i = 0; i < _capacity; i++)
(*note)(param, _entries[i]);
@@ -633,13 +647,13 @@ void ListTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void ListTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void ListTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (!isValidEntry(addr.offset)) {
warning("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- List *list = &(_table[addr.offset]);
+ const List *list = &(_table[addr.offset]);
note(param, list->first);
note(param, list->last);
@@ -653,12 +667,12 @@ void NodeTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (!isValidEntry(addr.offset)) {
warning("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- Node *node = &(_table[addr.offset]);
+ const Node *node = &(_table[addr.offset]);
// We need all four here. Can't just stick with 'pred' OR 'succ' because node operations allow us
// to walk around from any given node
@@ -673,20 +687,43 @@ void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback
//-------------------- object ----------------------------
-Object *Object::getClass(SegManager *segMan) {
+void Object::init(byte *buf, reg_t obj_pos, bool initVariables) {
+ byte *data = buf + obj_pos.offset;
+ _baseObj = data;
+ _pos = obj_pos;
+
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ _variables.resize(READ_LE_UINT16(data + kOffsetSelectorCounter));
+ _baseVars = (const uint16 *)(_baseObj + _variables.size() * 2);
+ _baseMethod = (const uint16 *)(data + READ_LE_UINT16(data + kOffsetFunctionArea));
+ _methodCount = READ_LE_UINT16(_baseMethod - 1);
+ } else {
+ _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2));
+ _baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4));
+ _baseMethod = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 6));
+ _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod);
+ }
+
+ if (initVariables) {
+ for (uint i = 0; i < _variables.size(); i++)
+ _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2)));
+ }
+}
+
+const Object *Object::getClass(SegManager *segMan) const {
return isClass() ? this : segMan->getObject(getSuperClassSelector());
}
-int Object::locateVarSelector(SegManager *segMan, Selector slc) {
- byte *buf;
+int Object::locateVarSelector(SegManager *segMan, Selector slc) const {
+ const byte *buf;
uint varnum;
if (getSciVersion() < SCI_VERSION_1_1) {
varnum = getVarCount();
- int selector_name_offset = varnum * 2 + SCRIPT_SELECTOR_OFFSET;
+ int selector_name_offset = varnum * 2 + kOffsetSelectorSegment;
buf = _baseObj + selector_name_offset;
} else {
- Object *obj = getClass(segMan);
+ const Object *obj = getClass(segMan);
varnum = obj->getVariable(1).toUint16();
buf = (byte *)obj->_baseVars;
}
@@ -698,14 +735,72 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) {
return -1; // Failed
}
+bool Object::relocate(SegmentId segment, int location, size_t scriptSize) {
+ return relocateBlock(_variables, getPos().offset, segment, location, scriptSize);
+}
+
+int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const {
+ int selectors = getVarCount();
+
+ if (propertyOffset < 0 || (propertyOffset >> 1) >= selectors) {
+ warning("Applied propertyOffsetToId to invalid property offset %x (property #%d not in [0..%d])",
+ propertyOffset, propertyOffset >> 1, selectors - 1);
+ return -1;
+ }
+
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ const byte *selectoroffset = ((const byte *)(_baseObj)) + kOffsetSelectorSegment + selectors * 2;
+ return READ_SCI11ENDIAN_UINT16(selectoroffset + propertyOffset);
+ } else {
+ const Object *obj = this;
+ if (!isClass())
+ obj = segMan->getObject(getSuperClassSelector());
+
+ return READ_SCI11ENDIAN_UINT16((const byte *)obj->_baseVars + propertyOffset);
+ }
+}
+
+void Object::initSpecies(SegManager *segMan, reg_t addr) {
+ uint16 speciesOffset = getSpeciesSelector().offset;
+
+ if (speciesOffset == 0xffff) // -1
+ setSpeciesSelector(NULL_REG); // no species
+ else
+ setSpeciesSelector(segMan->getClassAddress(speciesOffset, SCRIPT_GET_LOCK, addr));
+}
+
+void Object::initSuperClass(SegManager *segMan, reg_t addr) {
+ uint16 superClassOffset = getSuperClassSelector().offset;
+
+ if (superClassOffset == 0xffff) // -1
+ setSuperClassSelector(NULL_REG); // no superclass
+ else
+ setSuperClassSelector(segMan->getClassAddress(superClassOffset, SCRIPT_GET_LOCK, addr));
+}
+
+bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass) {
+ const Object *baseObj = segMan->getObject(getSpeciesSelector());
+
+ if (baseObj) {
+ _variables.resize(baseObj->getVarCount());
+ // Copy base from species class, as we need its selector IDs
+ _baseObj = baseObj->_baseObj;
+ if (doInitSuperClass)
+ initSuperClass(segMan, addr);
+ return true;
+ }
+
+ return false;
+}
+
//-------------------- dynamic memory --------------------
-reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) const {
addr.offset = 0;
return addr;
}
-void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
(*note)(param, make_reg(segId, 0));
}
@@ -724,13 +819,13 @@ void ArrayTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (!isValidEntry(addr.offset)) {
warning("Invalid array referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- SciArray<reg_t> *array = &(_table[addr.offset]);
+ const SciArray<reg_t> *array = &(_table[addr.offset]);
for (uint32 i = 0; i < array->getSize(); i++) {
reg_t value = array->getValue(i);
@@ -739,7 +834,7 @@ void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback
}
}
-Common::String SciString::toString() {
+Common::String SciString::toString() const {
if (_type != 3)
error("SciString::toString(): Array is not a string");
@@ -750,7 +845,7 @@ Common::String SciString::toString() {
return string;
}
-void SciString::fromString(Common::String string) {
+void SciString::fromString(const Common::String &string) {
if (_type != 3)
error("SciString::fromString(): Array is not a string");
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 1089ada475..f1b6dccaa2 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -112,7 +112,7 @@ public:
*
* @param sub_addr base address whose canonic address is to be found
*/
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) { return sub_addr; }
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const { return sub_addr; }
/**
* Deallocates all memory associated with the specified address.
@@ -125,7 +125,7 @@ public:
* @param note Invoked for each address on which free_at_address() makes sense
* @param param parameter passed to 'note'
*/
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {}
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {}
/**
* Iterates over all references reachable from the specified object.
@@ -134,7 +134,7 @@ public:
* @param note Invoked for each outgoing reference within the object
* Note: This function may also choose to report numbers (segment 0) as adresses
*/
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) {}
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const {}
};
@@ -194,8 +194,8 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -205,6 +205,22 @@ enum {
OBJECT_FLAG_FREED = (1 << 0)
};
+enum infoSelectorFlags {
+ kInfoFlagClone = 0x0001,
+ kInfoFlagClass = 0x8000
+};
+
+enum ObjectOffsets {
+ kOffsetLocalVariables = -6,
+ kOffsetFunctionArea = -4,
+ kOffsetSelectorCounter = -2,
+ kOffsetSelectorSegment = 0,
+ kOffsetInfoSelectorSci0 = 4,
+ kOffsetNamePointerSci0 = 6,
+ kOffsetInfoSelectorSci11 = 14,
+ kOffsetNamePointerSci11 = 16
+};
+
class Object {
public:
Object() {
@@ -214,31 +230,34 @@ public:
~Object() { }
- reg_t getSpeciesSelector() { return _variables[_offset]; }
+ reg_t getSpeciesSelector() const { return _variables[_offset]; }
void setSpeciesSelector(reg_t value) { _variables[_offset] = value; }
- reg_t getSuperClassSelector() { return _variables[_offset + 1]; }
+ reg_t getSuperClassSelector() const { return _variables[_offset + 1]; }
void setSuperClassSelector(reg_t value) { _variables[_offset + 1] = value; }
- reg_t getInfoSelector() { return _variables[_offset + 2]; }
- void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; }
+ reg_t getInfoSelector() const { return _variables[_offset + 2]; }
+ void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; }
- reg_t getNameSelector() { return _variables[_offset + 3]; }
- void setNameSelector(reg_t value) { _variables[_offset + 3] = value; }
+ reg_t getNameSelector() const { return _variables[_offset + 3]; }
+ void setNameSelector(reg_t value) { _variables[_offset + 3] = value; }
- reg_t getClassScriptSelector() { return _variables[4]; }
+ reg_t getPropDictSelector() const { return _variables[2]; }
+ void setPropDictSelector(reg_t value) { _variables[2] = value; }
+
+ reg_t getClassScriptSelector() const { return _variables[4]; }
void setClassScriptSelector(reg_t value) { _variables[4] = value; }
- Selector getVarSelector(uint16 i) { return READ_SCI11ENDIAN_UINT16(_baseVars + i); }
+ Selector getVarSelector(uint16 i) const { return READ_SCI11ENDIAN_UINT16(_baseVars + i); }
- reg_t getFunction(uint16 i) {
+ reg_t getFunction(uint16 i) const {
uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? _methodCount + 1 + i : i * 2 + 2;
- return make_reg(_pos.segment, READ_SCI11ENDIAN_UINT16((byte *) (_baseMethod + offset)));
+ return make_reg(_pos.segment, READ_SCI11ENDIAN_UINT16(_baseMethod + offset));
}
- Selector getFuncSelector(uint16 i) {
+ Selector getFuncSelector(uint16 i) const {
uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? i : i * 2 + 1;
- return READ_SCI11ENDIAN_UINT16((byte *) (_baseMethod + offset));
+ return READ_SCI11ENDIAN_UINT16(_baseMethod + offset);
}
/**
@@ -247,7 +266,7 @@ public:
* superclasses, i.e. failure may be returned even if one of the
* superclasses defines the funcselector
*/
- int funcSelectorPosition(Selector sel) {
+ int funcSelectorPosition(Selector sel) const {
for (uint i = 0; i < _methodCount; i++)
if (getFuncSelector(i) == sel)
return i;
@@ -256,61 +275,56 @@ public:
}
/**
- * Determines if the object explicitly defines slc as a varselector
- * Returns -1 if not found
+ * Determines if the object explicitly defines slc as a varselector.
+ * Returns -1 if not found.
*/
- int locateVarSelector(SegManager *segMan, Selector slc);
-
- bool isClass() { return (getInfoSelector().offset & SCRIPT_INFO_CLASS); }
- Object *getClass(SegManager *segMan);
+ int locateVarSelector(SegManager *segMan, Selector slc) const;
- void markAsFreed() { _flags |= OBJECT_FLAG_FREED; }
- bool isFreed() { return _flags & OBJECT_FLAG_FREED; }
+ bool isClass() const { return (getInfoSelector().offset & kInfoFlagClass); }
+ const Object *getClass(SegManager *segMan) const;
- void setVarCount(uint size) { _variables.resize(size); }
- uint getVarCount() { return _variables.size(); }
+ void markAsClone() { setInfoSelector(make_reg(0, kInfoFlagClone)); }
+ bool isClone() const { return (getInfoSelector().offset & kInfoFlagClone); }
- void init(byte *buf, reg_t obj_pos) {
- byte *data = (byte *)(buf + obj_pos.offset);
- _baseObj = data;
- _pos = obj_pos;
+ void markAsFreed() { _flags |= OBJECT_FLAG_FREED; }
+ bool isFreed() const { return _flags & OBJECT_FLAG_FREED; }
- if (getSciVersion() < SCI_VERSION_1_1) {
- _variables.resize(READ_LE_UINT16(data + SCRIPT_SELECTORCTR_OFFSET));
- _baseVars = (uint16 *)(_baseObj + _variables.size() * 2);
- _baseMethod = (uint16 *)(data + READ_LE_UINT16(data + SCRIPT_FUNCTAREAPTR_OFFSET));
- _methodCount = READ_LE_UINT16(_baseMethod - 1);
- } else {
- _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2));
- _baseVars = (uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4));
- _baseMethod = (uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 6));
- _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod);
- }
+ uint getVarCount() const { return _variables.size(); }
- for (uint i = 0; i < _variables.size(); i++)
- _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2)));
- }
+ void init(byte *buf, reg_t obj_pos, bool initVariables = true);
- reg_t getVariable(uint var) { return _variables[var]; }
+ reg_t getVariable(uint var) const { return _variables[var]; }
+ reg_t &getVariableRef(uint var) { return _variables[var]; }
- uint16 getMethodCount() { return _methodCount; }
- reg_t getPos() { return _pos; }
+ uint16 getMethodCount() const { return _methodCount; }
+ reg_t getPos() const { return _pos; }
void saveLoadWithSerializer(Common::Serializer &ser);
- void cloneFromObject(Object *obj) {
+ void cloneFromObject(const Object *obj) {
_baseObj = obj ? obj->_baseObj : NULL;
_baseMethod = obj ? obj->_baseMethod : NULL;
_baseVars = obj ? obj->_baseVars : NULL;
}
+ bool relocate(SegmentId segment, int location, size_t scriptSize);
+
+ int propertyOffsetToId(SegManager *segMan, int propertyOffset) const;
+
+ void initSpecies(SegManager *segMan, reg_t addr);
+ void initSuperClass(SegManager *segMan, reg_t addr);
+ bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true);
+
// TODO: make private
- Common::Array<reg_t> _variables;
- byte *_baseObj; /**< base + object offset within base */
- uint16 *_baseVars; /**< Pointer to the varselector area for this object */
- uint16 *_baseMethod; /**< Pointer to the method selector area for this object */
+ // Only SegManager::reconstructScripts() is left needing direct access to these
+public:
+ const byte *_baseObj; /**< base + object offset within base */
private:
+ const uint16 *_baseVars; /**< Pointer to the varselector area for this object */
+ const uint16 *_baseMethod; /**< Pointer to the method selector area for this object */
+
+ Common::Array<reg_t> _variables;
uint16 _methodCount;
int _flags;
uint16 _offset;
@@ -328,21 +342,28 @@ class Script : public SegmentObj {
public:
int _nr; /**< Script number */
byte *_buf; /**< Static data buffer, or NULL if not used */
- size_t _bufSize;
- size_t _scriptSize;
- size_t _heapSize;
-
byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */
- uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */
- int _numExports; /**< Number of entries in the exports table */
-
- byte *_synonyms; /**< Synonyms block or 0 if not present*/
- int _numSynonyms; /**< Number of entries in the synonyms block */
+ uint32 getScriptSize() { return _scriptSize; }
+ uint32 getHeapSize() { return _heapSize; }
+ uint32 getBufSize() { return _bufSize; }
protected:
int _lockers; /**< Number of classes and objects that require this script */
+private:
+ size_t _scriptSize;
+ size_t _heapSize;
+ size_t _bufSize;
+
+ const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */
+ uint16 _numExports; /**< Number of entries in the exports table */
+
+ const byte *_synonyms; /**< Synonyms block or 0 if not present*/
+ uint16 _numSynonyms; /**< Number of entries in the synonyms block */
+
+ Common::Array<CodeBlock> _codeBlocks;
+
public:
/**
* Table for objects, contains property variables.
@@ -354,8 +375,6 @@ public:
SegmentId _localsSegment; /**< The local variable segment */
LocalVariables *_localsBlock;
- Common::Array<CodeBlock> _codeBlocks;
- bool _relocated;
bool _markedAsDeleted;
public:
@@ -363,19 +382,21 @@ public:
~Script();
void freeScript();
- bool init(int script_nr, ResourceManager *resMan);
+ void init(int script_nr, ResourceManager *resMan);
+ void load(ResourceManager *resMan);
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const;
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
Object *allocateObject(uint16 offset);
Object *getObject(uint16 offset);
+ const Object *getObject(uint16 offset) const;
/**
* Informs the segment manager that a code block must be relocated
@@ -392,7 +413,7 @@ public:
* @returns A newly created Object describing the object,
* stored within the relevant script
*/
- Object *scriptObjInit(reg_t obj_pos);
+ Object *scriptObjInit(reg_t obj_pos, bool fullObjectInit = true);
/**
* Removes a script object
@@ -407,14 +428,10 @@ public:
* @param obj_pos Location (segment, offset) of the block
* @return Location of the relocation block
*/
- void scriptRelocate(reg_t block);
-
- void heapRelocate(reg_t block);
+ void relocate(reg_t block);
private:
- int relocateLocal(SegmentId segment, int location);
- int relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location);
- int relocateObject(Object &obj, SegmentId segment, int location);
+ bool relocateLocal(SegmentId segment, int location);
public:
// script lock operations
@@ -435,22 +452,28 @@ public:
void setLockers(int lockers);
/**
+ * Retrieves a pointer to the exports of this script
+ * @return pointer to the exports.
+ */
+ const uint16 *getExportTable() const { return _exportTable; }
+
+ /**
+ * Retrieves the number of exports of script.
+ * @return the number of exports of this script
+ */
+ uint16 getExportsNr() const { return _numExports; }
+
+ /**
* Retrieves a pointer to the synonyms associated with this script
* @return pointer to the synonyms, in non-parsed format.
*/
- byte *getSynonyms() const;
+ const byte *getSynonyms() const { return _synonyms; }
/**
* Retrieves the number of synonyms associated with this script.
* @return the number of synonyms associated with this script
*/
- int getSynonymsNr() const;
-
- /**
- * Sets the script-relative offset of the exports table.
- * @param offset script-relative exports table offset
- */
- void setExportTableOffset(int offset);
+ uint16 getSynonymsNr() const { return _numSynonyms; }
/**
* Validate whether the specified public function is exported by
@@ -462,19 +485,6 @@ public:
uint16 validateExportFunc(int pubfunct);
/**
- * Sets the script-relative offset of the synonyms associated with this script.
- * @param offset script-relative offset of the synonyms block
- */
- void setSynonymsOffset(int offset);
-
- /**
- * Sets the number of synonyms associated with this script,
- * @param nr number of synonyms, as to be stored within the script
- */
- void setSynonymsNr(int nr);
-
-
- /**
* Marks the script as deleted.
* This will not actually delete the script. If references remain present on the
* heap or the stack, the script will stay in memory in a quasi-deleted state until
@@ -508,8 +518,10 @@ public:
*/
int16 getHeap(uint16 offset) const;
-private:
- void setScriptSize(int script_nr, ResourceManager *resMan);
+ /**
+ * Finds the pointer where a block of a specific type starts from
+ */
+ byte *findBlock(int type);
};
/** Data stack */
@@ -529,8 +541,8 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -618,7 +630,7 @@ public:
entries_used--;
}
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
for (uint i = 0; i < _table.size(); i++)
if (isValidEntry(i))
(*note)(param, make_reg(segId, i));
@@ -631,7 +643,7 @@ struct CloneTable : public Table<Clone> {
CloneTable() : Table<Clone>(SEG_TYPE_CLONES) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -642,7 +654,7 @@ struct NodeTable : public Table<Node> {
NodeTable() : Table<Node>(SEG_TYPE_NODES) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -653,7 +665,7 @@ struct ListTable : public Table<List> {
ListTable() : Table<List>(SEG_TYPE_LISTS) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -688,8 +700,8 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -782,7 +794,7 @@ public:
_size = _actualSize = size;
}
- T getValue(uint16 index) {
+ T getValue(uint16 index) const {
if (index >= _size)
error("SciArray::getValue(): %d is out of bounds (%d)", index, _size);
@@ -796,8 +808,8 @@ public:
_data[index] = value;
}
- byte getType() { return _type; }
- uint32 getSize() { return _size; }
+ byte getType() const { return _type; }
+ uint32 getSize() const { return _size; }
T *getRawData() { return _data; }
protected:
@@ -814,15 +826,15 @@ public:
// We overload destroy to ensure the string type is 3 after destroying
void destroy() { SciArray<char>::destroy(); _type = 3; }
- Common::String toString();
- void fromString(Common::String string);
+ Common::String toString() const;
+ void fromString(const Common::String &string);
};
struct ArrayTable : public Table<SciArray<reg_t> > {
ArrayTable() : Table<SciArray<reg_t> >(SEG_TYPE_ARRAY) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
void saveLoadWithSerializer(Common::Serializer &ser);
SegmentRef dereference(reg_t pointer);
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index e226c4b574..04a1b8fbba 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -153,11 +153,11 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(subtitleLang);
FIND_SELECTOR(parseLang);
FIND_SELECTOR(overlay);
- FIND_SELECTOR(setCursor);
FIND_SELECTOR(topString);
FIND_SELECTOR(scaleSignal);
FIND_SELECTOR(scaleX);
FIND_SELECTOR(scaleY);
+ FIND_SELECTOR(iconIndex);
#ifdef ENABLE_SCI32
FIND_SELECTOR(data);
@@ -175,32 +175,32 @@ void Kernel::mapSelectors() {
#endif
}
-reg_t read_selector(SegManager *segMan, reg_t object, Selector selector_id) {
+reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId) {
ObjVarRef address;
- if (lookup_selector(segMan, object, selector_id, &address, NULL) != kSelectorVariable)
+ if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
return NULL_REG;
else
return *address.getPointer(segMan);
}
-void write_selector(SegManager *segMan, reg_t object, Selector selector_id, reg_t value) {
+void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t value) {
ObjVarRef address;
- if ((selector_id < 0) || (selector_id > (int)g_sci->getKernel()->getSelectorNamesSize())) {
+ if ((selectorId < 0) || (selectorId > (int)g_sci->getKernel()->getSelectorNamesSize())) {
warning("Attempt to write to invalid selector %d of"
- " object at %04x:%04x.", selector_id, PRINT_REG(object));
+ " object at %04x:%04x.", selectorId, PRINT_REG(object));
return;
}
- if (lookup_selector(segMan, object, selector_id, &address, NULL) != kSelectorVariable)
+ if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
warning("Selector '%s' of object at %04x:%04x could not be"
- " written to", g_sci->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object));
+ " written to", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
else
*address.getPointer(segMan) = value;
}
-int invoke_selector_argv(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
+int invokeSelectorArgv(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
int k_argc, StackPtr k_argp, int argc, const reg_t *argv) {
int i;
int framesize = 2 + 1 * argc;
@@ -208,21 +208,21 @@ int invoke_selector_argv(EngineState *s, reg_t object, int selector_id, Selector
int slc_type;
StackPtr stackframe = k_argp + k_argc;
- stackframe[0] = make_reg(0, selector_id); // The selector we want to call
+ stackframe[0] = make_reg(0, selectorId); // The selector we want to call
stackframe[1] = make_reg(0, argc); // Argument count
- slc_type = lookup_selector(s->_segMan, object, selector_id, NULL, &address);
+ slc_type = lookupSelector(s->_segMan, object, selectorId, NULL, &address);
if (slc_type == kSelectorNone) {
warning("Selector '%s' of object at %04x:%04x could not be invoked",
- g_sci->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object));
+ g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
if (noinvalid == kStopOnInvalidSelector)
error("[Kernel] Not recoverable: VM was halted");
return 1;
}
if (slc_type == kSelectorVariable) {
warning("Attempting to invoke variable selector %s of object %04x:%04x",
- g_sci->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object));
+ g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
return 0;
}
@@ -242,7 +242,7 @@ int invoke_selector_argv(EngineState *s, reg_t object, int selector_id, Selector
return 0;
}
-int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
+int invokeSelector(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
int k_argc, StackPtr k_argp, int argc, ...) {
va_list argp;
reg_t *args = new reg_t[argc];
@@ -252,28 +252,28 @@ int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvoc
args[i] = va_arg(argp, reg_t);
va_end(argp);
- int retval = invoke_selector_argv(s, object, selector_id, noinvalid, k_argc, k_argp, argc, args);
+ int retval = invokeSelectorArgv(s, object, selectorId, noinvalid, k_argc, k_argp, argc, args);
delete[] args;
return retval;
}
-SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector selector_id, ObjVarRef *varp, reg_t *fptr) {
- Object *obj = segMan->getObject(obj_location);
+SelectorType lookupSelector(SegManager *segMan, reg_t obj_location, Selector selectorId, ObjVarRef *varp, reg_t *fptr) {
+ const Object *obj = segMan->getObject(obj_location);
int index;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
// Early SCI versions used the LSB in the selector ID as a read/write
// toggle, meaning that we must remove it for selector lookup.
if (oldScriptHeader)
- selector_id &= ~1;
+ selectorId &= ~1;
if (!obj) {
- error("lookup_selector(): Attempt to send to non-object or invalid script. Address was %04x:%04x",
+ error("lookupSelector(): Attempt to send to non-object or invalid script. Address was %04x:%04x",
PRINT_REG(obj_location));
}
- index = obj->locateVarSelector(segMan, selector_id);
+ index = obj->locateVarSelector(segMan, selectorId);
if (index >= 0) {
// Found it as a variable
@@ -285,7 +285,7 @@ SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector se
} else {
// Check if it's a method, with recursive lookup in superclasses
while (obj) {
- index = obj->funcSelectorPosition(selector_id);
+ index = obj->funcSelectorPosition(selectorId);
if (index >= 0) {
if (fptr)
*fptr = obj->getFunction(index);
@@ -300,7 +300,7 @@ SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector se
}
-// return _lookup_selector_function(segMan, obj, selector_id, fptr);
+// return _lookupSelector_function(segMan, obj, selectorId, fptr);
}
} // End of namespace Sci
diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h
index 70eeb34d93..f50b9ab1b3 100644
--- a/engines/sci/engine/selector.h
+++ b/engines/sci/engine/selector.h
@@ -34,20 +34,15 @@
namespace Sci {
-
-/******************** Selector functionality ********************/
-
enum SelectorInvocation {
kStopOnInvalidSelector = 0,
kContinueOnInvalidSelector = 1
};
-
/**
* Map a selector name to a selector id. Shortcut for accessing the selector cache.
*/
#define SELECTOR(_slc_) (g_sci->getKernel()->_selectorCache._slc_)
-//#define SELECTOR(_slc_) _slc_
/**
* Retrieves a selector from an object.
@@ -58,8 +53,8 @@ enum SelectorInvocation {
* This macro halts on error. 'selector' must be a selector name registered in vm.h's
* SelectorCache and mapped in script.cpp.
*/
-#define GET_SEL32(segMan, _obj_, _slc_) read_selector(segMan, _obj_, _slc_)
-#define GET_SEL32V(segMan, _obj_, _slc_) (GET_SEL32(segMan, _obj_, _slc_).offset)
+reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId);
+#define readSelectorValue(segMan, _obj_, _slc_) (readSelector(segMan, _obj_, _slc_).offset)
/**
* Writes a selector value to an object.
@@ -70,27 +65,25 @@ enum SelectorInvocation {
* This macro halts on error. 'selector' must be a selector name registered in vm.h's
* SelectorCache and mapped in script.cpp.
*/
-#define PUT_SEL32(segMan, _obj_, _slc_, _val_) write_selector(segMan, _obj_, _slc_, _val_)
-#define PUT_SEL32V(segMan, _obj_, _slc_, _val_) PUT_SEL32(segMan, _obj_, _slc_, make_reg(0, _val_))
+void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t value);
+#define writeSelectorValue(segMan, _obj_, _slc_, _val_) writeSelector(segMan, _obj_, _slc_, make_reg(0, _val_))
+/**
+ * Invokes a selector from an object.
+ */
+int invokeSelector(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
+ int k_argc, StackPtr k_argp, int argc, ...);
+int invokeSelectorArgv(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
+ int k_argc, StackPtr k_argp, int argc, const reg_t *argv);
/**
- * Kludge for use with invoke_selector(). Used for compatibility with compilers
+ * Kludge for use with invokeSelector(). Used for compatibility with compilers
* that cannot handle vararg macros.
*/
#define INV_SEL(s, _object_, _selector_, _noinvalid_) \
s, _object_, g_sci->getKernel()->_selectorCache._selector_, _noinvalid_, argc, argv
-reg_t read_selector(SegManager *segMan, reg_t object, Selector selector_id);
-void write_selector(SegManager *segMan, reg_t object, Selector selector_id, reg_t value);
-int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
- int k_argc, StackPtr k_argp, int argc, ...);
-int invoke_selector_argv(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
- int k_argc, StackPtr k_argp, int argc, const reg_t *argv);
-
-
-
} // End of namespace Sci
#endif // SCI_ENGINE_KERNEL_H
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index bd78639c77..b4a04f8826 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -69,51 +69,56 @@ static const uint16 s_halfWidthSJISMap[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
-EngineState::EngineState(Vocabulary *voc, SegManager *segMan)
-: _voc(voc), _segMan(segMan), _dirseeker() {
+EngineState::EngineState(SegManager *segMan)
+: _segMan(segMan), _dirseeker() {
+ reset(false);
+}
+
+EngineState::~EngineState() {
+ delete _msgState;
+}
+
+void EngineState::reset(bool isRestoring) {
#ifdef USE_OLD_MUSIC_FUNCTIONS
sfx_init_flags = 0;
#endif
- restarting_flags = 0;
-
- last_wait_time = 0;
+ if (!isRestoring) {
+ script_000 = 0;
+ _gameObj = NULL_REG;
- _fileHandles.resize(5);
+ _memorySegmentSize = 0;
+ _soundCmd = 0;
- execution_stack_base = 0;
- _executionStackPosChanged = false;
+ restarting_flags = 0;
- r_acc = NULL_REG;
- restAdjust = 0;
- r_prev = NULL_REG;
+ execution_stack_base = 0;
+ _executionStackPosChanged = false;
- stack_base = 0;
- stack_top = 0;
+ _fileHandles.resize(5);
- script_000 = 0;
+ r_acc = NULL_REG;
+ restAdjust = 0;
+ r_prev = NULL_REG;
- sys_strings_segment = 0;
- sys_strings = 0;
+ stack_base = 0;
+ stack_top = 0;
+ }
- _gameObj = NULL_REG;
+ last_wait_time = 0;
gc_countdown = 0;
- successor = 0;
-
_throttleCounter = 0;
_throttleLastTime = 0;
_throttleTrigger = false;
- _memorySegmentSize = 0;
-
- _soundCmd = 0;
-}
+ script_abort_flag = 0;
+ script_step_counter = 0;
+ script_gc_interval = GC_INTERVAL;
-EngineState::~EngineState() {
- delete _msgState;
+ restoring = false;
}
void EngineState::wait(int16 ticks) {
@@ -135,6 +140,15 @@ void EngineState::setRoomNumber(uint16 roomNumber) {
script_000->_localsBlock->_locals[13] = make_reg(0, roomNumber);
}
+void EngineState::shrinkStackToBase() {
+ uint size = execution_stack_base + 1;
+ assert(_executionStack.size() >= size);
+ Common::List<ExecStack>::iterator iter = _executionStack.begin();
+ for (uint i = 0; i < size; ++i)
+ ++iter;
+ _executionStack.erase(iter, _executionStack.end());
+}
+
static kLanguage charToLanguage(const char c) {
switch (c) {
case 'F':
@@ -218,7 +232,7 @@ kLanguage SciEngine::getSciLanguage() {
lang = K_LANG_ENGLISH;
if (_kernel->_selectorCache.printLang != -1) {
- lang = (kLanguage)GET_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang));
+ lang = (kLanguage)readSelectorValue(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang));
if ((getSciVersion() >= SCI_VERSION_1_1) || (lang == K_LANG_NONE)) {
// If language is set to none, we use the language from the game detector.
@@ -253,7 +267,7 @@ kLanguage SciEngine::getSciLanguage() {
}
// Store language in printLang selector
- PUT_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang), lang);
+ writeSelectorValue(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang), lang);
}
}
@@ -265,7 +279,7 @@ Common::String SciEngine::strSplit(const char *str, const char *sep) {
kLanguage subLang = K_LANG_NONE;
if (_kernel->_selectorCache.subtitleLang != -1) {
- subLang = (kLanguage)GET_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(subtitleLang));
+ subLang = (kLanguage)readSelectorValue(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(subtitleLang));
}
kLanguage secondLang;
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index c4b995806f..68e6a5516a 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -76,8 +76,7 @@ enum {
enum {
SCI_GAME_IS_NOT_RESTARTING = 0,
SCI_GAME_WAS_RESTARTED = 1,
- SCI_GAME_IS_RESTARTING_NOW = 2,
- SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE = 4
+ SCI_GAME_IS_RESTARTING_NOW = 2
};
class FileHandle {
@@ -96,16 +95,13 @@ public:
struct EngineState : public Common::Serializable {
public:
- EngineState(Vocabulary *voc, SegManager *segMan);
+ EngineState(SegManager *segMan);
virtual ~EngineState();
virtual void saveLoadWithSerializer(Common::Serializer &ser);
public:
SegManager *_segMan; /**< The segment manager */
- Vocabulary *_voc;
-
- Common::String _gameId; /**< Designation of the primary object (which inherits from Game) */
/* Non-VM information */
@@ -152,14 +148,34 @@ public:
StackPtr stack_base; /**< Pointer to the least stack element */
StackPtr stack_top; /**< First invalid stack element */
+ // Script state
+ ExecStack *xs;
+ reg_t *variables[4]; ///< global, local, temp, param, as immediate pointers
+ reg_t *variables_base[4]; ///< Used for referencing VM ops
+ SegmentId variables_seg[4]; ///< Same as above, contains segment IDs
+ int variables_max[4]; ///< Max. values for all variables
+
Script *script_000; /**< script 000, e.g. for globals */
+ int loadFromLauncher;
+
+ /**
+ * Set this to 1 to abort script execution immediately. Aborting will
+ * leave the debug exec stack intact.
+ * Set it to 2 to force a replay afterwards.
+ */
+ int script_abort_flag; // Set to 1 to abort execution. Set to 2 to force a replay afterwards
+ int script_step_counter; // Counts the number of steps executed
+ int script_gc_interval; // Number of steps in between gcs
+
uint16 currentRoomNumber() const;
void setRoomNumber(uint16 roomNumber);
- /* System strings */
- SegmentId sys_strings_segment;
- SystemStrings *sys_strings;
+ /**
+ * Shrink execution stack to size.
+ * Contains an assert it is not already smaller.
+ */
+ void shrinkStackToBase();
reg_t _gameObj; /**< Pointer to the game object */
@@ -176,7 +192,12 @@ public:
uint _memorySegmentSize;
byte _memorySegment[kMemorySegmentMax];
- EngineState *successor; /**< Successor of this state: Used for restoring */
+ /**
+ * Resets the engine state.
+ */
+ void reset(bool isRestoring);
+
+ bool restoring; /**< A flag to indicate if a game is being restored */
};
} // End of namespace Sci
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index e2ee2e1971..b04cc473b5 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -46,13 +46,6 @@ const reg_t SIGNAL_REG = {0, SIGNAL_OFFSET};
//#define VM_DEBUG_SEND
-ScriptState scriptState; // FIXME: Avoid non-const global vars
-int g_loadFromLauncher; // FIXME: Avoid non-const global vars
-
-int script_abort_flag = 0; // Set to 1 to abort execution. Set to 2 to force a replay afterwards // FIXME: Avoid non-const global vars
-int script_step_counter = 0; // Counts the number of steps executed // FIXME: Avoid non-const global vars
-int script_gc_interval = GC_INTERVAL; // Number of steps in between gcs // FIXME: Avoid non-const global vars
-
#define SCI_XS_CALLEE_LOCALS ((SegmentId)-1)
/**
@@ -120,7 +113,7 @@ static reg_t &validate_property(Object *obj, int index) {
return dummyReg;
}
- return obj->_variables[index];
+ return obj->getVariableRef(index);
}
static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) {
@@ -212,7 +205,7 @@ static void validate_write_var(reg_t *r, reg_t *stack_base, int type, int max, i
if (!stopGroopPos.isNull()) { // does the game have a stopGroop object?
// Find the "client" member variable of the stopGroop object, and update it
ObjVarRef varp;
- if (lookup_selector(segMan, stopGroopPos, kernel->_selectorCache.client, &varp, NULL) == kSelectorVariable) {
+ if (lookupSelector(segMan, stopGroopPos, kernel->_selectorCache.client, &varp, NULL) == kSelectorVariable) {
reg_t *clientVar = varp.getPointer(segMan);
*clientVar = value;
}
@@ -236,8 +229,8 @@ static void validate_write_var(reg_t *r, reg_t *stack_base, int type, int max, i
#endif
-#define READ_VAR(type, index, def) validate_read_var(scriptState.variables[type], s->stack_base, type, scriptState.variables_max[type], index, __LINE__, def)
-#define WRITE_VAR(type, index, value) validate_write_var(scriptState.variables[type], s->stack_base, type, scriptState.variables_max[type], index, __LINE__, value, s->_segMan, g_sci->getKernel())
+#define READ_VAR(type, index, def) validate_read_var(s->variables[type], s->stack_base, type, s->variables_max[type], index, __LINE__, def)
+#define WRITE_VAR(type, index, value) validate_write_var(s->variables[type], s->stack_base, type, s->variables_max[type], index, __LINE__, value, s->_segMan, g_sci->getKernel())
#define WRITE_VAR16(type, index, value) WRITE_VAR(type, index, make_reg(0, value));
#define ACC_ARITHMETIC_L(op) make_reg(0, (op validate_arithmetic(s->r_acc)))
@@ -251,8 +244,8 @@ static void validate_write_var(reg_t *r, reg_t *stack_base, int type, int max, i
#define PUSH(v) PUSH32(make_reg(0, v))
#define POP() (validate_arithmetic(POP32()))
// 32 bit:
-#define PUSH32(a) (*(validate_stack_addr(s, (scriptState.xs->sp)++)) = (a))
-#define POP32() (*(validate_stack_addr(s, --(scriptState.xs->sp))))
+#define PUSH32(a) (*(validate_stack_addr(s, (s->xs->sp)++)) = (a))
+#define POP32() (*(validate_stack_addr(s, --(s->xs->sp))))
ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackPtr sp, reg_t calling_obj, uint16 argc, StackPtr argp) {
int seg = s->_segMan->getScriptSegment(script);
@@ -341,7 +334,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
int selector;
int argc;
int origin = s->_executionStack.size()-1; // Origin: Used for debugging
- int print_send_action = 0;
+ bool printSendActions = false;
// We return a pointer to the new active ExecStack
// The selector calls we catch are stored below:
@@ -370,7 +363,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
if (bp->type == BREAK_SELECTOR && !strncmp(bp->name.c_str(), method_name, cmplen)) {
Console *con = g_sci->getSciDebugger();
con->DebugPrintf("Break on %s (in [%04x:%04x])\n", method_name, PRINT_REG(send_obj));
- print_send_action = 1;
+ printSendActions = true;
g_debugState.debugging = true;
g_debugState.breakpointWasHit = true;
break;
@@ -383,7 +376,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
#endif // VM_DEBUG_SEND
ObjVarRef varp;
- switch (lookup_selector(s->_segMan, send_obj, selector, &varp, &funcp)) {
+ switch (lookupSelector(s->_segMan, send_obj, selector, &varp, &funcp)) {
case kSelectorNone:
error("Send to invalid selector 0x%x of object at %04x:%04x", 0xffff & selector, PRINT_REG(send_obj));
break;
@@ -398,22 +391,34 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
#endif // VM_DEBUG_SEND
// argc == 0: read selector
- // argc == 1: write selector
- // argc > 1: write selector?
- if (print_send_action && argc == 0) { // read selector
- printf("[read selector]\n");
- print_send_action = 0;
+ // argc != 0: write selector
+ if (printSendActions && !argc) { // read selector
+ debug("[read selector]\n");
+ printSendActions = false;
}
- if (print_send_action && argc > 0) {
+ if (printSendActions && argc) {
reg_t oldReg = *varp.getPointer(s->_segMan);
reg_t newReg = argp[1];
- printf("[write to selector: change %04x:%04x to %04x:%04x]\n", PRINT_REG(oldReg), PRINT_REG(newReg));
- print_send_action = 0;
+ debug("[write to selector: change %04x:%04x to %04x:%04x]\n", PRINT_REG(oldReg), PRINT_REG(newReg));
+ printSendActions = false;
}
- if (argc > 1)
- warning("send_selector(): more than 1 parameter (%d) while modifying a variable selector", argc);
+ if (argc > 1) {
+ // argc can indeed be bigger than 1 in some cases, and it seems correct
+ // (i.e. we should skip that many bytes later on)... question is, why
+ // does this occur? Could such calls be used to point to data after X
+ // bytes in the heap? What are the skipped bytes in this case?
+ // In SQ4CD, this occurs with the returnVal selector of object
+ // Sq4GlobalNarrator when the game starts, and right after the narrator
+ // is heard (e.g. after he talks when examining something)
+ reg_t oldReg = *varp.getPointer(s->_segMan);
+ reg_t newReg = argp[1];
+ warning("send_selector(): argc = %d while modifying variable selector "
+ "%x (%s) of object %04x:%04x (%s) from %04x:%04x to %04x:%04x",
+ argc, selector, g_sci->getKernel()->getSelectorName(selector).c_str(), PRINT_REG(send_obj),
+ s->_segMan->getObjectName(send_obj), PRINT_REG(oldReg), PRINT_REG(newReg));
+ }
{
CallsStruct call;
@@ -438,9 +443,9 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
}
printf(") at %04x:%04x\n", PRINT_REG(funcp));
#endif // VM_DEBUG_SEND
- if (print_send_action) {
- printf("[invoke selector]\n");
- print_send_action = 0;
+ if (printSendActions) {
+ debug("[invoke selector]\n");
+ printSendActions = false;
}
{
@@ -456,7 +461,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
}
break;
- } // switch (lookup_selector())
+ } // switch (lookupSelector())
framesize -= (2 + argc);
argp += argc + 1;
@@ -477,9 +482,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
_exec_varselectors(s);
- if (s->_executionStack.empty())
- return NULL;
- return &(s->_executionStack.back());
+ return s->_executionStack.empty() ? NULL : &(s->_executionStack.back());
}
static ExecStack *add_exec_stack_varselector(Common::List<ExecStack> &execStack, reg_t objp, int argc, StackPtr argp, Selector selector, const ObjVarRef& address, int origin) {
@@ -565,11 +568,11 @@ static void callKernelFunc(EngineState *s, int kernelFuncNum, int argc) {
const KernelFuncWithSignature &kernelFunc = g_sci->getKernel()->_kernelFuncs[kernelFuncNum];
if (kernelFunc.signature
- && !g_sci->getKernel()->signatureMatch(kernelFunc.signature, argc, scriptState.xs->sp + 1)) {
+ && !g_sci->getKernel()->signatureMatch(kernelFunc.signature, argc, s->xs->sp + 1)) {
error("[VM] Invalid arguments to kernel call %x", kernelFuncNum);
}
- reg_t *argv = scriptState.xs->sp + 1;
+ reg_t *argv = s->xs->sp + 1;
if (!kernelFunc.isDummy) {
// Add stack frame to indicate we're executing a callk.
@@ -583,19 +586,26 @@ static void callKernelFunc(EngineState *s, int kernelFuncNum, int argc) {
//warning("callk %s", kernelFunc.orig_name.c_str());
- // TODO: SCI2/SCI2.1+ equivalent, once saving/loading works in SCI2/SCI2.1+
- if (g_loadFromLauncher >= 0 && kernelFuncNum == 0x8) {
- // A game is being loaded from the launcher, and kDisplay is called, all initialization has taken
- // place (i.e. menus have been constructed etc). Therefore, inject a kRestoreGame call
- // here, instead of the requested function.
- int saveSlot = g_loadFromLauncher;
- g_loadFromLauncher = -1; // invalidate slot, so that we don't load again
-
- if (saveSlot < 0)
- error("Requested to load invalid save slot"); // should never happen, really
-
- reg_t restoreArgv[2] = { NULL_REG, make_reg(0, saveSlot) }; // special call (argv[0] is NULL)
- kRestoreGame(s, 2, restoreArgv);
+ // TODO: SCI2.1 equivalent
+ if (s->loadFromLauncher >= 0 && (
+ (kernelFuncNum == 0x8 && getSciVersion() <= SCI_VERSION_1_1) || // DrawPic
+ (kernelFuncNum == 0x3d && getSciVersion() == SCI_VERSION_2) // GetSaveDir
+ //(kernelFuncNum == 0x28 && getSciVersion() == SCI_VERSION_2_1) // AddPlane
+ )) {
+
+ // A game is being loaded from the launcher, and the game is about to draw something on
+ // screen, hence all initialization has taken place (i.e. menus have been constructed etc).
+ // Therefore, inject a kRestoreGame call here, instead of the requested function.
+ // The restore call is injected here mainly for games which have a menu, as the menu is
+ // constructed when the game starts and is not reconstructed when a saved game is loaded.
+ int saveSlot = s->loadFromLauncher;
+ s->loadFromLauncher = -1; // invalidate slot, so that we don't load again
+
+ if (saveSlot < 0)
+ error("Requested to load invalid save slot"); // should never happen, really
+
+ reg_t restoreArgv[2] = { NULL_REG, make_reg(0, saveSlot) }; // special call (argv[0] is NULL)
+ kRestoreGame(s, 2, restoreArgv);
} else {
// Call kernel function
s->r_acc = kernelFunc.fun(s, argc, argv);
@@ -620,7 +630,7 @@ static void callKernelFunc(EngineState *s, int kernelFuncNum, int argc) {
static void gc_countdown(EngineState *s) {
if (s->gc_countdown-- <= 0) {
- s->gc_countdown = script_gc_interval;
+ s->gc_countdown = s->script_gc_interval;
run_gc(s);
}
}
@@ -708,13 +718,13 @@ void run_vm(EngineState *s, bool restoring) {
StackPtr s_temp; // Temporary stack pointer
int16 opparams[4]; // opcode parameters
- scriptState.restAdjust = s->restAdjust;
+ s->restAdjust = s->restAdjust;
// &rest adjusts the parameter count by this value
// Current execution data:
- scriptState.xs = &(s->_executionStack.back());
+ s->xs = &(s->_executionStack.back());
ExecStack *xs_new = NULL;
- Object *obj = s->_segMan->getObject(scriptState.xs->objp);
- Script *local_script = s->_segMan->getScriptIfLoaded(scriptState.xs->local_segment);
+ Object *obj = s->_segMan->getObject(s->xs->objp);
+ Script *local_script = s->_segMan->getScriptIfLoaded(s->xs->local_segment);
int old_execution_stack_base = s->execution_stack_base;
// Used to detect the stack bottom, for "physical" returns
const byte *code_buf = NULL; // (Avoid spurious warning)
@@ -724,25 +734,25 @@ void run_vm(EngineState *s, bool restoring) {
}
if (!restoring)
- s->execution_stack_base = s->_executionStack.size()-1;
+ s->execution_stack_base = s->_executionStack.size() - 1;
#ifndef DISABLE_VALIDATIONS
// Initialize maximum variable count
if (s->script_000->_localsBlock)
- scriptState.variables_max[VAR_GLOBAL] = s->script_000->_localsBlock->_locals.size();
+ s->variables_max[VAR_GLOBAL] = s->script_000->_localsBlock->_locals.size();
else
- scriptState.variables_max[VAR_GLOBAL] = 0;
+ s->variables_max[VAR_GLOBAL] = 0;
#endif
- scriptState.variables_seg[VAR_GLOBAL] = s->script_000->_localsSegment;
- scriptState.variables_seg[VAR_TEMP] = scriptState.variables_seg[VAR_PARAM] = s->_segMan->findSegmentByType(SEG_TYPE_STACK);
- scriptState.variables_base[VAR_TEMP] = scriptState.variables_base[VAR_PARAM] = s->stack_base;
+ s->variables_seg[VAR_GLOBAL] = s->script_000->_localsSegment;
+ s->variables_seg[VAR_TEMP] = s->variables_seg[VAR_PARAM] = s->_segMan->findSegmentByType(SEG_TYPE_STACK);
+ s->variables_base[VAR_TEMP] = s->variables_base[VAR_PARAM] = s->stack_base;
// SCI code reads the zeroth argument to determine argc
if (s->script_000->_localsBlock)
- scriptState.variables_base[VAR_GLOBAL] = scriptState.variables[VAR_GLOBAL] = s->script_000->_localsBlock->_locals.begin();
+ s->variables_base[VAR_GLOBAL] = s->variables[VAR_GLOBAL] = s->script_000->_localsBlock->_locals.begin();
else
- scriptState.variables_base[VAR_GLOBAL] = scriptState.variables[VAR_GLOBAL] = NULL;
+ s->variables_base[VAR_GLOBAL] = s->variables[VAR_GLOBAL] = NULL;
s->_executionStackPosChanged = true; // Force initialization
@@ -750,63 +760,63 @@ void run_vm(EngineState *s, bool restoring) {
int var_type; // See description below
int var_number;
- g_debugState.old_pc_offset = scriptState.xs->addr.pc.offset;
- g_debugState.old_sp = scriptState.xs->sp;
+ g_debugState.old_pc_offset = s->xs->addr.pc.offset;
+ g_debugState.old_sp = s->xs->sp;
if (s->_executionStackPosChanged) {
Script *scr;
- scriptState.xs = &(s->_executionStack.back());
+ s->xs = &(s->_executionStack.back());
s->_executionStackPosChanged = false;
- scr = s->_segMan->getScriptIfLoaded(scriptState.xs->addr.pc.segment);
+ scr = s->_segMan->getScriptIfLoaded(s->xs->addr.pc.segment);
if (!scr) {
// No script? Implicit return via fake instruction buffer
- warning("Running on non-existant script in segment %x", scriptState.xs->addr.pc.segment);
+ warning("Running on non-existant script in segment %x", s->xs->addr.pc.segment);
code_buf = _fake_return_buffer;
#ifndef DISABLE_VALIDATIONS
code_buf_size = 2;
#endif
- scriptState.xs->addr.pc.offset = 1;
+ s->xs->addr.pc.offset = 1;
scr = NULL;
obj = NULL;
} else {
- obj = s->_segMan->getObject(scriptState.xs->objp);
+ obj = s->_segMan->getObject(s->xs->objp);
code_buf = scr->_buf;
#ifndef DISABLE_VALIDATIONS
- code_buf_size = scr->_bufSize;
+ code_buf_size = scr->getBufSize();
#endif
- local_script = s->_segMan->getScriptIfLoaded(scriptState.xs->local_segment);
+ local_script = s->_segMan->getScriptIfLoaded(s->xs->local_segment);
if (!local_script) {
- warning("Could not find local script from segment %x", scriptState.xs->local_segment);
+ warning("Could not find local script from segment %x", s->xs->local_segment);
local_script = NULL;
- scriptState.variables_base[VAR_LOCAL] = scriptState.variables[VAR_LOCAL] = NULL;
+ s->variables_base[VAR_LOCAL] = s->variables[VAR_LOCAL] = NULL;
#ifndef DISABLE_VALIDATIONS
- scriptState.variables_max[VAR_LOCAL] = 0;
+ s->variables_max[VAR_LOCAL] = 0;
#endif
} else {
- scriptState.variables_seg[VAR_LOCAL] = local_script->_localsSegment;
+ s->variables_seg[VAR_LOCAL] = local_script->_localsSegment;
if (local_script->_localsBlock)
- scriptState.variables_base[VAR_LOCAL] = scriptState.variables[VAR_LOCAL] = local_script->_localsBlock->_locals.begin();
+ s->variables_base[VAR_LOCAL] = s->variables[VAR_LOCAL] = local_script->_localsBlock->_locals.begin();
else
- scriptState.variables_base[VAR_LOCAL] = scriptState.variables[VAR_LOCAL] = NULL;
+ s->variables_base[VAR_LOCAL] = s->variables[VAR_LOCAL] = NULL;
#ifndef DISABLE_VALIDATIONS
if (local_script->_localsBlock)
- scriptState.variables_max[VAR_LOCAL] = local_script->_localsBlock->_locals.size();
+ s->variables_max[VAR_LOCAL] = local_script->_localsBlock->_locals.size();
else
- scriptState.variables_max[VAR_LOCAL] = 0;
- scriptState.variables_max[VAR_TEMP] = scriptState.xs->sp - scriptState.xs->fp;
- scriptState.variables_max[VAR_PARAM] = scriptState.xs->argc + 1;
+ s->variables_max[VAR_LOCAL] = 0;
+ s->variables_max[VAR_TEMP] = s->xs->sp - s->xs->fp;
+ s->variables_max[VAR_PARAM] = s->xs->argc + 1;
#endif
}
- scriptState.variables[VAR_TEMP] = scriptState.xs->fp;
- scriptState.variables[VAR_PARAM] = scriptState.xs->variables_argp;
+ s->variables[VAR_TEMP] = s->xs->fp;
+ s->variables[VAR_PARAM] = s->xs->variables_argp;
}
}
- if (script_abort_flag || g_engine->shouldQuit())
+ if (s->script_abort_flag || g_engine->shouldQuit())
return; // Emergency
// Debug if this has been requested:
@@ -821,18 +831,20 @@ void run_vm(EngineState *s, bool restoring) {
}
#ifndef DISABLE_VALIDATIONS
- if (scriptState.xs->sp < scriptState.xs->fp)
- error("run_vm(): stack underflow");
+ if (s->xs->sp < s->xs->fp)
+ error("run_vm(): stack underflow, sp: %04x:%04x, fp: %04x:%04x",
+ PRINT_REG(*s->xs->sp), PRINT_REG(*s->xs->fp));
- scriptState.variables_max[VAR_TEMP] = scriptState.xs->sp - scriptState.xs->fp;
+ s->variables_max[VAR_TEMP] = s->xs->sp - s->xs->fp;
- if (scriptState.xs->addr.pc.offset >= code_buf_size)
- error("run_vm(): program counter gone astray");
+ if (s->xs->addr.pc.offset >= code_buf_size)
+ error("run_vm(): program counter gone astray, addr: %d, code buffer size: %d",
+ s->xs->addr.pc.offset, code_buf_size);
#endif
// Get opcode
byte extOpcode;
- scriptState.xs->addr.pc.offset += readPMachineInstruction(code_buf + scriptState.xs->addr.pc.offset, extOpcode, opparams);
+ s->xs->addr.pc.offset += readPMachineInstruction(code_buf + s->xs->addr.pc.offset, extOpcode, opparams);
const byte opcode = extOpcode >> 1;
switch (opcode) {
@@ -1063,16 +1075,16 @@ void run_vm(EngineState *s, bool restoring) {
case op_bt: // 0x17 (23)
if (s->r_acc.offset || s->r_acc.segment)
- scriptState.xs->addr.pc.offset += opparams[0];
+ s->xs->addr.pc.offset += opparams[0];
break;
case op_bnt: // 0x18 (24)
if (!(s->r_acc.offset || s->r_acc.segment))
- scriptState.xs->addr.pc.offset += opparams[0];
+ s->xs->addr.pc.offset += opparams[0];
break;
case op_jmp: // 0x19 (25)
- scriptState.xs->addr.pc.offset += opparams[0];
+ s->xs->addr.pc.offset += opparams[0];
break;
case op_ldi: // 0x1a (26)
@@ -1088,34 +1100,34 @@ void run_vm(EngineState *s, bool restoring) {
break;
case op_toss: // 0x1d (29)
- scriptState.xs->sp--;
+ s->xs->sp--;
break;
case op_dup: // 0x1e (30)
- r_temp = scriptState.xs->sp[-1];
+ r_temp = s->xs->sp[-1];
PUSH32(r_temp);
break;
case op_link: // 0x1f (31)
for (int i = 0; i < opparams[0]; i++)
- scriptState.xs->sp[i] = NULL_REG;
- scriptState.xs->sp += opparams[0];
+ s->xs->sp[i] = NULL_REG;
+ s->xs->sp += opparams[0];
break;
case op_call: { // 0x20 (32)
int argc = (opparams[1] >> 1) // Given as offset, but we need count
- + 1 + scriptState.restAdjust;
- StackPtr call_base = scriptState.xs->sp - argc;
- scriptState.xs->sp[1].offset += scriptState.restAdjust;
-
- xs_new = add_exec_stack_entry(s->_executionStack, make_reg(scriptState.xs->addr.pc.segment,
- scriptState.xs->addr.pc.offset + opparams[0]),
- scriptState.xs->sp, scriptState.xs->objp,
- (validate_arithmetic(*call_base)) + scriptState.restAdjust,
- call_base, NULL_SELECTOR, scriptState.xs->objp,
- s->_executionStack.size()-1, scriptState.xs->local_segment);
- scriptState.restAdjust = 0; // Used up the &rest adjustment
- scriptState.xs->sp = call_base;
+ + 1 + s->restAdjust;
+ StackPtr call_base = s->xs->sp - argc;
+ s->xs->sp[1].offset += s->restAdjust;
+
+ xs_new = add_exec_stack_entry(s->_executionStack, make_reg(s->xs->addr.pc.segment,
+ s->xs->addr.pc.offset + opparams[0]),
+ s->xs->sp, s->xs->objp,
+ (validate_arithmetic(*call_base)) + s->restAdjust,
+ call_base, NULL_SELECTOR, s->xs->objp,
+ s->_executionStack.size()-1, s->xs->local_segment);
+ s->restAdjust = 0; // Used up the &rest adjustment
+ s->xs->sp = call_base;
s->_executionStackPosChanged = true;
break;
@@ -1124,23 +1136,23 @@ void run_vm(EngineState *s, bool restoring) {
case op_callk: { // 0x21 (33)
gc_countdown(s);
- scriptState.xs->sp -= (opparams[1] >> 1) + 1;
+ s->xs->sp -= (opparams[1] >> 1) + 1;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
if (!oldScriptHeader) {
- scriptState.xs->sp -= scriptState.restAdjust;
- s->restAdjust = 0; // We just used up the scriptState.restAdjust, remember?
+ s->xs->sp -= s->restAdjust;
+ s->restAdjust = 0; // We just used up the s->restAdjust, remember?
}
- int argc = validate_arithmetic(scriptState.xs->sp[0]);
+ int argc = validate_arithmetic(s->xs->sp[0]);
if (!oldScriptHeader)
- argc += scriptState.restAdjust;
+ argc += s->restAdjust;
callKernelFunc(s, opparams[0], argc);
if (!oldScriptHeader)
- scriptState.restAdjust = s->restAdjust;
+ s->restAdjust = s->restAdjust;
// Calculate xs again: The kernel function might
// have spawned a new VM
@@ -1151,27 +1163,27 @@ void run_vm(EngineState *s, bool restoring) {
}
case op_callb: // 0x22 (34)
- temp = ((opparams[1] >> 1) + scriptState.restAdjust + 1);
- s_temp = scriptState.xs->sp;
- scriptState.xs->sp -= temp;
-
- scriptState.xs->sp[0].offset += scriptState.restAdjust;
- xs_new = execute_method(s, 0, opparams[0], s_temp, scriptState.xs->objp,
- scriptState.xs->sp[0].offset, scriptState.xs->sp);
- scriptState.restAdjust = 0; // Used up the &rest adjustment
+ temp = ((opparams[1] >> 1) + s->restAdjust + 1);
+ s_temp = s->xs->sp;
+ s->xs->sp -= temp;
+
+ s->xs->sp[0].offset += s->restAdjust;
+ xs_new = execute_method(s, 0, opparams[0], s_temp, s->xs->objp,
+ s->xs->sp[0].offset, s->xs->sp);
+ s->restAdjust = 0; // Used up the &rest adjustment
if (xs_new) // in case of error, keep old stack
s->_executionStackPosChanged = true;
break;
case op_calle: // 0x23 (35)
- temp = ((opparams[2] >> 1) + scriptState.restAdjust + 1);
- s_temp = scriptState.xs->sp;
- scriptState.xs->sp -= temp;
+ temp = ((opparams[2] >> 1) + s->restAdjust + 1);
+ s_temp = s->xs->sp;
+ s->xs->sp -= temp;
- scriptState.xs->sp[0].offset += scriptState.restAdjust;
- xs_new = execute_method(s, opparams[0], opparams[1], s_temp, scriptState.xs->objp,
- scriptState.xs->sp[0].offset, scriptState.xs->sp);
- scriptState.restAdjust = 0; // Used up the &rest adjustment
+ s->xs->sp[0].offset += s->restAdjust;
+ xs_new = execute_method(s, opparams[0], opparams[1], s_temp, s->xs->objp,
+ s->xs->sp[0].offset, s->xs->sp);
+ s->restAdjust = 0; // Used up the &rest adjustment
if (xs_new) // in case of error, keep old stack
s->_executionStackPosChanged = true;
@@ -1179,17 +1191,17 @@ void run_vm(EngineState *s, bool restoring) {
case op_ret: // 0x24 (36)
do {
- StackPtr old_sp2 = scriptState.xs->sp;
- StackPtr old_fp = scriptState.xs->fp;
+ StackPtr old_sp2 = s->xs->sp;
+ StackPtr old_fp = s->xs->fp;
ExecStack *old_xs = &(s->_executionStack.back());
- if ((int)s->_executionStack.size()-1 == s->execution_stack_base) { // Have we reached the base?
+ if ((int)s->_executionStack.size() - 1 == s->execution_stack_base) { // Have we reached the base?
s->execution_stack_base = old_execution_stack_base; // Restore stack base
s->_executionStack.pop_back();
s->_executionStackPosChanged = true;
- s->restAdjust = scriptState.restAdjust; // Update &rest
+ s->restAdjust = s->restAdjust; // Update &rest
return; // "Hard" return
}
@@ -1205,33 +1217,33 @@ void run_vm(EngineState *s, bool restoring) {
// Not reached the base, so let's do a soft return
s->_executionStack.pop_back();
s->_executionStackPosChanged = true;
- scriptState.xs = &(s->_executionStack.back());
+ s->xs = &(s->_executionStack.back());
- if (scriptState.xs->sp == CALL_SP_CARRY // Used in sends to 'carry' the stack pointer
- || scriptState.xs->type != EXEC_STACK_TYPE_CALL) {
- scriptState.xs->sp = old_sp2;
- scriptState.xs->fp = old_fp;
+ if (s->xs->sp == CALL_SP_CARRY // Used in sends to 'carry' the stack pointer
+ || s->xs->type != EXEC_STACK_TYPE_CALL) {
+ s->xs->sp = old_sp2;
+ s->xs->fp = old_fp;
}
- } while (scriptState.xs->type == EXEC_STACK_TYPE_VARSELECTOR);
+ } while (s->xs->type == EXEC_STACK_TYPE_VARSELECTOR);
// Iterate over all varselector accesses
s->_executionStackPosChanged = true;
- xs_new = scriptState.xs;
+ xs_new = s->xs;
break;
case op_send: // 0x25 (37)
- s_temp = scriptState.xs->sp;
- scriptState.xs->sp -= ((opparams[0] >> 1) + scriptState.restAdjust); // Adjust stack
+ s_temp = s->xs->sp;
+ s->xs->sp -= ((opparams[0] >> 1) + s->restAdjust); // Adjust stack
- scriptState.xs->sp[1].offset += scriptState.restAdjust;
+ s->xs->sp[1].offset += s->restAdjust;
xs_new = send_selector(s, s->r_acc, s->r_acc, s_temp,
- (int)(opparams[0] >> 1) + (uint16)scriptState.restAdjust, scriptState.xs->sp);
+ (int)(opparams[0] >> 1) + (uint16)s->restAdjust, s->xs->sp);
- if (xs_new && xs_new != scriptState.xs)
+ if (xs_new && xs_new != s->xs)
s->_executionStackPosChanged = true;
- scriptState.restAdjust = 0;
+ s->restAdjust = 0;
break;
@@ -1242,7 +1254,7 @@ void run_vm(EngineState *s, bool restoring) {
case op_class: // 0x28 (40)
s->r_acc = s->_segMan->getClassAddress((unsigned)opparams[0], SCRIPT_GET_LOCK,
- scriptState.xs->addr.pc);
+ s->xs->addr.pc);
break;
case 0x29: // (41)
@@ -1250,48 +1262,48 @@ void run_vm(EngineState *s, bool restoring) {
break;
case op_self: // 0x2a (42)
- s_temp = scriptState.xs->sp;
- scriptState.xs->sp -= ((opparams[0] >> 1) + scriptState.restAdjust); // Adjust stack
+ s_temp = s->xs->sp;
+ s->xs->sp -= ((opparams[0] >> 1) + s->restAdjust); // Adjust stack
- scriptState.xs->sp[1].offset += scriptState.restAdjust;
- xs_new = send_selector(s, scriptState.xs->objp, scriptState.xs->objp,
- s_temp, (int)(opparams[0] >> 1) + (uint16)scriptState.restAdjust,
- scriptState.xs->sp);
+ s->xs->sp[1].offset += s->restAdjust;
+ xs_new = send_selector(s, s->xs->objp, s->xs->objp,
+ s_temp, (int)(opparams[0] >> 1) + (uint16)s->restAdjust,
+ s->xs->sp);
- if (xs_new && xs_new != scriptState.xs)
+ if (xs_new && xs_new != s->xs)
s->_executionStackPosChanged = true;
- scriptState.restAdjust = 0;
+ s->restAdjust = 0;
break;
case op_super: // 0x2b (43)
- r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, scriptState.xs->addr.pc);
+ r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, s->xs->addr.pc);
if (!r_temp.segment)
error("[VM]: Invalid superclass in object");
else {
- s_temp = scriptState.xs->sp;
- scriptState.xs->sp -= ((opparams[1] >> 1) + scriptState.restAdjust); // Adjust stack
+ s_temp = s->xs->sp;
+ s->xs->sp -= ((opparams[1] >> 1) + s->restAdjust); // Adjust stack
- scriptState.xs->sp[1].offset += scriptState.restAdjust;
- xs_new = send_selector(s, r_temp, scriptState.xs->objp, s_temp,
- (int)(opparams[1] >> 1) + (uint16)scriptState.restAdjust,
- scriptState.xs->sp);
+ s->xs->sp[1].offset += s->restAdjust;
+ xs_new = send_selector(s, r_temp, s->xs->objp, s_temp,
+ (int)(opparams[1] >> 1) + (uint16)s->restAdjust,
+ s->xs->sp);
- if (xs_new && xs_new != scriptState.xs)
+ if (xs_new && xs_new != s->xs)
s->_executionStackPosChanged = true;
- scriptState.restAdjust = 0;
+ s->restAdjust = 0;
}
break;
case op_rest: // 0x2c (44)
temp = (uint16) opparams[0]; // First argument
- scriptState.restAdjust = MAX<int16>(scriptState.xs->argc - temp + 1, 0); // +1 because temp counts the paramcount while argc doesn't
+ s->restAdjust = MAX<int16>(s->xs->argc - temp + 1, 0); // +1 because temp counts the paramcount while argc doesn't
- for (; temp <= scriptState.xs->argc; temp++)
- PUSH32(scriptState.xs->variables_argp[temp]);
+ for (; temp <= s->xs->argc; temp++)
+ PUSH32(s->xs->variables_argp[temp]);
break;
@@ -1300,8 +1312,8 @@ void run_vm(EngineState *s, bool restoring) {
var_number = temp & 0x03; // Get variable type
// Get variable block offset
- r_temp.segment = scriptState.variables_seg[var_number];
- r_temp.offset = scriptState.variables[var_number] - scriptState.variables_base[var_number];
+ r_temp.segment = s->variables_seg[var_number];
+ r_temp.offset = s->variables[var_number] - s->variables_base[var_number];
if (temp & 0x08) // Add accumulator offset if requested
r_temp.offset += signed_validate_arithmetic(s->r_acc);
@@ -1314,7 +1326,7 @@ void run_vm(EngineState *s, bool restoring) {
case op_selfID: // 0x2e (46)
- s->r_acc = scriptState.xs->objp;
+ s->r_acc = s->xs->objp;
break;
case 0x2f: // (47)
@@ -1382,17 +1394,17 @@ void run_vm(EngineState *s, bool restoring) {
break;
case op_lofsa: // 0x39 (57)
- s->r_acc.segment = scriptState.xs->addr.pc.segment;
+ s->r_acc.segment = s->xs->addr.pc.segment;
switch (g_sci->_features->detectLofsType()) {
case SCI_VERSION_1_1:
- s->r_acc.offset = opparams[0] + local_script->_scriptSize;
+ s->r_acc.offset = opparams[0] + local_script->getScriptSize();
break;
case SCI_VERSION_1_MIDDLE:
s->r_acc.offset = opparams[0];
break;
default:
- s->r_acc.offset = scriptState.xs->addr.pc.offset + opparams[0];
+ s->r_acc.offset = s->xs->addr.pc.offset + opparams[0];
}
#ifndef DISABLE_VALIDATIONS
@@ -1404,17 +1416,17 @@ void run_vm(EngineState *s, bool restoring) {
break;
case op_lofss: // 0x3a (58)
- r_temp.segment = scriptState.xs->addr.pc.segment;
+ r_temp.segment = s->xs->addr.pc.segment;
switch (g_sci->_features->detectLofsType()) {
case SCI_VERSION_1_1:
- r_temp.offset = opparams[0] + local_script->_scriptSize;
+ r_temp.offset = opparams[0] + local_script->getScriptSize();
break;
case SCI_VERSION_1_MIDDLE:
r_temp.offset = opparams[0];
break;
default:
- r_temp.offset = scriptState.xs->addr.pc.offset + opparams[0];
+ r_temp.offset = s->xs->addr.pc.offset + opparams[0];
}
#ifndef DISABLE_VALIDATIONS
@@ -1440,10 +1452,10 @@ void run_vm(EngineState *s, bool restoring) {
case op_pushSelf: // 0x3e (62)
if (!(extOpcode & 1)) {
- PUSH32(scriptState.xs->objp);
+ PUSH32(s->xs->objp);
} else {
// Debug opcode op_file, skip null-terminated string (file name)
- while (code_buf[scriptState.xs->addr.pc.offset++]) ;
+ while (code_buf[s->xs->addr.pc.offset++]) ;
}
break;
@@ -1657,16 +1669,16 @@ void run_vm(EngineState *s, bool restoring) {
} // switch (opcode)
if (s->_executionStackPosChanged) // Force initialization
- scriptState.xs = xs_new;
+ s->xs = xs_new;
//#ifndef DISABLE_VALIDATIONS
- if (scriptState.xs != &(s->_executionStack.back())) {
+ if (s->xs != &(s->_executionStack.back())) {
warning("xs is stale (%p vs %p); last command was %02x",
- (void *)scriptState.xs, (void *)&(s->_executionStack.back()),
+ (void *)s->xs, (void *)&(s->_executionStack.back()),
opcode);
}
//#endif
- ++script_step_counter;
+ ++s->script_step_counter;
}
}
@@ -1676,17 +1688,16 @@ static void _init_stack_base_with_selector(EngineState *s, Selector selector) {
}
static EngineState *_game_run(EngineState *&s) {
- EngineState *successor = NULL;
- int game_is_finished = 0;
+ bool restoring = false;
if (DebugMan.isDebugChannelEnabled(kDebugLevelOnStartup))
g_sci->getSciDebugger()->attach();
do {
s->_executionStackPosChanged = false;
- run_vm(s, successor ? true : false);
+ run_vm(s, restoring);
if (s->restarting_flags & SCI_GAME_IS_RESTARTING_NOW) { // Restart was requested?
- successor = NULL;
+ restoring = false;
s->_executionStack.clear();
s->_executionStackPosChanged = false;
@@ -1700,17 +1711,15 @@ static EngineState *_game_run(EngineState *&s) {
send_selector(s, s->_gameObj, s->_gameObj, s->stack_base, 2, s->stack_base);
- script_abort_flag = 0;
- s->restarting_flags = SCI_GAME_WAS_RESTARTED | SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE;
+ s->script_abort_flag = 0;
+ s->restarting_flags = SCI_GAME_WAS_RESTARTED;
} else {
- successor = s->successor;
- if (successor) {
+ restoring = s->restoring;
+ if (restoring) {
game_exit(s);
- delete s;
- s = successor;
-
- if (script_abort_flag == 2) {
+ s->restoring = false;
+ if (s->script_abort_flag == 2) {
debugC(2, kDebugLevelVM, "Restarting with replay()");
s->_executionStack.clear(); // Restart with replay
@@ -1719,12 +1728,12 @@ static EngineState *_game_run(EngineState *&s) {
send_selector(s, s->_gameObj, s->_gameObj, s->stack_base, 2, s->stack_base);
}
- script_abort_flag = 0;
+ s->script_abort_flag = 0;
} else
- game_is_finished = 1;
+ break; // exit loop
}
- } while (!game_is_finished);
+ } while (true);
return s;
}
@@ -1732,7 +1741,7 @@ static EngineState *_game_run(EngineState *&s) {
int game_run(EngineState **_s) {
EngineState *s = *_s;
- debugC(2, kDebugLevelVM, "Calling %s::play()", s->_gameId.c_str());
+ debugC(2, kDebugLevelVM, "Calling %s::play()", g_sci->getGameID());
_init_stack_base_with_selector(s, g_sci->getKernel()->_selectorCache.play); // Call the play selector
// Now: Register the first element on the execution stack-
@@ -1750,28 +1759,18 @@ int game_run(EngineState **_s) {
return 0;
}
-void quit_vm() {
- script_abort_flag = 1; // Terminate VM
+void quit_vm(EngineState *s) {
+ s->script_abort_flag = 1; // Terminate VM
g_debugState.seeking = kDebugSeekNothing;
g_debugState.runningStep = 0;
}
-void shrink_execution_stack(EngineState *s, uint size) {
- assert(s->_executionStack.size() >= size);
- Common::List<ExecStack>::iterator iter;
- iter = s->_executionStack.begin();
- for (uint i = 0; i < size; ++i)
- ++iter;
- s->_executionStack.erase(iter, s->_executionStack.end());
-}
-
-reg_t* ObjVarRef::getPointer(SegManager *segMan) const {
+reg_t *ObjVarRef::getPointer(SegManager *segMan) const {
Object *o = segMan->getObject(obj);
- if (!o) return 0;
- return &(o->_variables[varindex]);
+ return o ? &o->getVariableRef(varindex) : 0;
}
-reg_t* ExecStack::getVarPointer(SegManager *segMan) const {
+reg_t *ExecStack::getVarPointer(SegManager *segMan) const {
assert(type == EXEC_STACK_TYPE_VARSELECTOR);
return addr.varp.getPointer(segMan);
}
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index 8e40fed818..67a6bd0dc3 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -43,44 +43,9 @@ class ResourceManager;
/** Number of bytes to be allocated for the stack */
#define VM_STACK_SIZE 0x1000
-/** Maximum number of calls residing on the stack */
-#define SCRIPT_MAX_EXEC_STACK 256
-/** Maximum number of entries in the class table */
-#define SCRIPT_MAX_CLASSTABLE_SIZE 256
-/** Maximum number of cloned objects on the heap */
-#define SCRIPT_MAX_CLONES 256
-
-
-/** Object-relative offset of the selector area inside a script */
-#define SCRIPT_SELECTOR_OFFSET 8 -8
-
-/** Object-relative offset of the pointer to the underlying script's local variables */
-#define SCRIPT_LOCALVARPTR_OFFSET 2 -8
-
-/** Object-relative offset of the selector counter */
-#define SCRIPT_SELECTORCTR_OFFSET 6 -8
-
-/** Object-relative offset of the offset of the function area */
-#define SCRIPT_FUNCTAREAPTR_OFFSET 4 -8
-
-/** Offset that has to be added to the function area pointer */
-#define SCRIPT_FUNCTAREAPTR_MAGIC 8 -8
-
-/** Offset of the name pointer */
-#define SCRIPT_NAME_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? 14 -8 : 16)
-
-/** Object-relative offset of the -info- selector */
-#define SCRIPT_INFO_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? 12 -8 : 14)
-
-/** Flag fo the -info- selector */
-#define SCRIPT_INFO_CLONE 0x0001
-
-/** Flag for the -info- selector */
-#define SCRIPT_INFO_CLASS 0x8000
-
-
/** Magical object identifier */
#define SCRIPT_OBJECT_MAGIC_NUMBER 0x1234
+
/** Offset of this identifier */
#define SCRIPT_OBJECT_MAGIC_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? -8 : 0)
@@ -89,13 +54,10 @@ class ResourceManager;
#define SCRIPT_SUPERCLASS_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? 10 -8 : 12)
-/** Magic adjustment value for lofsa and lofss */
-#define SCRIPT_LOFS_MAGIC 3
-
/** Stack pointer value: Use predecessor's value */
#define CALL_SP_CARRY NULL
-/** Types of selectors as returned by lookup_selector() below. */
+/** Types of selectors as returned by lookupSelector() below. */
enum SelectorType {
kSelectorNone = 0,
kSelectorVariable,
@@ -195,7 +157,9 @@ struct SelectorCache {
// Used for auto detection purposes
Selector overlay; ///< Used to determine if a game is using old gfx functions or not
- Selector setCursor; ///< For cursor semantics autodetection
+
+ // SCI1.1 Mac icon bar selectors
+ Selector iconIndex; ///< Used to index icon bar objects
#ifdef ENABLE_SCI32
Selector data; // Used by Array()/String()
@@ -260,41 +224,11 @@ enum {
VAR_PARAM = 3
};
-/**
- * Structure for storing the current internal state of the VM.
- */
-struct ScriptState {
- ExecStack *xs;
- int16 restAdjust;
- reg_t *variables[4]; ///< global, local, temp, param, as immediate pointers
- reg_t *variables_base[4]; ///< Used for referencing VM ops
- SegmentId variables_seg[4]; ///< Same as above, contains segment IDs
- int variables_max[4]; ///< Max. values for all variables
-};
-
-/**
- * The current internal state of the VM.
- */
-extern ScriptState scriptState;
-
-/**
- * Set this to 1 to abort script execution immediately. Aborting will
- * leave the debug exec stack intact.
- * Set it to 2 to force a replay afterwards.
- */
-extern int script_abort_flag;
-
/** Number of kernel calls in between gcs; should be < 50000 */
enum {
GC_INTERVAL = 32768
};
-/** Initially GC_DELAY, can be set at runtime */
-extern int script_gc_interval;
-
-/** Number of steps executed */
-extern int script_step_counter;
-
/**
* Executes function pubfunct of the specified script.
@@ -376,7 +310,7 @@ int script_init_engine(EngineState *);
* kSelectorMethod if the selector represents a
* method
*/
-SelectorType lookup_selector(SegManager *segMan, reg_t obj, Selector selectorid,
+SelectorType lookupSelector(SegManager *segMan, reg_t obj, Selector selectorid,
ObjVarRef *varp, reg_t *fptr);
/**
@@ -466,13 +400,7 @@ int game_exit(EngineState *s);
/**
* Instructs the virtual machine to abort
*/
-void quit_vm();
-
-/**
- * Shrink execution stack to size.
- * Contains an assert it is not already smaller.
- */
-void shrink_execution_stack(EngineState *s, uint size);
+void quit_vm(EngineState *s);
/**
* Read a PMachine instruction from a memory buffer and return its length.
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index 53f4675f56..c3be22b143 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -319,8 +319,6 @@ sciEvent SciEvent::get(unsigned int mask) {
//sci_event_t error_event = { SCI_EVT_ERROR, 0, 0, 0 };
sciEvent event = { 0, 0, 0, 0 };
- // TODO: we need to call Cursor::refreshPosition() before each screen update to limit the mouse cursor position
-
// Update the screen here, since it's called very often
g_system->updateScreen();
@@ -389,7 +387,6 @@ void SciEvent::sleep(uint32 msecs) {
while (true) {
// let backend process events and update the screen
get(SCI_EVENT_PEEK);
- // TODO: we need to call Cursor::refreshPosition() before each screen update to limit the mouse cursor position
time = g_system->getMillis();
if (time + 10 < wakeup_time) {
g_system->delayMillis(10);
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index 71c7b7dd7f..c201b2cfb7 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -92,10 +92,10 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
}
}
- signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
+ signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
if (!(signal & kSignalFrozen)) {
// Call .doit method of that object
- invoke_selector(_s, curObject, g_sci->getKernel()->_selectorCache.doit, kContinueOnInvalidSelector, argc, argv, 0);
+ invokeSelector(_s, curObject, g_sci->getKernel()->_selectorCache.doit, kContinueOnInvalidSelector, argc, argv, 0);
// Lookup node again, since the nodetable it was in may have been reallocated
curNode = _s->_segMan->lookupNode(curAddress);
}
@@ -109,7 +109,15 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
}
bool sortHelper(const AnimateEntry* entry1, const AnimateEntry* entry2) {
- return (entry1->y == entry2->y) ? (entry1->z < entry2->z) : (entry1->y < entry2->y);
+ if (entry1->y == entry2->y) {
+ // if both y and z are the same, use the order we were given originally
+ // this is needed for special cases like iceman room 35
+ if (entry1->z == entry2->z)
+ return entry1->givenOrderNo < entry2->givenOrderNo;
+ else
+ return entry1->z < entry2->z;
+ }
+ return entry1->y < entry2->y;
}
void GfxAnimate::makeSortedList(List *list) {
@@ -156,21 +164,22 @@ void GfxAnimate::makeSortedList(List *list) {
listEntry->object = curObject;
// Get data from current object
- listEntry->viewId = GET_SEL32V(_s->_segMan, curObject, SELECTOR(view));
- listEntry->loopNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(loop));
- listEntry->celNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(cel));
- listEntry->paletteNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(palette));
- listEntry->x = GET_SEL32V(_s->_segMan, curObject, SELECTOR(x));
- listEntry->y = GET_SEL32V(_s->_segMan, curObject, SELECTOR(y));
- listEntry->z = GET_SEL32V(_s->_segMan, curObject, SELECTOR(z));
- listEntry->priority = GET_SEL32V(_s->_segMan, curObject, SELECTOR(priority));
- listEntry->signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
+ listEntry->givenOrderNo = listNr;
+ listEntry->viewId = readSelectorValue(_s->_segMan, curObject, SELECTOR(view));
+ listEntry->loopNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(loop));
+ listEntry->celNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(cel));
+ listEntry->paletteNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(palette));
+ listEntry->x = readSelectorValue(_s->_segMan, curObject, SELECTOR(x));
+ listEntry->y = readSelectorValue(_s->_segMan, curObject, SELECTOR(y));
+ listEntry->z = readSelectorValue(_s->_segMan, curObject, SELECTOR(z));
+ listEntry->priority = readSelectorValue(_s->_segMan, curObject, SELECTOR(priority));
+ listEntry->signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
if (getSciVersion() >= SCI_VERSION_1_1) {
// Cel scaling
- listEntry->scaleSignal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleSignal));
+ listEntry->scaleSignal = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleSignal));
if (listEntry->scaleSignal & kScaleSignalDoScaling) {
- listEntry->scaleX = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleX));
- listEntry->scaleY = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleY));
+ listEntry->scaleX = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleX));
+ listEntry->scaleY = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY));
} else {
listEntry->scaleX = 128;
listEntry->scaleY = 128;
@@ -219,11 +228,11 @@ void GfxAnimate::fill(byte &old_picNotValid) {
// adjust loop and cel, if any of those is invalid
if (listEntry->loopNo >= view->getLoopCount()) {
listEntry->loopNo = 0;
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(loop), listEntry->loopNo);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(loop), listEntry->loopNo);
}
if (listEntry->celNo >= view->getCelCount(listEntry->loopNo)) {
listEntry->celNo = 0;
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(cel), listEntry->celNo);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(cel), listEntry->celNo);
}
// Create rect according to coordinates and given cel
@@ -232,17 +241,17 @@ void GfxAnimate::fill(byte &old_picNotValid) {
} else {
view->getCelRect(listEntry->loopNo, listEntry->celNo, listEntry->x, listEntry->y, listEntry->z, &listEntry->celRect);
}
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsLeft), listEntry->celRect.left);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsTop), listEntry->celRect.top);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsRight), listEntry->celRect.right);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsBottom), listEntry->celRect.bottom);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), listEntry->celRect.left);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), listEntry->celRect.top);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsRight), listEntry->celRect.right);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsBottom), listEntry->celRect.bottom);
signal = listEntry->signal;
// Calculate current priority according to y-coordinate
if (!(signal & kSignalFixedPriority)) {
listEntry->priority = _ports->kernelCoordinateToPriority(listEntry->y);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(priority), listEntry->priority);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(priority), listEntry->priority);
}
if (signal & kSignalNoUpdate) {
@@ -282,14 +291,14 @@ void GfxAnimate::update() {
if (signal & kSignalNoUpdate) {
if (!(signal & kSignalRemoveView)) {
- bitsHandle = GET_SEL32(_s->_segMan, curObject, SELECTOR(underBits));
+ bitsHandle = readSelector(_s->_segMan, curObject, SELECTOR(underBits));
if (_screen->_picNotValid != 1) {
_paint16->bitsRestore(bitsHandle);
listEntry->showBitsFlag = true;
} else {
_paint16->bitsFree(bitsHandle);
}
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(underBits), 0);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(underBits), 0);
}
signal &= 0xFFFF ^ kSignalForceUpdate;
signal &= signal & kSignalViewUpdated ? 0xFFFF ^ (kSignalViewUpdated | kSignalNoUpdate) : 0xFFFF;
@@ -339,7 +348,7 @@ void GfxAnimate::update() {
bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY);
else
bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_ALL);
- PUT_SEL32(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
+ writeSelector(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
}
listEntry->signal = signal;
}
@@ -387,7 +396,7 @@ void GfxAnimate::drawCels() {
if (!(signal & (kSignalNoUpdate | kSignalHidden | kSignalAlwaysUpdate))) {
// Save background
bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_ALL);
- PUT_SEL32(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
+ writeSelector(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
// draw corresponding cel
_paint16->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo, listEntry->scaleX, listEntry->scaleY);
@@ -423,10 +432,10 @@ void GfxAnimate::updateScreen(byte oldPicNotValid) {
if (listEntry->showBitsFlag || !(signal & (kSignalRemoveView | kSignalNoUpdate) ||
(!(signal & kSignalRemoveView) && (signal & kSignalNoUpdate) && oldPicNotValid))) {
- lsRect.left = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsLeft));
- lsRect.top = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsTop));
- lsRect.right = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsRight));
- lsRect.bottom = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsBottom));
+ lsRect.left = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsLeft));
+ lsRect.top = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsTop));
+ lsRect.right = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsRight));
+ lsRect.bottom = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsBottom));
workerRect = lsRect;
workerRect.clip(listEntry->celRect);
@@ -438,10 +447,10 @@ void GfxAnimate::updateScreen(byte oldPicNotValid) {
_paint16->bitsShow(lsRect);
workerRect = listEntry->celRect;
}
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsLeft), workerRect.left);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsTop), workerRect.top);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsRight), workerRect.right);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsBottom), workerRect.bottom);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsLeft), workerRect.left);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsTop), workerRect.top);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsRight), workerRect.right);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsBottom), workerRect.bottom);
_paint16->bitsShow(workerRect);
if (signal & kSignalHidden) {
@@ -472,7 +481,7 @@ void GfxAnimate::restoreAndDelete(int argc, reg_t *argv) {
signal = listEntry->signal;
// Finally update signal
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(signal), signal);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(signal), signal);
listIterator++;
}
@@ -481,16 +490,16 @@ void GfxAnimate::restoreAndDelete(int argc, reg_t *argv) {
listEntry = *listIterator;
curObject = listEntry->object;
// We read out signal here again, this is not by accident but to ensure that we got an up-to-date signal
- signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
+ signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
if ((signal & (kSignalNoUpdate | kSignalRemoveView)) == 0) {
- _paint16->bitsRestore(GET_SEL32(_s->_segMan, curObject, SELECTOR(underBits)));
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(underBits), 0);
+ _paint16->bitsRestore(readSelector(_s->_segMan, curObject, SELECTOR(underBits)));
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(underBits), 0);
}
if (signal & kSignalDisposeMe) {
// Call .delete_ method of that object
- invoke_selector(_s, curObject, g_sci->getKernel()->_selectorCache.delete_, kContinueOnInvalidSelector, argc, argv, 0);
+ invokeSelector(_s, curObject, g_sci->getKernel()->_selectorCache.delete_, kContinueOnInvalidSelector, argc, argv, 0);
}
listIterator--;
}
diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h
index 2cc59b1767..706b7182cf 100644
--- a/engines/sci/graphics/animate.h
+++ b/engines/sci/graphics/animate.h
@@ -40,7 +40,7 @@ enum ViewSignals {
kSignalAlwaysUpdate = 0x0020,
kSignalForceUpdate = 0x0040,
kSignalRemoveView = 0x0080,
- kSignalFrozen = 0x0100,
+ kSignalFrozen = 0x0100, // I got frozen today!!
kSignalExtraActor = 0x0200, // unused by us, defines all actors that may be included into the background if speed is too slow
kSignalHitObstacle = 0x0400, // used in the actor movement code by kDoBresen()
kSignalDoesntTurn = 0x0800, // used by _k_dirloop() to determine if an actor can turn or not
@@ -57,6 +57,7 @@ enum ViewScaleSignals {
};
struct AnimateEntry {
+ int16 givenOrderNo;
reg_t object;
GuiResourceId viewId;
int16 loopNo;
diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp
index 36dd2d4aed..3102edc2fa 100644
--- a/engines/sci/graphics/compare.cpp
+++ b/engines/sci/graphics/compare.cpp
@@ -79,12 +79,12 @@ bool GfxCompare::canBeHereCheckRectList(reg_t checkObject, const Common::Rect &c
while (curNode) {
curObject = curNode->value;
if (curObject != checkObject) {
- signal = GET_SEL32V(_segMan, curObject, SELECTOR(signal));
+ signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
if ((signal & (kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate)) == 0) {
- curRect.left = GET_SEL32V(_segMan, curObject, SELECTOR(brLeft));
- curRect.top = GET_SEL32V(_segMan, curObject, SELECTOR(brTop));
- curRect.right = GET_SEL32V(_segMan, curObject, SELECTOR(brRight));
- curRect.bottom = GET_SEL32V(_segMan, curObject, SELECTOR(brBottom));
+ curRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
+ curRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
+ curRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
+ curRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
// Check if curRect is within checkRect
// TODO: This check is slightly odd, because it means that a rect is not contained
// in itself. It may very well be that the original SCI engine did it just
@@ -115,29 +115,29 @@ uint16 GfxCompare::kernelOnControl(byte screenMask, const Common::Rect &rect) {
void GfxCompare::kernelSetNowSeen(reg_t objectReference) {
GfxView *view = NULL;
Common::Rect celRect(0, 0);
- GuiResourceId viewId = (GuiResourceId)GET_SEL32V(_segMan, objectReference, SELECTOR(view));
+ GuiResourceId viewId = (GuiResourceId)readSelectorValue(_segMan, objectReference, SELECTOR(view));
// HACK: Ignore invalid views for now (perhaps unimplemented text views?)
if (viewId == 0xFFFF) // invalid view
return;
- int16 loopNo = GET_SEL32V(_segMan, objectReference, SELECTOR(loop));
- int16 celNo = GET_SEL32V(_segMan, objectReference, SELECTOR(cel));
- int16 x = (int16)GET_SEL32V(_segMan, objectReference, SELECTOR(x));
- int16 y = (int16)GET_SEL32V(_segMan, objectReference, SELECTOR(y));
+ int16 loopNo = readSelectorValue(_segMan, objectReference, SELECTOR(loop));
+ int16 celNo = readSelectorValue(_segMan, objectReference, SELECTOR(cel));
+ int16 x = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(x));
+ int16 y = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(y));
int16 z = 0;
if (_kernel->_selectorCache.z > -1)
- z = (int16)GET_SEL32V(_segMan, objectReference, SELECTOR(z));
+ z = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(z));
// now get cel rectangle
view = _cache->getView(viewId);
view->getCelRect(loopNo, celNo, x, y, z, &celRect);
- if (lookup_selector(_segMan, objectReference, _kernel->_selectorCache.nsTop, NULL, NULL) == kSelectorVariable) {
- PUT_SEL32V(_segMan, objectReference, SELECTOR(nsLeft), celRect.left);
- PUT_SEL32V(_segMan, objectReference, SELECTOR(nsRight), celRect.right);
- PUT_SEL32V(_segMan, objectReference, SELECTOR(nsTop), celRect.top);
- PUT_SEL32V(_segMan, objectReference, SELECTOR(nsBottom), celRect.bottom);
+ if (lookupSelector(_segMan, objectReference, _kernel->_selectorCache.nsTop, NULL, NULL) == kSelectorVariable) {
+ writeSelectorValue(_segMan, objectReference, SELECTOR(nsLeft), celRect.left);
+ writeSelectorValue(_segMan, objectReference, SELECTOR(nsRight), celRect.right);
+ writeSelectorValue(_segMan, objectReference, SELECTOR(nsTop), celRect.top);
+ writeSelectorValue(_segMan, objectReference, SELECTOR(nsBottom), celRect.bottom);
}
}
@@ -147,10 +147,10 @@ bool GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) {
uint16 signal, controlMask;
bool result;
- checkRect.left = GET_SEL32V(_segMan, curObject, SELECTOR(brLeft));
- checkRect.top = GET_SEL32V(_segMan, curObject, SELECTOR(brTop));
- checkRect.right = GET_SEL32V(_segMan, curObject, SELECTOR(brRight));
- checkRect.bottom = GET_SEL32V(_segMan, curObject, SELECTOR(brBottom));
+ checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
+ checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
+ checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
+ checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
if (!checkRect.isValidRect()) { // can occur in Iceman - HACK? TODO: is this really occuring in sierra sci? check this
warning("kCan(t)BeHere - invalid rect %d, %d -> %d, %d", checkRect.left, checkRect.top, checkRect.right, checkRect.bottom);
@@ -159,8 +159,8 @@ bool GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) {
adjustedRect = _coordAdjuster->onControl(checkRect);
- signal = GET_SEL32V(_segMan, curObject, SELECTOR(signal));
- controlMask = GET_SEL32V(_segMan, curObject, SELECTOR(illegalBits));
+ signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
+ controlMask = readSelectorValue(_segMan, curObject, SELECTOR(illegalBits));
result = (isOnControl(GFX_SCREEN_MASK_CONTROL, adjustedRect) & controlMask) ? false : true;
if ((result) && (signal & (kSignalIgnoreActor | kSignalRemoveView)) == 0) {
List *list = _segMan->lookupList(listReference);
@@ -183,14 +183,14 @@ bool GfxCompare::kernelIsItSkip(GuiResourceId viewId, int16 loopNo, int16 celNo,
}
void GfxCompare::kernelBaseSetter(reg_t object) {
- if (lookup_selector(_segMan, object, _kernel->_selectorCache.brLeft, NULL, NULL) == kSelectorVariable) {
- int16 x = GET_SEL32V(_segMan, object, SELECTOR(x));
- int16 y = GET_SEL32V(_segMan, object, SELECTOR(y));
- int16 z = (_kernel->_selectorCache.z > -1) ? GET_SEL32V(_segMan, object, SELECTOR(z)) : 0;
- int16 yStep = GET_SEL32V(_segMan, object, SELECTOR(yStep));
- GuiResourceId viewId = GET_SEL32V(_segMan, object, SELECTOR(view));
- int16 loopNo = GET_SEL32V(_segMan, object, SELECTOR(loop));
- int16 celNo = GET_SEL32V(_segMan, object, SELECTOR(cel));
+ if (lookupSelector(_segMan, object, _kernel->_selectorCache.brLeft, NULL, NULL) == kSelectorVariable) {
+ int16 x = readSelectorValue(_segMan, object, SELECTOR(x));
+ int16 y = readSelectorValue(_segMan, object, SELECTOR(y));
+ int16 z = (_kernel->_selectorCache.z > -1) ? readSelectorValue(_segMan, object, SELECTOR(z)) : 0;
+ int16 yStep = readSelectorValue(_segMan, object, SELECTOR(yStep));
+ GuiResourceId viewId = readSelectorValue(_segMan, object, SELECTOR(view));
+ int16 loopNo = readSelectorValue(_segMan, object, SELECTOR(loop));
+ int16 celNo = readSelectorValue(_segMan, object, SELECTOR(cel));
// HACK: Ignore invalid views for now (perhaps unimplemented text views?)
if (viewId == 0xFFFF) // invalid view
@@ -203,10 +203,10 @@ void GfxCompare::kernelBaseSetter(reg_t object) {
celRect.bottom = y + 1;
celRect.top = celRect.bottom - yStep;
- PUT_SEL32V(_segMan, object, SELECTOR(brLeft), celRect.left);
- PUT_SEL32V(_segMan, object, SELECTOR(brRight), celRect.right);
- PUT_SEL32V(_segMan, object, SELECTOR(brTop), celRect.top);
- PUT_SEL32V(_segMan, object, SELECTOR(brBottom), celRect.bottom);
+ writeSelectorValue(_segMan, object, SELECTOR(brLeft), celRect.left);
+ writeSelectorValue(_segMan, object, SELECTOR(brRight), celRect.right);
+ writeSelectorValue(_segMan, object, SELECTOR(brTop), celRect.top);
+ writeSelectorValue(_segMan, object, SELECTOR(brBottom), celRect.bottom);
}
}
diff --git a/engines/sci/graphics/controls.cpp b/engines/sci/graphics/controls.cpp
index f744d6e7f1..26af9741c2 100644
--- a/engines/sci/graphics/controls.cpp
+++ b/engines/sci/graphics/controls.cpp
@@ -143,9 +143,9 @@ void GfxControls::texteditSetBlinkTime() {
}
void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
- uint16 cursorPos = GET_SEL32V(_segMan, controlObject, SELECTOR(cursor));
- uint16 maxChars = GET_SEL32V(_segMan, controlObject, SELECTOR(max));
- reg_t textReference = GET_SEL32(_segMan, controlObject, SELECTOR(text));
+ uint16 cursorPos = readSelectorValue(_segMan, controlObject, SELECTOR(cursor));
+ uint16 maxChars = readSelectorValue(_segMan, controlObject, SELECTOR(max));
+ reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text));
Common::String text;
uint16 textSize, eventType, eventKey = 0;
bool textChanged = false;
@@ -158,14 +158,14 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
if (!eventObject.isNull()) {
textSize = text.size();
- eventType = GET_SEL32V(_segMan, eventObject, SELECTOR(type));
+ eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type));
switch (eventType) {
case SCI_EVENT_MOUSE_PRESS:
// TODO: Implement mouse support for cursor change
break;
case SCI_EVENT_KEYBOARD:
- eventKey = GET_SEL32V(_segMan, eventObject, SELECTOR(message));
+ eventKey = readSelectorValue(_segMan, eventObject, SELECTOR(message));
switch (eventKey) {
case SCI_KEY_BACKSPACE:
if (cursorPos > 0) {
@@ -207,9 +207,9 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
if (textChanged) {
GuiResourceId oldFontId = _text16->GetFontId();
- GuiResourceId fontId = GET_SEL32V(_segMan, controlObject, SELECTOR(font));
- rect = Common::Rect(GET_SEL32V(_segMan, controlObject, SELECTOR(nsLeft)), GET_SEL32V(_segMan, controlObject, SELECTOR(nsTop)),
- GET_SEL32V(_segMan, controlObject, SELECTOR(nsRight)), GET_SEL32V(_segMan, controlObject, SELECTOR(nsBottom)));
+ GuiResourceId fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font));
+ rect = Common::Rect(readSelectorValue(_segMan, controlObject, SELECTOR(nsLeft)), readSelectorValue(_segMan, controlObject, SELECTOR(nsTop)),
+ readSelectorValue(_segMan, controlObject, SELECTOR(nsRight)), readSelectorValue(_segMan, controlObject, SELECTOR(nsBottom)));
_text16->SetFont(fontId);
if (textAddChar) {
// We check, if we are really able to add the new char
@@ -241,7 +241,7 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
}
}
- PUT_SEL32V(_segMan, controlObject, SELECTOR(cursor), cursorPos);
+ writeSelectorValue(_segMan, controlObject, SELECTOR(cursor), cursorPos);
}
int GfxControls::getPicNotValid() {
diff --git a/engines/sci/graphics/coordadjuster.cpp b/engines/sci/graphics/coordadjuster.cpp
index 40ef655be7..422df52f27 100644
--- a/engines/sci/graphics/coordadjuster.cpp
+++ b/engines/sci/graphics/coordadjuster.cpp
@@ -93,18 +93,18 @@ GfxCoordAdjuster32::~GfxCoordAdjuster32() {
}
void GfxCoordAdjuster32::kernelGlobalToLocal(int16 &x, int16 &y, reg_t planeObject) {
- //int16 resY = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resY));
- //int16 resX = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resX));
+ //int16 resY = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resY));
+ //int16 resX = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resX));
//*x = ( *x * _screen->getWidth()) / resX;
//*y = ( *y * _screen->getHeight()) / resY;
- x -= GET_SEL32V(_segMan, planeObject, SELECTOR(left));
- y -= GET_SEL32V(_segMan, planeObject, SELECTOR(top));
+ x -= readSelectorValue(_segMan, planeObject, SELECTOR(left));
+ y -= readSelectorValue(_segMan, planeObject, SELECTOR(top));
}
void GfxCoordAdjuster32::kernelLocalToGlobal(int16 &x, int16 &y, reg_t planeObject) {
- //int16 resY = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resY));
- //int16 resX = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resX));
- x += GET_SEL32V(_segMan, planeObject, SELECTOR(left));
- y += GET_SEL32V(_segMan, planeObject, SELECTOR(top));
+ //int16 resY = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resY));
+ //int16 resX = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resX));
+ x += readSelectorValue(_segMan, planeObject, SELECTOR(left));
+ y += readSelectorValue(_segMan, planeObject, SELECTOR(top));
//*x = ( *x * resX) / _screen->getWidth();
//*y = ( *y * resY) / _screen->getHeight();
}
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 78253bd913..3cc5ca5447 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -54,7 +54,7 @@ GfxFrameout::~GfxFrameout() {
void GfxFrameout::kernelAddPlane(reg_t object) {
_planes.push_back(object);
- int16 planePri = GET_SEL32V(_segMan, object, SELECTOR(priority)) & 0xFFFF;
+ int16 planePri = readSelectorValue(_segMan, object, SELECTOR(priority)) & 0xFFFF;
if (planePri > _highPlanePri)
_highPlanePri = planePri;
}
@@ -74,7 +74,7 @@ void GfxFrameout::kernelDeletePlane(reg_t object) {
_highPlanePri = 0;
for (uint32 planeNr = 0; planeNr < _planes.size(); planeNr++) {
- int16 planePri = GET_SEL32V(_segMan, _planes[planeNr], SELECTOR(priority)) & 0xFFFF;
+ int16 planePri = readSelectorValue(_segMan, _planes[planeNr], SELECTOR(priority)) & 0xFFFF;
if (planePri > _highPlanePri)
_highPlanePri = planePri;
}
@@ -126,29 +126,29 @@ void GfxFrameout::kernelFrameout() {
for (uint32 planeNr = 0; planeNr < _planes.size(); planeNr++) {
planeObject = _planes[planeNr];
- planePriority = GET_SEL32V(_segMan, planeObject, SELECTOR(priority));
+ planePriority = readSelectorValue(_segMan, planeObject, SELECTOR(priority));
if (planePriority == -1) // Plane currently not meant to be shown
continue;
- planeRect.top = GET_SEL32V(_segMan, planeObject, SELECTOR(top));
- planeRect.left = GET_SEL32V(_segMan, planeObject, SELECTOR(left));
- planeRect.bottom = GET_SEL32V(_segMan, planeObject, SELECTOR(bottom));
- planeRect.right = GET_SEL32V(_segMan, planeObject, SELECTOR(right));
- planeResY = GET_SEL32V(_segMan, planeObject, SELECTOR(resY));
- planeResX = GET_SEL32V(_segMan, planeObject, SELECTOR(resX));
+ planeRect.top = readSelectorValue(_segMan, planeObject, SELECTOR(top));
+ planeRect.left = readSelectorValue(_segMan, planeObject, SELECTOR(left));
+ planeRect.bottom = readSelectorValue(_segMan, planeObject, SELECTOR(bottom));
+ planeRect.right = readSelectorValue(_segMan, planeObject, SELECTOR(right));
+ planeResY = readSelectorValue(_segMan, planeObject, SELECTOR(resY));
+ planeResX = readSelectorValue(_segMan, planeObject, SELECTOR(resX));
planeRect.top = (planeRect.top * _screen->getHeight()) / planeResY;
planeRect.left = (planeRect.left * _screen->getWidth()) / planeResX;
planeRect.bottom = (planeRect.bottom * _screen->getHeight()) / planeResY;
planeRect.right = (planeRect.right * _screen->getWidth()) / planeResX;
- planeBack = GET_SEL32V(_segMan, planeObject, SELECTOR(back));
+ planeBack = readSelectorValue(_segMan, planeObject, SELECTOR(back));
if (planeBack) {
_paint32->fillRect(planeRect, planeBack);
}
- planePictureNr = GET_SEL32V(_segMan, planeObject, SELECTOR(picture));
+ planePictureNr = readSelectorValue(_segMan, planeObject, SELECTOR(picture));
if ((planePictureNr != 0xFFFF) && (planePictureNr != 0xFFFE)) {
planePicture = new GfxPicture(_resMan, _coordAdjuster, 0, _screen, _palette, planePictureNr, false);
planePictureCels = planePicture->getSci32celCount();
@@ -161,19 +161,19 @@ void GfxFrameout::kernelFrameout() {
itemEntry = itemData;
for (uint32 itemNr = 0; itemNr < _screenItems.size(); itemNr++) {
itemObject = _screenItems[itemNr];
- itemPlane = GET_SEL32(_segMan, itemObject, SELECTOR(plane));
+ itemPlane = readSelector(_segMan, itemObject, SELECTOR(plane));
if (planeObject == itemPlane) {
// Found an item on current plane
- itemEntry->viewId = GET_SEL32V(_segMan, itemObject, SELECTOR(view));
- itemEntry->loopNo = GET_SEL32V(_segMan, itemObject, SELECTOR(loop));
- itemEntry->celNo = GET_SEL32V(_segMan, itemObject, SELECTOR(cel));
- itemEntry->x = GET_SEL32V(_segMan, itemObject, SELECTOR(x));
- itemEntry->y = GET_SEL32V(_segMan, itemObject, SELECTOR(y));
- itemEntry->z = GET_SEL32V(_segMan, itemObject, SELECTOR(z));
- itemEntry->priority = GET_SEL32V(_segMan, itemObject, SELECTOR(priority));
- itemEntry->signal = GET_SEL32V(_segMan, itemObject, SELECTOR(signal));
- itemEntry->scaleX = GET_SEL32V(_segMan, itemObject, SELECTOR(scaleX));
- itemEntry->scaleY = GET_SEL32V(_segMan, itemObject, SELECTOR(scaleY));
+ itemEntry->viewId = readSelectorValue(_segMan, itemObject, SELECTOR(view));
+ itemEntry->loopNo = readSelectorValue(_segMan, itemObject, SELECTOR(loop));
+ itemEntry->celNo = readSelectorValue(_segMan, itemObject, SELECTOR(cel));
+ itemEntry->x = readSelectorValue(_segMan, itemObject, SELECTOR(x));
+ itemEntry->y = readSelectorValue(_segMan, itemObject, SELECTOR(y));
+ itemEntry->z = readSelectorValue(_segMan, itemObject, SELECTOR(z));
+ itemEntry->priority = readSelectorValue(_segMan, itemObject, SELECTOR(priority));
+ itemEntry->signal = readSelectorValue(_segMan, itemObject, SELECTOR(signal));
+ itemEntry->scaleX = readSelectorValue(_segMan, itemObject, SELECTOR(scaleX));
+ itemEntry->scaleY = readSelectorValue(_segMan, itemObject, SELECTOR(scaleY));
itemEntry->object = itemObject;
itemEntry->y = ((itemEntry->y * _screen->getHeight()) / planeResY);
@@ -240,12 +240,12 @@ void GfxFrameout::kernelFrameout() {
// This doesn't work for SCI2.1 games...
if (getSciVersion() == SCI_VERSION_2) {
Kernel *kernel = g_sci->getKernel();
- if (lookup_selector(_segMan, itemEntry->object, kernel->_selectorCache.text, NULL, NULL) == kSelectorVariable) {
- Common::String text = _segMan->getString(GET_SEL32(_segMan, itemEntry->object, SELECTOR(text)));
- int16 fontRes = GET_SEL32V(_segMan, itemEntry->object, SELECTOR(font));
+ if (lookupSelector(_segMan, itemEntry->object, kernel->_selectorCache.text, NULL, NULL) == kSelectorVariable) {
+ Common::String text = _segMan->getString(readSelector(_segMan, itemEntry->object, SELECTOR(text)));
+ int16 fontRes = readSelectorValue(_segMan, itemEntry->object, SELECTOR(font));
GfxFont *font = new GfxFontFromResource(_resMan, _screen, fontRes);
- bool dimmed = GET_SEL32V(_segMan, itemEntry->object, SELECTOR(dimmed));
- uint16 foreColor = GET_SEL32V(_segMan, itemEntry->object, SELECTOR(fore));
+ bool dimmed = readSelectorValue(_segMan, itemEntry->object, SELECTOR(dimmed));
+ uint16 foreColor = readSelectorValue(_segMan, itemEntry->object, SELECTOR(fore));
uint16 curX = itemEntry->x;
uint16 curY = itemEntry->y;
for (uint32 i = 0; i < text.size(); i++) {
diff --git a/engines/sci/graphics/gui.cpp b/engines/sci/graphics/gui.cpp
index 46f7fcd689..e427edd732 100644
--- a/engines/sci/graphics/gui.cpp
+++ b/engines/sci/graphics/gui.cpp
@@ -92,7 +92,7 @@ void SciGui::resetEngineState(EngineState *s) {
}
void SciGui::init(bool usesOldGfxFunctions) {
- _ports->init(usesOldGfxFunctions, this, _paint16, _text16, _s->_gameId);
+ _ports->init(usesOldGfxFunctions, this, _paint16, _text16);
_paint16->init(_animate, _text16);
}
@@ -136,9 +136,4 @@ void SciGui::portraitShow(Common::String resourceName, Common::Point position, u
void SciGui::portraitUnload(uint16 portraitId) {
}
-bool SciGui::debugEGAdrawingVisualize(bool state) {
- _paint16->setEGAdrawingVisualize(state);
- return false;
-}
-
} // End of namespace Sci
diff --git a/engines/sci/graphics/gui.h b/engines/sci/graphics/gui.h
index 732e195026..7663036117 100644
--- a/engines/sci/graphics/gui.h
+++ b/engines/sci/graphics/gui.h
@@ -61,8 +61,6 @@ public:
virtual void portraitShow(Common::String resourceName, Common::Point position, uint16 resourceNum, uint16 noun, uint16 verb, uint16 cond, uint16 seq);
virtual void portraitUnload(uint16 portraitId);
- virtual bool debugEGAdrawingVisualize(bool state);
-
// FIXME: Don't store EngineState
virtual void resetEngineState(EngineState *s);
diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp
new file mode 100644
index 0000000000..a06e98ccbf
--- /dev/null
+++ b/engines/sci/graphics/maciconbar.cpp
@@ -0,0 +1,91 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "sci/sci.h"
+#include "sci/engine/selector.h"
+#include "sci/engine/state.h"
+#include "sci/graphics/maciconbar.h"
+#include "sci/graphics/palette.h"
+
+#include "common/stream.h"
+#include "common/system.h"
+#include "graphics/pict.h"
+#include "graphics/surface.h"
+
+namespace Sci {
+
+void GfxMacIconBar::addIcon(reg_t obj) {
+ _iconBarObjects.push_back(obj);
+}
+
+void GfxMacIconBar::drawIcons() {
+ // Draw the icons to the bottom of the screen
+
+ byte *pal = new byte[256 * 4];
+ Graphics::PictDecoder *pict = new Graphics::PictDecoder(Graphics::PixelFormat::createFormatCLUT8());
+ uint32 lastX = 0;
+
+ for (uint32 i = 0; i < _iconBarObjects.size(); i++) {
+ uint32 iconIndex = readSelectorValue(g_sci->getEngineState()->_segMan, _iconBarObjects[i], SELECTOR(iconIndex));
+ Resource *res = g_sci->getResMan()->findResource(ResourceId(kResourceTypeMacIconBarPictN, iconIndex + 1), false);
+ if (!res)
+ continue;
+
+ Common::MemoryReadStream *stream = new Common::MemoryReadStream(res->data, res->size);
+ Graphics::Surface *surf = pict->decodeImage(stream, pal);
+ remapColors(surf, pal);
+
+ g_system->copyRectToScreen((byte *)surf->pixels, surf->pitch, lastX, 200, MIN<uint32>(surf->w, 320 - lastX), surf->h);
+
+ lastX += surf->w;
+ surf->free();
+ delete surf;
+ delete stream;
+ }
+
+ delete pict;
+ delete[] pal;
+}
+
+void GfxMacIconBar::remapColors(Graphics::Surface *surf, byte *palette) {
+ byte *pixels = (byte *)surf->pixels;
+
+ // Remap to the screen palette
+ for (uint16 i = 0; i < surf->w * surf->h; i++) {
+ byte color = *pixels;
+
+ byte r = palette[color * 4];
+ byte g = palette[color * 4 + 1];
+ byte b = palette[color * 4 + 2];
+
+ // For black, make sure the index is 0
+ if (r == 0 && g == 0 && b == 0)
+ *pixels++ = 0;
+ else
+ *pixels++ = g_sci->_gfxPalette->kernelFindColor(r, g, b);
+ }
+}
+
+} // End of namespace Sci
diff --git a/engines/mohawk/video/rpza.h b/engines/sci/graphics/maciconbar.h
index c6d0ada6f5..71e65fcb40 100644
--- a/engines/mohawk/video/rpza.h
+++ b/engines/sci/graphics/maciconbar.h
@@ -23,27 +23,33 @@
*
*/
-#ifndef MOHAWK_RPZA_H
-#define MOHAWK_RPZA_H
+#ifndef SCI_GRAPHICS_MACICONBAR_H
+#define SCI_GRAPHICS_MACICONBAR_H
-#include "graphics/pixelformat.h"
-#include "graphics/video/codecs/codec.h"
+#include "common/array.h"
-namespace Mohawk {
+#include "sci/engine/vm.h"
-class RPZADecoder : public Graphics::Codec {
+namespace Graphics {
+ struct Surface;
+}
+
+namespace Sci {
+
+class GfxMacIconBar {
public:
- RPZADecoder(uint16 width, uint16 height);
- ~RPZADecoder() { delete _surface; }
+ GfxMacIconBar() {}
+ ~GfxMacIconBar() {}
- Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
- Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
+ void addIcon(reg_t obj);
+ void drawIcons();
private:
- Graphics::Surface *_surface;
- Graphics::PixelFormat _pixelFormat;
+ Common::Array<reg_t> _iconBarObjects;
+
+ void remapColors(Graphics::Surface *surf, byte *palette);
};
-} // End of namespace Mohawk
+} // End of namespace Sci
#endif
diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp
index 5e3b419fe3..880e1aba12 100644
--- a/engines/sci/graphics/menu.cpp
+++ b/engines/sci/graphics/menu.cpp
@@ -378,7 +378,7 @@ void GfxMenu::calculateMenuAndItemWidth() {
}
reg_t GfxMenu::kernelSelect(reg_t eventObject) {
- int16 eventType = GET_SEL32V(_segMan, eventObject, SELECTOR(type));
+ int16 eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type));
int16 keyPress, keyModifier;
Common::Point mousePosition;
GuiMenuItemList::iterator itemIterator = _itemList.begin();
@@ -390,8 +390,8 @@ reg_t GfxMenu::kernelSelect(reg_t eventObject) {
switch (eventType) {
case SCI_EVENT_KEYBOARD:
- keyPress = GET_SEL32V(_segMan, eventObject, SELECTOR(message));
- keyModifier = GET_SEL32V(_segMan, eventObject, SELECTOR(modifiers));
+ keyPress = readSelectorValue(_segMan, eventObject, SELECTOR(message));
+ keyModifier = readSelectorValue(_segMan, eventObject, SELECTOR(modifiers));
// If tab got pressed, handle it here as if it was Ctrl-I - at least sci0 also did it that way
if (keyPress == SCI_KEY_TAB) {
keyModifier = SCI_KEYMOD_CTRL;
@@ -465,7 +465,7 @@ reg_t GfxMenu::kernelSelect(reg_t eventObject) {
_ports->setPort(_oldPort);
if ((itemEntry) || (forceClaimed))
- PUT_SEL32(_segMan, eventObject, SELECTOR(claimed), make_reg(0, 1));
+ writeSelector(_segMan, eventObject, SELECTOR(claimed), make_reg(0, 1));
if (itemEntry)
return make_reg(0, (itemEntry->menuId << 8) | (itemEntry->id));
return NULL_REG;
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index d0975f3d3d..ff4f3bec52 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -61,7 +61,7 @@ void GfxPaint16::init(GfxAnimate *animate, GfxText16 *text16) {
_EGAdrawingVisualize = false;
}
-void GfxPaint16::setEGAdrawingVisualize(bool state) {
+void GfxPaint16::debugSetEGAdrawingVisualize(bool state) {
_EGAdrawingVisualize = state;
}
@@ -354,7 +354,8 @@ void GfxPaint16::bitsRestore(reg_t memoryHandle) {
}
void GfxPaint16::bitsFree(reg_t memoryHandle) {
- _segMan->freeHunkEntry(memoryHandle);
+ if (!memoryHandle.isNull()) // happens in KQ5CD
+ _segMan->freeHunkEntry(memoryHandle);
}
void GfxPaint16::kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo) {
diff --git a/engines/sci/graphics/paint16.h b/engines/sci/graphics/paint16.h
index b18c879387..65f9dd0d9c 100644
--- a/engines/sci/graphics/paint16.h
+++ b/engines/sci/graphics/paint16.h
@@ -50,7 +50,7 @@ public:
void init(GfxAnimate *animate, GfxText16 *text16);
- void setEGAdrawingVisualize(bool state);
+ void debugSetEGAdrawingVisualize(bool state);
void drawPicture(GuiResourceId pictureId, int16 animationNr, bool mirroredFlag, bool addToFlag, GuiResourceId paletteId);
void drawCelAndShow(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo, uint16 scaleX = 128, uint16 scaleY = 128);
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 96bdb42007..3c4cf7e964 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -30,8 +30,9 @@
#include "sci/sci.h"
#include "sci/engine/state.h"
-#include "sci/graphics/screen.h"
+#include "sci/graphics/maciconbar.h"
#include "sci/graphics/palette.h"
+#include "sci/graphics/screen.h"
namespace Sci {
@@ -55,6 +56,7 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen, bool autoSetP
_sysPalette.colors[255].g = 255;
_sysPalette.colors[255].b = 255;
+ _sysPaletteChanged = false;
if (autoSetPalette) {
if (_resMan->getViewType() == kViewEga)
setEGA();
@@ -63,7 +65,6 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen, bool autoSetP
else
kernelSetFromResource(999, true);
}
- _sysPaletteChanged = false;
}
GfxPalette::~GfxPalette() {
@@ -311,6 +312,10 @@ void GfxPalette::setOnScreen() {
if (_resMan->isAmiga32color())
return;
_screen->setPalette(&_sysPalette);
+
+ // Redraw the Mac SCI1.1 Icon bar every palette change
+ if (g_sci->_gfxMacIconBar)
+ g_sci->_gfxMacIconBar->drawIcons();
}
bool GfxPalette::kernelSetFromResource(GuiResourceId resourceId, bool force) {
diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp
index 74f651a88a..a59153f116 100644
--- a/engines/sci/graphics/picture.cpp
+++ b/engines/sci/graphics/picture.cpp
@@ -69,15 +69,20 @@ void GfxPicture::draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int1
headerSize = READ_LE_UINT16(_resource->data);
switch (headerSize) {
case 0x26: // SCI 1.1 VGA picture
+ _resourceType = SCI_PICTURE_TYPE_SCI11;
+ if (_addToFlag)
+ _priority = 15;
drawSci11Vga();
break;
#ifdef ENABLE_SCI32
case 0x0e: // SCI32 VGA picture
+ _resourceType = SCI_PICTURE_TYPE_SCI32;
drawSci32Vga();
break;
#endif
default:
// VGA, EGA or Amiga vector data
+ _resourceType = SCI_PICTURE_TYPE_REGULAR;
drawVectorData(_resource->data, _resource->size);
}
}
@@ -108,9 +113,8 @@ void GfxPicture::drawSci11Vga() {
_palette->set(&palette, true);
// display Cel-data
- if (has_cel) {
- drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, false);
- }
+ if (has_cel)
+ drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0);
// process vector data
drawVectorData(inbuffer + vector_dataPos, vector_size);
@@ -139,6 +143,7 @@ void GfxPicture::drawSci32Vga(int16 celNo) {
// HACK
_mirroredFlag = false;
_addToFlag = false;
+ _resourceType = SCI_PICTURE_TYPE_SCI32;
if ((celNo == -1) || (celNo == 0)) {
// Create palette and set it
@@ -155,14 +160,14 @@ void GfxPicture::drawSci32Vga(int16 celNo) {
cel_LiteralPos = READ_LE_UINT32(inbuffer + cel_headerPos + 28);
cel_relXpos = READ_LE_UINT16(inbuffer + cel_headerPos + 38);
cel_relYpos = READ_LE_UINT16(inbuffer + cel_headerPos + 40);
- drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, cel_relXpos, cel_relYpos, true);
+ drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, cel_relXpos, cel_relYpos);
cel_headerPos += 42;
celCount--;
}
}
#endif
-void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY, bool hasSci32Header) {
+void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY) {
byte *celBitmap = NULL;
byte *ptr = NULL;
byte *headerPtr = inbuffer + headerPos;
@@ -179,11 +184,16 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
int pixelNr, pixelCount;
#ifdef ENABLE_SCI32
- if (!hasSci32Header) {
+ if (_resourceType != SCI_PICTURE_TYPE_SCI32) {
#endif
displaceX = (signed char)headerPtr[4];
displaceY = (unsigned char)headerPtr[5];
- clearColor = headerPtr[6];
+ if (_resourceType == SCI_PICTURE_TYPE_SCI11) {
+ // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise
+ clearColor = _screen->getColorWhite();
+ } else {
+ clearColor = headerPtr[6];
+ }
#ifdef ENABLE_SCI32
} else {
displaceX = READ_LE_UINT16(headerPtr + 4); // probably signed?!?
@@ -518,10 +528,29 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
break;
+ // Pattern opcodes are handled in sierra sci1.1+ as actual NOPs and normally they definitely should not occur
+ // inside picture data for such games
case PIC_OP_SET_PATTERN:
+ if (_resourceType >= SCI_PICTURE_TYPE_SCI11) {
+ if (strcmp(g_sci->getGameID(), "sq4") == 0) {
+ // WORKAROUND: For SQ4 / for some pictures handle this like a terminator
+ // This picture includes garbage data, first a set pattern w/o parameter and then short pattern
+ // I guess that garbage is a left over from the sq4-floppy (sci1) to sq4-cd (sci1.1) conversion
+ switch (_resourceId) {
+ case 381:
+ case 376:
+ return;
+ default:
+ break;
+ }
+ }
+ error("pic-operation set pattern inside sci1.1+ vector data");
+ }
pattern_Code = data[curPos++];
break;
case PIC_OP_SHORT_PATTERNS:
+ if (_resourceType >= SCI_PICTURE_TYPE_SCI11)
+ error("pic-operation short pattern inside sci1.1+ vector data");
vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture);
vectorGetAbsCoords(data, curPos, x, y);
vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture);
@@ -532,6 +561,8 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
break;
case PIC_OP_MEDIUM_PATTERNS:
+ if (_resourceType >= SCI_PICTURE_TYPE_SCI11)
+ error("pic-operation medium pattern inside sci1.1+ vector data");
vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture);
vectorGetAbsCoords(data, curPos, x, y);
vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture);
@@ -542,6 +573,8 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
break;
case PIC_OP_ABSOLUTE_PATTERN:
+ if (_resourceType >= SCI_PICTURE_TYPE_SCI11)
+ error("pic-operation absolute pattern inside sci1.1+ vector data");
while (vectorIsNonOpcode(data[curPos])) {
vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture);
vectorGetAbsCoords(data, curPos, x, y);
@@ -585,7 +618,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
vectorGetAbsCoordsNoMirror(data, curPos, x, y);
size = READ_LE_UINT16(data + curPos); curPos += 2;
_priority = pic_priority; // set global priority so the cel gets drawn using current priority as well
- drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, false);
+ drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y);
curPos += size;
break;
case PIC_OPX_EGA_SET_PRIORITY_TABLE:
@@ -627,7 +660,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
_priority = pic_priority; // set global priority so the cel gets drawn using current priority as well
if (pic_priority == 255)
_priority = 0; // if priority not set, use priority 0
- drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, false);
+ drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y);
curPos += size;
break;
case PIC_OPX_VGA_PRIORITY_TABLE_EQDIST:
diff --git a/engines/sci/graphics/picture.h b/engines/sci/graphics/picture.h
index 3374c33b52..5a86539b37 100644
--- a/engines/sci/graphics/picture.h
+++ b/engines/sci/graphics/picture.h
@@ -32,6 +32,12 @@ namespace Sci {
#define SCI_PATTERN_CODE_USE_TEXTURE 0x20
#define SCI_PATTERN_CODE_PENSIZE 0x07
+enum {
+ SCI_PICTURE_TYPE_REGULAR = 0,
+ SCI_PICTURE_TYPE_SCI11 = 1,
+ SCI_PICTURE_TYPE_SCI32 = 2
+};
+
class GfxPorts;
class GfxScreen;
class GfxPalette;
@@ -57,7 +63,7 @@ private:
void initData(GuiResourceId resourceId);
void reset();
void drawSci11Vga();
- void drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY, bool hasSci32Header);
+ void drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY);
void drawVectorData(byte *data, int size);
bool vectorIsNonOpcode(byte pixel);
void vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y);
@@ -80,6 +86,7 @@ private:
int16 _resourceId;
Resource *_resource;
+ int _resourceType;
int16 _animationNr;
bool _mirroredFlag;
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index ab3291dd79..cdb6fe4ae1 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -54,7 +54,7 @@ GfxPorts::~GfxPorts() {
delete _menuPort;
}
-void GfxPorts::init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16, Common::String gameId) {
+void GfxPorts::init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16) {
int16 offTop = 10;
_usesOldGfxFunctions = usesOldGfxFunctions;
@@ -88,6 +88,7 @@ void GfxPorts::init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16,
// Jones, Slater and Hoyle 3 were called with parameter -Nw 0 0 200 320.
// Mother Goose (SCI1) uses -Nw 0 0 159 262. The game will later use SetPort so we don't need to set the other fields.
// This actually meant not skipping the first 10 pixellines in windowMgrPort
+ Common::String gameId = g_sci->getGameID();
if (gameId == "jones" || gameId == "slater" || gameId == "hoyle3" || (gameId == "mothergoose" && getSciVersion() == SCI_VERSION_1_EARLY))
offTop = 0;
diff --git a/engines/sci/graphics/ports.h b/engines/sci/graphics/ports.h
index 0876d9e442..c8ce6b3470 100644
--- a/engines/sci/graphics/ports.h
+++ b/engines/sci/graphics/ports.h
@@ -45,7 +45,7 @@ public:
GfxPorts(SegManager *segMan, GfxScreen *screen);
~GfxPorts();
- void init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16, Common::String gameId);
+ void init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16);
void kernelSetActive(uint16 portId);
Common::Rect kernelGetPicWindow(int16 &picTop, int16 &picLeft);
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 7ca9e33509..0e054d5a76 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -93,7 +93,18 @@ GfxScreen::GfxScreen(ResourceManager *resMan, int16 width, int16 height, int ups
}
// Initialize the actual screen
- initGraphics(_displayWidth, _displayHeight, _displayWidth > 320);
+
+ if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1) {
+ // For SCI1.1 Mac, we need to expand the screen to accommodate for
+ // the icon bar. Of course, both KQ6 and QFG1 VGA differ in size.
+ if (!scumm_stricmp(g_sci->getGameID(), "kq6"))
+ initGraphics(_displayWidth, _displayHeight + 26, _displayWidth > 320);
+ else if (!scumm_stricmp(g_sci->getGameID(), "qfg1"))
+ initGraphics(_displayWidth, _displayHeight + 20, _displayWidth > 320);
+ else
+ error("Unknown SCI1.1 Mac game");
+ } else
+ initGraphics(_displayWidth, _displayHeight, _displayWidth > 320);
}
GfxScreen::~GfxScreen() {
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 8c4d666ba7..a2cfd38f95 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -6,6 +6,7 @@ MODULE_OBJS := \
detection.o \
event.o \
resource.o \
+ resource_audio.o \
sci.o \
util.o \
engine/features.o \
@@ -44,6 +45,7 @@ MODULE_OBJS := \
graphics/font.o \
graphics/fontsjis.o \
graphics/gui.o \
+ graphics/maciconbar.o \
graphics/menu.o \
graphics/paint.o \
graphics/paint16.o \
diff --git a/engines/sci/parser/grammar.cpp b/engines/sci/parser/grammar.cpp
index 1cfe84076f..070e6767cf 100644
--- a/engines/sci/parser/grammar.cpp
+++ b/engines/sci/parser/grammar.cpp
@@ -258,6 +258,11 @@ void Vocabulary::freeRuleList(ParseRuleList *list) {
static ParseRuleList *_vocab_add_rule(ParseRuleList *list, ParseRule *rule) {
if (!rule)
return list;
+ if (!rule->_data.size()) {
+ // Special case for qfg2 demo
+ warning("no rule contents on _vocab_add_rule()");
+ return list;
+ }
ParseRuleList *new_elem = new ParseRuleList(rule);
diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp
index 5cd1310ad3..f49704372a 100644
--- a/engines/sci/parser/said.cpp
+++ b/engines/sci/parser/said.cpp
@@ -2443,13 +2443,14 @@ static int augment_parse_nodes(parse_tree_node_t *parset, parse_tree_node_t *sai
int said(EngineState *s, byte *spec, bool verbose) {
int retval;
+ Vocabulary *voc = g_sci->getVocabulary();
- parse_tree_node_t *parse_tree_ptr = s->_voc->_parserNodes;
+ parse_tree_node_t *parse_tree_ptr = voc->_parserNodes;
- if (s->_voc->parserIsValid) {
+ if (voc->parserIsValid) {
if (said_parse_spec(spec)) {
printf("Offending spec was: ");
- s->_voc->decipherSaidBlock(spec);
+ voc->decipherSaidBlock(spec);
return SAID_NO_MATCH;
}
diff --git a/engines/sci/parser/said.y b/engines/sci/parser/said.y
index 27486c5794..cbb2ff3e62 100644
--- a/engines/sci/parser/said.y
+++ b/engines/sci/parser/said.y
@@ -799,13 +799,14 @@ static int augment_parse_nodes(parse_tree_node_t *parset, parse_tree_node_t *sai
int said(EngineState *s, byte *spec, bool verbose) {
int retval;
+ Vocabulary *voc = g_sci->getVocabulary();
- parse_tree_node_t *parse_tree_ptr = s->_voc->_parserNodes;
+ parse_tree_node_t *parse_tree_ptr = voc->_parserNodes;
- if (s->_voc->parserIsValid) {
+ if (voc->parserIsValid) {
if (said_parse_spec(spec)) {
printf("Offending spec was: ");
- s->_voc->decipherSaidBlock(spec);
+ voc->decipherSaidBlock(spec);
return SAID_NO_MATCH;
}
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 4888dbd4cb..4818428663 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -26,7 +26,6 @@
// Resource library
#include "common/file.h"
-#include "common/macresman.h"
#include "sci/resource.h"
#include "sci/util.h"
@@ -45,18 +44,6 @@ struct resource_index_t {
uint16 wSize;
};
-struct ResourceSource {
- ResSourceType source_type;
- bool scanned;
- Common::String location_name; // FIXME: Replace by FSNode ?
- const Common::FSNode *resourceFile;
- int volume_number;
- ResourceSource *associated_map;
- uint32 audioCompressionType;
- int32 *audioCompressionOffsetMapping;
- Common::MacResManager macResMan;
-};
-
//////////////////////////////////////////////////////////////////////
static SciVersion s_sciVersion = SCI_VERSION_NONE; // FIXME: Move this inside a suitable class, e.g. SciEngine
@@ -196,7 +183,7 @@ ResourceSource *ResourceManager::addExternalMap(const char *file_name, int volum
return newsrc;
}
-ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile) {
+ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile, int volume_nr) {
ResourceSource *newsrc = new ResourceSource();
newsrc->source_type = kSourceExtMap;
@@ -204,7 +191,7 @@ ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile) {
newsrc->resourceFile = mapFile;
newsrc->scanned = false;
newsrc->associated_map = NULL;
- newsrc->volume_number = 0;
+ newsrc->volume_number = volume_nr;
_sources.push_back(newsrc);
return newsrc;
@@ -250,6 +237,7 @@ ResourceSource *ResourceManager::addPatchDir(const char *dirname) {
ResourceSource *newsrc = new ResourceSource();
newsrc->source_type = kSourceDirectory;
+ newsrc->resourceFile = 0;
newsrc->scanned = false;
newsrc->location_name = dirname;
@@ -270,37 +258,7 @@ ResourceSource *ResourceManager::getVolume(ResourceSource *map, int volume_nr) {
// Resource manager constructors and operations
-void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) {
- Common::File *file = getVolumeFile(source->location_name.c_str());
- if (!file) {
- warning("Failed to open %s", source->location_name.c_str());
- return;
- }
- file->seek(0, SEEK_SET);
- uint32 compressionType = file->readUint32BE();
- switch (compressionType) {
- case MKID_BE('MP3 '):
- case MKID_BE('OGG '):
- case MKID_BE('FLAC'):
- // Detected a compressed audio volume
- source->audioCompressionType = compressionType;
- // Now read the whole offset mapping table for later usage
- int32 recordCount = file->readUint32LE();
- if (!recordCount)
- error("compressed audio volume doesn't contain any entries!");
- int32 *offsetMapping = new int32[(recordCount + 1) * 2];
- source->audioCompressionOffsetMapping = offsetMapping;
- for (int recordNo = 0; recordNo < recordCount; recordNo++) {
- *offsetMapping++ = file->readUint32LE();
- *offsetMapping++ = file->readUint32LE();
- }
- // Put ending zero
- *offsetMapping++ = 0;
- *offsetMapping++ = file->size();
- }
-}
-
-bool ResourceManager::loadPatch(Resource *res, Common::File &file) {
+bool ResourceManager::loadPatch(Resource *res, Common::SeekableReadStream *file) {
// We assume that the resource type matches res->type
// We also assume that the current file position is right at the actual data (behind resourceid/headersize byte)
@@ -315,12 +273,12 @@ bool ResourceManager::loadPatch(Resource *res, Common::File &file) {
unsigned int really_read;
if (res->_headerSize > 0) {
- really_read = file.read(res->_header, res->_headerSize);
+ really_read = file->read(res->_header, res->_headerSize);
if (really_read != res->_headerSize)
error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->_headerSize);
}
- really_read = file.read(res->data, res->size);
+ really_read = file->read(res->data, res->size);
if (really_read != res->size)
error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
@@ -338,77 +296,18 @@ bool ResourceManager::loadFromPatchFile(Resource *res) {
}
// Skip resourceid and header size byte
file.seek(2, SEEK_SET);
- return loadPatch(res, file);
-}
-
-bool ResourceManager::loadFromWaveFile(Resource *res, Common::File &file) {
- res->data = new byte[res->size];
-
- uint32 really_read = file.read(res->data, res->size);
- if (really_read != res->size)
- error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
-
- res->_status = kResStatusAllocated;
- return true;
-}
-
-bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::File &file) {
- // Check for WAVE files here
- uint32 riffTag = file.readUint32BE();
- if (riffTag == MKID_BE('RIFF')) {
- res->_headerSize = 0;
- res->size = file.readUint32LE();
- file.seek(-8, SEEK_CUR);
- return loadFromWaveFile(res, file);
- }
- file.seek(-4, SEEK_CUR);
-
- ResourceType type = (ResourceType)(file.readByte() & 0x7f);
- if (((res->_id.type == kResourceTypeAudio || res->_id.type == kResourceTypeAudio36) && (type != kResourceTypeAudio))
- || ((res->_id.type == kResourceTypeSync || res->_id.type == kResourceTypeSync36) && (type != kResourceTypeSync))) {
- warning("Resource type mismatch loading %s from %s", res->_id.toString().c_str(), file.getName());
- res->unalloc();
- return false;
- }
-
- res->_headerSize = file.readByte();
-
- if (type == kResourceTypeAudio) {
- if (res->_headerSize != 11 && res->_headerSize != 12) {
- warning("Unsupported audio header");
- res->unalloc();
- return false;
- }
-
- // Load sample size
- file.seek(7, SEEK_CUR);
- res->size = file.readUint32LE();
- // Adjust offset to point at the header data again
- file.seek(-11, SEEK_CUR);
- }
-
- return loadPatch(res, file);
-}
-
-bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::File &file) {
- res->data = new byte[res->size];
-
- if (res->data == NULL) {
- error("Can't allocate %d bytes needed for loading %s", res->size, res->_id.toString().c_str());
- }
-
- unsigned int really_read = file.read(res->data, res->size);
- if (really_read != res->size)
- warning("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
-
- res->_status = kResStatusAllocated;
- return true;
+ return loadPatch(res, &file);
}
-Common::File *ResourceManager::getVolumeFile(const char *filename) {
+Common::SeekableReadStream *ResourceManager::getVolumeFile(ResourceSource *source) {
Common::List<Common::File *>::iterator it = _volumeFiles.begin();
Common::File *file;
+ if (source->resourceFile)
+ return source->resourceFile->createReadStream();
+
+ const char *filename = source->location_name.c_str();
+
// check if file is already opened
while (it != _volumeFiles.end()) {
file = *it;
@@ -445,11 +344,10 @@ void ResourceManager::loadResource(Resource *res) {
return;
if (res->_source->source_type == kSourceMacResourceFork) {
- //error("ResourceManager::loadResource(): TODO: Mac resource fork ;)");
Common::SeekableReadStream *stream = res->_source->macResMan.getResource(resTypeToMacTag(res->_id.type), res->_id.number);
if (!stream)
- error("Could not get Mac resource fork resource");
+ error("Could not get Mac resource fork resource: %d %d", res->_id.type, res->_id.number);
int error = decompress(res, stream);
if (error) {
@@ -460,10 +358,9 @@ void ResourceManager::loadResource(Resource *res) {
return;
}
- Common::File *file;
- // Either loading from volume or patch loading failed
- file = getVolumeFile(res->_source->location_name.c_str());
- if (!file) {
+ Common::SeekableReadStream *fileStream = getVolumeFile(res->_source);
+
+ if (!fileStream) {
warning("Failed to open %s", res->_source->location_name.c_str());
res->unalloc();
return;
@@ -471,8 +368,10 @@ void ResourceManager::loadResource(Resource *res) {
switch(res->_source->source_type) {
case kSourceWave:
- file->seek(res->_fileOffset, SEEK_SET);
- loadFromWaveFile(res, *file);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
+ loadFromWaveFile(res, fileStream);
+ if (res->_source->resourceFile)
+ delete fileStream;
return;
case kSourceAudioVolume:
@@ -503,30 +402,39 @@ void ResourceManager::loadResource(Resource *res) {
if (!compressedOffset)
error("could not translate offset to compressed offset in audio volume");
- file->seek(compressedOffset, SEEK_SET);
+ fileStream->seek(compressedOffset, SEEK_SET);
switch (res->_id.type) {
case kResourceTypeAudio:
case kResourceTypeAudio36:
// Directly read the stream, compressed audio wont have resource type id and header size for SCI1.1
- loadFromAudioVolumeSCI1(res, *file);
+ loadFromAudioVolumeSCI1(res, fileStream);
+ if (res->_source->resourceFile)
+ delete fileStream;
return;
default:
break;
}
} else {
// original file, directly seek to given offset and get SCI1/SCI1.1 audio resource
- file->seek(res->_fileOffset, SEEK_SET);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
}
if (getSciVersion() < SCI_VERSION_1_1)
- loadFromAudioVolumeSCI1(res, *file);
+ loadFromAudioVolumeSCI1(res, fileStream);
else
- loadFromAudioVolumeSCI11(res, *file);
+ loadFromAudioVolumeSCI11(res, fileStream);
+
+ if (res->_source->resourceFile)
+ delete fileStream;
return;
default:
- file->seek(res->_fileOffset, SEEK_SET);
- int error = decompress(res, file);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
+ int error = decompress(res, fileStream);
+
+ if (res->_source->resourceFile)
+ delete fileStream;
+
if (error) {
warning("Error %d occured while reading %s from resource file: %s",
error, res->_id.toString().c_str(), sci_error_types[error]);
@@ -539,27 +447,14 @@ Resource *ResourceManager::testResource(ResourceId id) {
return _resMap.getVal(id, NULL);
}
-int sci0_get_compression_method(Common::ReadStream &stream) {
- uint16 compressionMethod;
-
- stream.readUint16LE();
- stream.readUint16LE();
- stream.readUint16LE();
- compressionMethod = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- return compressionMethod;
-}
-
int ResourceManager::addAppropriateSources() {
Common::ArchiveMemberList files;
- if (Common::File::exists("RESOURCE.MAP")) {
+ if (Common::File::exists("resource.map")) {
// SCI0-SCI2 file naming scheme
- ResourceSource *map = addExternalMap("RESOURCE.MAP");
+ ResourceSource *map = addExternalMap("resource.map");
- SearchMan.listMatchingMembers(files, "RESOURCE.0??");
+ SearchMan.listMatchingMembers(files, "resource.0??");
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
const Common::String name = (*x)->getName();
@@ -570,12 +465,12 @@ int ResourceManager::addAppropriateSources() {
}
#ifdef ENABLE_SCI32
// GK1CD hires content
- if (Common::File::exists("ALT.MAP") && Common::File::exists("RESOURCE.ALT"))
- addSource(addExternalMap("ALT.MAP", 10), kSourceVolume, "RESOURCE.ALT", 10);
+ if (Common::File::exists("alt.map") && Common::File::exists("resource.alt"))
+ addSource(addExternalMap("alt.map", 10), kSourceVolume, "resource.alt", 10);
#endif
} else if (Common::File::exists("Data1")) {
// Mac SCI1.1+ file naming scheme
- SearchMan.listMatchingMembers(files, "Data?");
+ SearchMan.listMatchingMembers(files, "Data?*");
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
Common::String filename = (*x)->getName();
@@ -594,8 +489,8 @@ int ResourceManager::addAppropriateSources() {
} else {
// SCI2.1-SCI3 file naming scheme
Common::ArchiveMemberList mapFiles;
- SearchMan.listMatchingMembers(mapFiles, "RESMAP.0??");
- SearchMan.listMatchingMembers(files, "RESSCI.0??");
+ SearchMan.listMatchingMembers(mapFiles, "resmap.0??");
+ SearchMan.listMatchingMembers(files, "ressci.0??");
// We need to have the same number of maps as resource archives
if (mapFiles.empty() || files.empty() || mapFiles.size() != files.size())
@@ -617,9 +512,9 @@ int ResourceManager::addAppropriateSources() {
}
// SCI2.1 resource patches
- if (Common::File::exists("RESMAP.PAT") && Common::File::exists("RESSCI.PAT")) {
+ if (Common::File::exists("resmap.pat") && Common::File::exists("ressci.pat")) {
// We add this resource with a map which surely won't exist
- addSource(addExternalMap("RESMAP.PAT", 100), kSourceVolume, "RESSCI.PAT", 100);
+ addSource(addExternalMap("resmap.pat", 100), kSourceVolume, "ressci.pat", 100);
}
}
#else
@@ -628,14 +523,18 @@ int ResourceManager::addAppropriateSources() {
#endif
addPatchDir(".");
- if (Common::File::exists("MESSAGE.MAP"))
- addSource(addExternalMap("MESSAGE.MAP"), kSourceVolume, "RESOURCE.MSG", 0);
+ if (Common::File::exists("message.map"))
+ addSource(addExternalMap("message.map"), kSourceVolume, "resource.msg", 0);
return 1;
}
int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
ResourceSource *map = 0;
+#ifdef ENABLE_SCI32
+ ResourceSource *sci21PatchMap = 0;
+ const Common::FSNode *sci21PatchRes = 0;
+#endif
// First, find resource.map
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
@@ -645,17 +544,33 @@ int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
Common::String filename = file->getName();
filename.toLowercase();
- // TODO: Load the SCI2.1+ maps (resmap.*) in concurrence with the volumes to
- // get the proper volume numbers from the maps.
- if (filename.contains("resource.map") || filename.contains("resmap.000")) {
+ if (filename.contains("resource.map"))
map = addExternalMap(file);
- break;
+
+ if (filename.contains("resmap.0")) {
+ const char *dot = strrchr(file->getName().c_str(), '.');
+ int number = atoi(dot + 1);
+ map = addExternalMap(file, number);
}
+
+#ifdef ENABLE_SCI32
+ // SCI2.1 resource patches
+ if (filename.contains("resmap.pat"))
+ sci21PatchMap = addExternalMap(file, 100);
+
+ if (filename.contains("ressci.pat"))
+ sci21PatchRes = file;
+#endif
}
if (!map)
return 0;
+#ifdef ENABLE_SCI32
+ if (sci21PatchMap && sci21PatchRes)
+ addSource(sci21PatchMap, kSourceVolume, sci21PatchRes, 100);
+#endif
+
// Now find all the resource.0?? files
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (file->isDirectory())
@@ -696,36 +611,6 @@ int ResourceManager::addInternalSources() {
return 1;
}
-void ResourceManager::addNewGMPatch(const Common::String &gameId) {
- Common::String gmPatchFile;
-
- if (gameId == "ecoquest")
- gmPatchFile = "ECO1GM.PAT";
- else if (gameId == "hoyle3")
- gmPatchFile = "HOY3GM.PAT";
- else if (gameId == "hoyle3")
- gmPatchFile = "HOY3GM.PAT";
- else if (gameId == "lsl1sci")
- gmPatchFile = "LL1_GM.PAT";
- else if (gameId == "lsl5")
- gmPatchFile = "LL5_GM.PAT";
- else if (gameId == "longbow")
- gmPatchFile = "ROBNGM.PAT";
- else if (gameId == "sq1sci")
- gmPatchFile = "SQ1_GM.PAT";
- else if (gameId == "sq4")
- gmPatchFile = "SQ4_GM.PAT";
- else if (gameId == "fairytales")
- gmPatchFile = "TALEGM.PAT";
-
- if (!gmPatchFile.empty() && Common::File::exists(gmPatchFile)) {
- ResourceSource *psrcPatch = new ResourceSource;
- psrcPatch->source_type = kSourcePatch;
- psrcPatch->location_name = gmPatchFile;
- processPatch(psrcPatch, kResourceTypePatch, 4);
- }
-}
-
void ResourceManager::scanNewSources() {
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
ResourceSource *source = *it;
@@ -735,6 +620,9 @@ void ResourceManager::scanNewSources() {
switch (source->source_type) {
case kSourceDirectory:
readResourcePatches(source);
+#ifdef ENABLE_SCI32
+ readResourcePatchesBase36(source);
+#endif
readWaveAudioPatches();
break;
case kSourceExtMap:
@@ -990,7 +878,6 @@ const char *ResourceManager::versionDescription(ResVersion version) const {
ResourceManager::ResVersion ResourceManager::detectMapVersion() {
Common::SeekableReadStream *fileStream = 0;
- Common::File *file = 0;
byte buff[6];
ResourceSource *rsrc= 0;
@@ -1001,7 +888,7 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
if (rsrc->resourceFile) {
fileStream = rsrc->resourceFile->createReadStream();
} else {
- file = new Common::File();
+ Common::File *file = new Common::File();
file->open(rsrc->location_name);
if (file->isOpen())
fileStream = file;
@@ -1081,7 +968,6 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
ResourceManager::ResVersion ResourceManager::detectVolVersion() {
Common::SeekableReadStream *fileStream = 0;
- Common::File *file = 0;
ResourceSource *rsrc;
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
@@ -1091,7 +977,7 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
if (rsrc->resourceFile) {
fileStream = rsrc->resourceFile->createReadStream();
} else {
- file = new Common::File();
+ Common::File *file = new Common::File();
file->open(rsrc->location_name);
if (file->isOpen())
fileStream = file;
@@ -1180,27 +1066,36 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
}
// version-agnostic patch application
-void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, int resnumber) {
- Common::File file;
+void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, uint16 resnumber, uint32 tuple) {
+ Common::SeekableReadStream *fileStream = 0;
Resource *newrsc;
- ResourceId resId = ResourceId(restype, resnumber);
+ ResourceId resId = ResourceId(restype, resnumber, tuple);
byte patchtype, patch_data_offset;
int fsize;
- if (resnumber == -1)
- return;
- if (!file.open(source->location_name)) {
- warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str());
+ if (resnumber == 0xFFFF)
return;
+
+ if (source->resourceFile) {
+ fileStream = source->resourceFile->createReadStream();
+ } else {
+ Common::File *file = new Common::File();
+ if (!file->open(source->location_name)) {
+ warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str());
+ return;
+ }
+ fileStream = file;
}
- fsize = file.size();
+ fsize = fileStream->size();
if (fsize < 3) {
debug("Patching %s failed - file too small", source->location_name.c_str());
return;
}
- patchtype = file.readByte() & 0x7F;
- patch_data_offset = file.readByte();
+ patchtype = fileStream->readByte() & 0x7F;
+ patch_data_offset = fileStream->readByte();
+
+ delete fileStream;
if (patchtype != restype) {
debug("Patching %s failed - resource type mismatch", source->location_name.c_str());
@@ -1215,8 +1110,12 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype,
case 1:
patch_data_offset = 2;
break;
+ case 4:
+ patch_data_offset = 8;
+ break;
default:
- warning("Resource patch unsupported special case %X", patch_data_offset);
+ warning("Resource patch unsupported special case %X", patch_data_offset & 0x7F);
+ return;
}
}
@@ -1241,11 +1140,70 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype,
debugC(1, kDebugLevelResMan, "Patching %s - OK", source->location_name.c_str());
}
+#ifdef ENABLE_SCI32
+
+void ResourceManager::readResourcePatchesBase36(ResourceSource *source) {
+ // The base36 encoded audio36 and sync36 resources use a different naming scheme, because they
+ // cannot be described with a single resource number, but are a result of a
+ // <number, noun, verb, cond, seq> tuple. Please don't be confused with the normal audio patches
+ // (*.aud) and normal sync patches (*.syn). audio36 patches can be seen for example in the AUD
+ // folder of GK1CD, and are like this file: @0CS0M00.0X1. GK1CD is the first game where these
+ // have been observed. The actual audio36 and sync36 resources exist in SCI1.1 as well, but the
+ // first game where external patch files for them have been found is GK1CD. The names of these
+ // files are base36 encoded, and we handle their decoding here. audio36 files start with a '@',
+ // whereas sync36 start with a '#'. Mac versions begin with 'A' (probably meaning AIFF). Torin
+ // has several that begin with 'B'.
+
+ Common::String name, inputName;
+ Common::ArchiveMemberList files;
+ //ResourceSource *psrcPatch;
+
+ for (int i = kResourceTypeAudio36; i <= kResourceTypeSync36; ++i) {
+ // audio36 resources start with a @, A, or B
+ // sync36 resources start with a #
+ if (i == kResourceTypeAudio36) {
+ SearchMan.listMatchingMembers(files, "@???????.???");
+ SearchMan.listMatchingMembers(files, "A???????.???");
+ SearchMan.listMatchingMembers(files, "B???????.???");
+ } else
+ SearchMan.listMatchingMembers(files, "#???????.???");
+
+ for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
+ name = (*x)->getName();
+ inputName = (*x)->getName();
+ inputName.toUppercase();
+ inputName.deleteChar(0); // delete the first character (type)
+ inputName.deleteChar(7); // delete the dot
+
+ // The base36 encoded resource contains the following:
+ // uint16 number, byte noun, byte verb, byte cond, byte seq
+ // TODO: this is still not right (especially the tuple part, seems to be overflowing?)
+ uint16 number = strtol(Common::String(inputName.c_str(), 2).c_str(), 0, 36);
+ uint32 tuple = strtol(inputName.c_str() + 2, 0, 36);
+ ResourceId resource36((ResourceType)i, number, tuple);
+
+ if (i == kResourceTypeAudio36)
+ debug("audio36 patch: %s => %s. tuple:%d, %s\n", name.c_str(), inputName.c_str(), tuple, resource36.toString().c_str());
+ else
+ debug("sync36 patch: %s => %s. tuple:%d, %s\n", name.c_str(), inputName.c_str(), tuple, resource36.toString().c_str());
+
+ /*
+ psrcPatch = new ResourceSource;
+ psrcPatch->source_type = kSourcePatch;
+ psrcPatch->location_name = name;
+ psrcPatch->resourceFile = 0;
+ processPatch(psrcPatch, (ResourceType)i, number, tuple);
+ */
+ }
+ }
+}
+
+#endif
void ResourceManager::readResourcePatches(ResourceSource *source) {
-// Note: since some SCI1 games(KQ5 floppy, SQ4) might use SCI0 naming scheme for patch files
-// this function tries to read patch file with any supported naming scheme,
-// regardless of s_sciVersion value
+ // Note: since some SCI1 games(KQ5 floppy, SQ4) might use SCI0 naming scheme for patch files
+ // this function tries to read patch file with any supported naming scheme,
+ // regardless of s_sciVersion value
Common::String mask, name;
Common::ArchiveMemberList files;
@@ -1253,11 +1211,7 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
const char *szResType;
ResourceSource *psrcPatch;
- for (int i = kResourceTypeView; i <= kResourceTypeRobot; ++i) {
- // TODO: add support for audio36 and sync36 files
- if (i == kResourceTypeAudio36 || i == kResourceTypeSync36)
- continue;
-
+ for (int i = kResourceTypeView; i <= kResourceTypeHeap; ++i) {
files.clear();
szResType = getResourceTypeName((ResourceType)i);
// SCI0 naming - type.nnn
@@ -1268,6 +1222,7 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
mask = "*.";
mask += resourceTypeSuffixes[i];
SearchMan.listMatchingMembers(files, mask);
+
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
bool bAdd = false;
name = (*x)->getName();
@@ -1289,75 +1244,42 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
psrcPatch = new ResourceSource;
psrcPatch->source_type = kSourcePatch;
psrcPatch->location_name = name;
+ psrcPatch->resourceFile = 0;
processPatch(psrcPatch, (ResourceType)i, number);
}
}
}
}
-void ResourceManager::readWaveAudioPatches() {
- // Here we do check for SCI1.1+ so we can patch wav files in as audio resources
- Common::ArchiveMemberList files;
- SearchMan.listMatchingMembers(files, "*.wav");
-
- for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
- Common::String name = (*x)->getName();
-
- if (isdigit(name[0])) {
- int number = atoi(name.c_str());
- ResourceSource *psrcPatch = new ResourceSource;
- psrcPatch->source_type = kSourceWave;
- psrcPatch->location_name = name;
- psrcPatch->volume_number = 0;
- psrcPatch->audioCompressionType = 0;
-
- ResourceId resId = ResourceId(kResourceTypeAudio, number);
-
- Resource *newrsc = NULL;
-
- // Prepare destination, if neccessary
- if (_resMap.contains(resId) == false) {
- newrsc = new Resource;
- _resMap.setVal(resId, newrsc);
- } else
- newrsc = _resMap.getVal(resId);
-
- // Get the size of the file
- Common::SeekableReadStream *stream = (*x)->createReadStream();
- uint32 fileSize = stream->size();
- delete stream;
-
- // Overwrite everything, because we're patching
- newrsc->_id = resId;
- newrsc->_status = kResStatusNoMalloc;
- newrsc->_source = psrcPatch;
- newrsc->size = fileSize;
- newrsc->_headerSize = 0;
- debugC(1, kDebugLevelResMan, "Patching %s - OK", psrcPatch->location_name.c_str());
- }
- }
-}
-
int ResourceManager::readResourceMapSCI0(ResourceSource *map) {
- Common::File file;
+ Common::SeekableReadStream *fileStream = 0;
Resource *res;
ResourceType type;
uint16 number, id;
uint32 offset;
- if (!file.open(map->location_name))
- return SCI_ERROR_RESMAP_NOT_FOUND;
+ if (map->resourceFile) {
+ fileStream = map->resourceFile->createReadStream();
+ if (!fileStream)
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ } else {
+ Common::File *file = new Common::File();
+ if (!file->open(map->location_name))
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ fileStream = file;
+ }
- file.seek(0, SEEK_SET);
+ fileStream->seek(0, SEEK_SET);
byte bMask = (_mapVersion == kResVersionSci1Middle) ? 0xF0 : 0xFC;
byte bShift = (_mapVersion == kResVersionSci1Middle) ? 28 : 26;
do {
- id = file.readUint16LE();
- offset = file.readUint32LE();
+ id = fileStream->readUint16LE();
+ offset = fileStream->readUint32LE();
- if (file.eos() || file.err()) {
+ if (fileStream->eos() || fileStream->err()) {
+ delete fileStream;
warning("Error while reading %s", map->location_name.c_str());
return SCI_ERROR_RESMAP_NOT_FOUND;
}
@@ -1386,15 +1308,26 @@ int ResourceManager::readResourceMapSCI0(ResourceSource *map) {
res->_id = resId;
_resMap.setVal(resId, res);
}
- } while (!file.eos());
+ } while (!fileStream->eos());
+
+ delete fileStream;
return 0;
}
int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
- Common::File file;
+ Common::SeekableReadStream *fileStream = 0;
Resource *res;
- if (!file.open(map->location_name))
- return SCI_ERROR_RESMAP_NOT_FOUND;
+
+ if (map->resourceFile) {
+ fileStream = map->resourceFile->createReadStream();
+ if (!fileStream)
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ } else {
+ Common::File *file = new Common::File();
+ if (!file->open(map->location_name))
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ fileStream = file;
+ }
resource_index_t resMap[32];
memset(resMap, 0, sizeof(resource_index_t) * 32);
@@ -1405,8 +1338,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
// Read resource type and offsets to resource offsets block from .MAP file
// The last entry has type=0xFF (0x1F) and offset equals to map file length
do {
- type = file.readByte() & 0x1F;
- resMap[type].wOffset = file.readUint16LE();
+ type = fileStream->readByte() & 0x1F;
+ resMap[type].wOffset = fileStream->readUint16LE();
resMap[prevtype].wSize = (resMap[type].wOffset
- resMap[prevtype].wOffset) / nEntrySize;
prevtype = type;
@@ -1417,18 +1350,18 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
for (type = 0; type < 32; type++) {
if (resMap[type].wOffset == 0) // this resource does not exist in map
continue;
- file.seek(resMap[type].wOffset);
+ fileStream->seek(resMap[type].wOffset);
for (int i = 0; i < resMap[type].wSize; i++) {
- uint16 number = file.readUint16LE();
+ uint16 number = fileStream->readUint16LE();
int volume_nr = 0;
if (_mapVersion == kResVersionSci11) {
// offset stored in 3 bytes
- off = file.readUint16LE();
- off |= file.readByte() << 16;
+ off = fileStream->readUint16LE();
+ off |= fileStream->readByte() << 16;
off <<= 1;
} else {
// offset/volume stored in 4 bytes
- off = file.readUint32LE();
+ off = fileStream->readUint32LE();
if (_mapVersion < kResVersionSci11) {
volume_nr = off >> 28; // most significant 4 bits
off &= 0x0FFFFFFF; // least significant 28 bits
@@ -1436,7 +1369,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
// in SCI32 it's a plain offset
}
}
- if (file.eos() || file.err()) {
+ if (fileStream->eos() || fileStream->err()) {
+ delete fileStream;
warning("Error while reading %s", map->location_name.c_str());
return SCI_ERROR_RESMAP_NOT_FOUND;
}
@@ -1448,7 +1382,7 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
res->_id = resId;
// NOTE: We add the map's volume number here to the specified volume number
- // for SCI2.1 and SCI3 maps that are not RESMAP.000. The RESMAP.* files' numbers
+ // for SCI2.1 and SCI3 maps that are not resmap.000. The resmap.* files' numbers
// need to be used in concurrence with the volume specified in the map to get
// the actual resource file.
res->_source = getVolume(map, volume_nr + map->volume_number);
@@ -1456,6 +1390,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
}
}
}
+
+ delete fileStream;
return 0;
}
@@ -1476,7 +1412,11 @@ struct {
{ MKID_BE('PAL '), kResourceTypePalette },
{ MKID_BE('snd '), kResourceTypeAudio },
{ MKID_BE('MSG '), kResourceTypeMessage },
- { MKID_BE('HEP '), kResourceTypeHeap }
+ { MKID_BE('HEP '), kResourceTypeHeap },
+ { MKID_BE('IBIN'), kResourceTypeMacIconBarPictN },
+ { MKID_BE('IBIS'), kResourceTypeMacIconBarPictS },
+ { MKID_BE('PICT'), kResourceTypeMacPict },
+ { MKID_BE('SYN '), kResourceTypeSync }
};
static uint32 resTypeToMacTag(ResourceType type) {
@@ -1509,6 +1449,16 @@ int ResourceManager::readMacResourceFork(ResourceSource *source) {
Common::MacResIDArray idArray = source->macResMan.getResIDArray(tagArray[i]);
for (uint32 j = 0; j < idArray.size(); j++) {
+ // Get the size of the file
+ Common::SeekableReadStream *stream = source->macResMan.getResource(tagArray[i], idArray[j]);
+
+ // Some IBIS resources have a size of 0, so we skip them
+ if (!stream)
+ continue;
+
+ uint32 fileSize = stream->size();
+ delete stream;
+
ResourceId resId = ResourceId(type, idArray[j]);
Resource *newrsc = NULL;
@@ -1520,11 +1470,6 @@ int ResourceManager::readMacResourceFork(ResourceSource *source) {
} else
newrsc = _resMap.getVal(resId);
- // Get the size of the file
- Common::SeekableReadStream *stream = source->macResMan.getResource(tagArray[i], idArray[j]);
- uint32 fileSize = stream->size();
- delete stream;
-
// Overwrite everything
newrsc->_id = resId;
newrsc->_status = kResStatusNoMalloc;
@@ -1549,261 +1494,6 @@ void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32
}
}
-void ResourceManager::removeAudioResource(ResourceId resId) {
- // Remove resource, unless it was loaded from a patch
- if (_resMap.contains(resId)) {
- Resource *res = _resMap.getVal(resId);
-
- if (res->_source->source_type == kSourceAudioVolume) {
- if (res->_status == kResStatusLocked) {
- warning("Failed to remove resource %s (still in use)", resId.toString().c_str());
- } else {
- if (res->_status == kResStatusEnqueued)
- removeFromLRU(res);
-
- _resMap.erase(resId);
- delete res;
- }
- }
- }
-}
-
-// Early SCI1.1 65535.MAP structure (uses RESOURCE.AUD):
-// =========
-// 6-byte entries:
-// w nEntry
-// dw offset
-
-// Late SCI1.1 65535.MAP structure (uses RESOURCE.SFX):
-// =========
-// 5-byte entries:
-// w nEntry
-// tb offset (cumulative)
-
-// Early SCI1.1 MAP structure:
-// ===============
-// 10-byte entries:
-// b noun
-// b verb
-// b cond
-// b seq
-// dw offset
-// w syncSize + syncAscSize
-
-// Late SCI1.1 MAP structure:
-// ===============
-// Header:
-// dw baseOffset
-// Followed by 7 or 11-byte entries:
-// b noun
-// b verb
-// b cond
-// b seq
-// tb cOffset (cumulative offset)
-// w syncSize (iff seq has bit 7 set)
-// w syncAscSize (iff seq has bit 6 set)
-
-int ResourceManager::readAudioMapSCI11(ResourceSource *map) {
- bool isEarly = true;
- uint32 offset = 0;
- Resource *mapRes = findResource(ResourceId(kResourceTypeMap, map->volume_number), false);
-
- if (!mapRes) {
- warning("Failed to open %i.MAP", map->volume_number);
- return SCI_ERROR_RESMAP_NOT_FOUND;
- }
-
- ResourceSource *src = getVolume(map, 0);
-
- if (!src)
- return SCI_ERROR_NO_RESOURCE_FILES_FOUND;
-
- byte *ptr = mapRes->data;
-
- if (map->volume_number == 65535) {
- // Heuristic to detect late SCI1.1 map format
- if ((mapRes->size >= 6) && (ptr[mapRes->size - 6] != 0xff))
- isEarly = false;
-
- while (ptr < mapRes->data + mapRes->size) {
- uint16 n = READ_LE_UINT16(ptr);
- ptr += 2;
-
- if (n == 0xffff)
- break;
-
- if (isEarly) {
- offset = READ_LE_UINT32(ptr);
- ptr += 4;
- } else {
- offset += READ_LE_UINT24(ptr);
- ptr += 3;
- }
-
- addResource(ResourceId(kResourceTypeAudio, n), src, offset);
- }
- } else {
- // Heuristic to detect late SCI1.1 map format
- if ((mapRes->size >= 11) && (ptr[mapRes->size - 11] == 0xff))
- isEarly = false;
-
- if (!isEarly) {
- offset = READ_LE_UINT32(ptr);
- ptr += 4;
- }
-
- while (ptr < mapRes->data + mapRes->size) {
- uint32 n = READ_BE_UINT32(ptr);
- int syncSize = 0;
- ptr += 4;
-
- if (n == 0xffffffff)
- break;
-
- if (isEarly) {
- offset = READ_LE_UINT32(ptr);
- ptr += 4;
- } else {
- offset += READ_LE_UINT24(ptr);
- ptr += 3;
- }
-
- if (isEarly || (n & 0x80)) {
- syncSize = READ_LE_UINT16(ptr);
- ptr += 2;
-
- if (syncSize > 0)
- addResource(ResourceId(kResourceTypeSync36, map->volume_number, n & 0xffffff3f), src, offset, syncSize);
- }
-
- if (n & 0x40) {
- syncSize += READ_LE_UINT16(ptr);
- ptr += 2;
- }
-
- addResource(ResourceId(kResourceTypeAudio36, map->volume_number, n & 0xffffff3f), src, offset + syncSize);
- }
- }
-
- return 0;
-}
-
-// AUDIOnnn.MAP contains 10-byte entries:
-// Early format:
-// w 5 bits resource type and 11 bits resource number
-// dw 7 bits volume number and 25 bits offset
-// dw size
-// Later format:
-// w nEntry
-// dw offset+volume (as in resource.map)
-// dw size
-// ending with 10 0xFFs
-int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) {
- Common::File file;
-
- if (!file.open(map->location_name))
- return SCI_ERROR_RESMAP_NOT_FOUND;
-
- bool oldFormat = (file.readUint16LE() >> 11) == kResourceTypeAudio;
- file.seek(0);
-
- while (1) {
- uint16 n = file.readUint16LE();
- uint32 offset = file.readUint32LE();
- uint32 size = file.readUint32LE();
-
- if (file.eos() || file.err()) {
- warning("Error while reading %s", map->location_name.c_str());
- return SCI_ERROR_RESMAP_NOT_FOUND;
- }
-
- if (n == 0xffff)
- break;
-
- byte volume_nr;
-
- if (oldFormat) {
- n &= 0x07ff; // Mask out resource type
- volume_nr = offset >> 25; // most significant 7 bits
- offset &= 0x01ffffff; // least significant 25 bits
- } else {
- volume_nr = offset >> 28; // most significant 4 bits
- offset &= 0x0fffffff; // least significant 28 bits
- }
-
- ResourceSource *src = getVolume(map, volume_nr);
-
- if (src) {
- if (unload)
- removeAudioResource(ResourceId(kResourceTypeAudio, n));
- else
- addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
- } else {
- warning("Failed to find audio volume %i", volume_nr);
- }
- }
-
- return 0;
-}
-
-void ResourceManager::setAudioLanguage(int language) {
- if (_audioMapSCI1) {
- if (_audioMapSCI1->volume_number == language) {
- // This language is already loaded
- return;
- }
-
- // We already have a map loaded, so we unload it first
- readAudioMapSCI1(_audioMapSCI1, true);
-
- // Remove all volumes that use this map from the source list
- Common::List<ResourceSource *>::iterator it = _sources.begin();
- while (it != _sources.end()) {
- ResourceSource *src = *it;
- if (src->associated_map == _audioMapSCI1) {
- it = _sources.erase(it);
- delete src;
- } else {
- ++it;
- }
- }
-
- // Remove the map itself from the source list
- _sources.remove(_audioMapSCI1);
- delete _audioMapSCI1;
-
- _audioMapSCI1 = NULL;
- }
-
- char filename[9];
- snprintf(filename, 9, "AUDIO%03d", language);
-
- Common::String fullname = Common::String(filename) + ".MAP";
- if (!Common::File::exists(fullname)) {
- warning("No audio map found for language %i", language);
- return;
- }
-
- _audioMapSCI1 = addSource(NULL, kSourceExtAudioMap, fullname.c_str(), language);
-
- // Search for audio volumes for this language and add them to the source list
- Common::ArchiveMemberList files;
- SearchMan.listMatchingMembers(files, Common::String(filename) + ".0??");
- for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
- const Common::String name = (*x)->getName();
- const char *dot = strrchr(name.c_str(), '.');
- int number = atoi(dot + 1);
-
- addSource(_audioMapSCI1, kSourceAudioVolume, name.c_str(), number);
- }
-
- scanNewSources();
-}
-
-int ResourceManager::getAudioLanguage() const {
- return (_audioMapSCI1 ? _audioMapSCI1->volume_number : 0);
-}
-
int ResourceManager::readResourceInfo(Resource *res, Common::SeekableReadStream *file,
uint32&szPacked, ResourceCompression &compression) {
// SCI0 volume format: {wResId wPacked+4 wUnpacked wCompression} = 8 bytes
@@ -1954,7 +1644,7 @@ ResourceCompression ResourceManager::getViewCompression() {
// Test 10 views to see if any are compressed
for (int i = 0; i < 1000; i++) {
- Common::File *file;
+ Common::SeekableReadStream *fileStream = 0;
Resource *res = testResource(ResourceId(kResourceTypeView, i));
if (!res)
@@ -1963,16 +1653,23 @@ ResourceCompression ResourceManager::getViewCompression() {
if (res->_source->source_type != kSourceVolume)
continue;
- file = getVolumeFile(res->_source->location_name.c_str());
- if (!file)
+ fileStream = getVolumeFile(res->_source);
+
+ if (!fileStream)
continue;
- file->seek(res->_fileOffset, SEEK_SET);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
uint32 szPacked;
ResourceCompression compression;
- if (readResourceInfo(res, file, szPacked, compression))
+ if (readResourceInfo(res, fileStream, szPacked, compression)) {
+ if (res->_source->resourceFile)
+ delete fileStream;
continue;
+ }
+
+ if (res->_source->resourceFile)
+ delete fileStream;
if (compression != kCompNone)
return compression;
@@ -2329,248 +2026,98 @@ bool ResourceManager::hasSci1Voc900() {
return offset == res->size;
}
-SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersion soundVersion) : _resMan(resMan), _soundVersion(soundVersion) {
- Resource *resource = _resMan->findResource(ResourceId(kResourceTypeSound, resNumber), true);
- int trackNr, channelNr;
- if (!resource)
- return;
-
- _innerResource = resource;
-
- byte *data, *data2;
- byte *dataEnd;
- Channel *channel, *sampleChannel;
-
- switch (_soundVersion) {
- case SCI_VERSION_0_EARLY:
- case SCI_VERSION_0_LATE:
- // SCI0 only has a header of 0x11/0x21 byte length and the actual midi track follows afterwards
- _trackCount = 1;
- _tracks = new Track[_trackCount];
- _tracks->digitalChannelNr = -1;
- _tracks->type = 0; // Not used for SCI0
- _tracks->channelCount = 1;
- // Digital sample data included? -> Add an additional channel
- if (resource->data[0] == 2)
- _tracks->channelCount++;
- _tracks->channels = new Channel[_tracks->channelCount];
- memset(_tracks->channels, 0, sizeof(Channel) * _tracks->channelCount);
- channel = &_tracks->channels[0];
- if (_soundVersion == SCI_VERSION_0_EARLY) {
- channel->data = resource->data + 0x11;
- channel->size = resource->size - 0x11;
- } else {
- channel->data = resource->data + 0x21;
- channel->size = resource->size - 0x21;
- }
- if (_tracks->channelCount == 2) {
- // Digital sample data included
- _tracks->digitalChannelNr = 1;
- sampleChannel = &_tracks->channels[1];
- // we need to find 0xFC (channel terminator) within the data
- data = channel->data;
- dataEnd = channel->data + channel->size;
- while ((data < dataEnd) && (*data != 0xfc))
- data++;
- // Skip any following 0xFCs as well
- while ((data < dataEnd) && (*data == 0xfc))
- data++;
- // Now adjust channels accordingly
- sampleChannel->data = data;
- sampleChannel->size = channel->size - (data - channel->data);
- channel->size = data - channel->data;
- // Read sample header information
- //Offset 14 in the header contains the frequency as a short integer. Offset 32 contains the sample length, also as a short integer.
- _tracks->digitalSampleRate = READ_LE_UINT16(sampleChannel->data + 14);
- _tracks->digitalSampleSize = READ_LE_UINT16(sampleChannel->data + 32);
- _tracks->digitalSampleStart = 0;
- _tracks->digitalSampleEnd = 0;
- sampleChannel->data += 44; // Skip over header
- sampleChannel->size -= 44;
- }
- break;
-
- case SCI_VERSION_1_EARLY:
- case SCI_VERSION_1_LATE:
- data = resource->data;
- // Count # of tracks
- _trackCount = 0;
- while ((*data++) != 0xFF) {
- _trackCount++;
- while (*data != 0xFF)
- data += 6;
- data++;
- }
- _tracks = new Track[_trackCount];
- data = resource->data;
- for (trackNr = 0; trackNr < _trackCount; trackNr++) {
- // Track info starts with track type:BYTE
- // Then the channel information gets appended Unknown:WORD, ChannelOffset:WORD, ChannelSize:WORD
- // 0xFF:BYTE as terminator to end that track and begin with another track type
- // Track type 0xFF is the marker signifying the end of the tracks
-
- _tracks[trackNr].type = *data++;
- // Counting # of channels used
- data2 = data;
- _tracks[trackNr].channelCount = 0;
- while (*data2 != 0xFF) {
- data2 += 6;
- _tracks[trackNr].channelCount++;
- }
- _tracks[trackNr].channels = new Channel[_tracks[trackNr].channelCount];
- _tracks[trackNr].digitalChannelNr = -1; // No digital sound associated
- _tracks[trackNr].digitalSampleRate = 0;
- _tracks[trackNr].digitalSampleSize = 0;
- _tracks[trackNr].digitalSampleStart = 0;
- _tracks[trackNr].digitalSampleEnd = 0;
- if (_tracks[trackNr].type != 0xF0) { // Digital track marker - not supported currently
- for (channelNr = 0; channelNr < _tracks[trackNr].channelCount; channelNr++) {
- channel = &_tracks[trackNr].channels[channelNr];
- channel->prio = READ_LE_UINT16(data);
- channel->data = resource->data + READ_LE_UINT16(data + 2) + 2;
- channel->size = READ_LE_UINT16(data + 4) - 2; // Not counting channel header
- channel->number = *(channel->data - 2);
- channel->poly = *(channel->data - 1);
- channel->time = channel->prev = 0;
- if (channel->number == 0xFE) { // Digital channel
- _tracks[trackNr].digitalChannelNr = channelNr;
- _tracks[trackNr].digitalSampleRate = READ_LE_UINT16(channel->data);
- _tracks[trackNr].digitalSampleSize = READ_LE_UINT16(channel->data + 2);
- _tracks[trackNr].digitalSampleStart = READ_LE_UINT16(channel->data + 4);
- _tracks[trackNr].digitalSampleEnd = READ_LE_UINT16(channel->data + 6);
- channel->data += 8; // Skip over header
- channel->size -= 8;
- }
- data += 6;
- }
- } else {
- // Skip over digital track
- data += 6;
- }
- data++; // Skipping 0xFF that closes channels list
- }
- break;
-
- default:
- error("SoundResource: SCI version %d is unsupported", _soundVersion);
- }
-}
-
-SoundResource::~SoundResource() {
- for (int trackNr = 0; trackNr < _trackCount; trackNr++)
- delete[] _tracks[trackNr].channels;
- delete[] _tracks;
+// Same function as Script::findBlock(). Slight code
+// duplication here, but this has been done to keep the resource
+// manager independent from the rest of the engine
+static byte *findSci0ExportsBlock(byte *buffer) {
+ byte *buf = buffer;
+ bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
- _resMan->unlockResource(_innerResource);
-}
+ if (oldScriptHeader)
+ buf += 2;
-#if 0
-SoundResource::Track* SoundResource::getTrackByNumber(uint16 number) {
- if (_soundVersion <= SCI_VERSION_0_LATE)
- return &_tracks[0];
-
- if (/*number >= 0 &&*/number < _trackCount)
- return &_tracks[number];
- return NULL;
-}
-#endif
+ do {
+ int seekerType = READ_LE_UINT16(buf);
-SoundResource::Track *SoundResource::getTrackByType(byte type) {
- if (_soundVersion <= SCI_VERSION_0_LATE)
- return &_tracks[0];
+ if (seekerType == 0)
+ break;
+ if (seekerType == 7) // exports
+ return buf;
- for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
- if (_tracks[trackNr].type == type)
- return &_tracks[trackNr];
- }
- return NULL;
-}
+ int seekerSize = READ_LE_UINT16(buf + 2);
+ assert(seekerSize > 0);
+ buf += seekerSize;
+ } while (1);
-SoundResource::Track *SoundResource::getDigitalTrack() {
- for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
- if (_tracks[trackNr].digitalChannelNr != -1)
- return &_tracks[trackNr];
- }
return NULL;
}
-// Gets the filter mask for SCI0 sound resources
-int SoundResource::getChannelFilterMask(int hardwareMask, bool wantsRhythm) {
- byte *data = _innerResource->data;
- int channelMask = 0;
-
- if (_soundVersion > SCI_VERSION_0_LATE)
- return 0;
+reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
+ Resource *script = findResource(ResourceId(kResourceTypeScript, 0), false);
- data++; // Skip over digital sample flag
+ if (!script)
+ return NULL_REG;
- for (int channelNr = 0; channelNr < 16; channelNr++) {
- channelMask = channelMask >> 1;
+ byte *offsetPtr = 0;
- byte flags;
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ byte *buf = (getSciVersion() == SCI_VERSION_0_EARLY) ? script->data + 2 : script->data;
- if (_soundVersion == SCI_VERSION_0_EARLY) {
- // Each channel is specified by a single byte
- // Upper 4 bits of the byte is a voices count
- // Lower 4 bits -> bit 0 set: use for AdLib
- // bit 1 set: use for PCjr
- // bit 2 set: use for PC speaker
- // bit 3 set and bit 0 clear: control channel (15)
- // bit 3 set and bit 0 set: rhythm channel (9)
- // Note: control channel is dynamically assigned inside the drivers,
- // but seems to be fixed at 15 in the song data.
- flags = *data++;
-
- // Get device bits
- flags &= 0x7;
+ // Check if the first block is the exports block (in most cases, it is)
+ bool exportsIsFirst = (READ_LE_UINT16(buf + 4) == 7);
+ if (exportsIsFirst) {
+ offsetPtr = buf + 4 + 2;
} else {
- // Each channel is specified by 2 bytes
- // 1st byte is voices count
- // 2nd byte is play mask, which specifies if the channel is supposed to be played
- // by the corresponding hardware
-
- // Skip voice count
- data++;
-
- flags = *data++;
+ offsetPtr = findSci0ExportsBlock(script->data);
+ if (!offsetPtr)
+ error("Unable to find exports block from script 0");
+ offsetPtr += 4 + 2;
}
+ } else {
+ offsetPtr = script->data + 4 + 2 + 2;
+ }
+
+ int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
- bool play;
- switch (channelNr) {
- case 15:
- // Always play control channel
- play = true;
- break;
- case 9:
- // Play rhythm channel when requested
- play = wantsRhythm;
- break;
- default:
- // Otherwise check for flag
- play = flags & hardwareMask;
- }
+ // In SCI1.1 and newer, the heap is appended at the end of the script,
+ // so adjust the offset accordingly
+ if (getSciVersion() >= SCI_VERSION_1_1 && addSci11ScriptOffset) {
+ offset += script->size;
- if (play) {
- // This Channel is supposed to be played by the hardware
- channelMask |= 0x8000;
- }
+ // Ensure that the start of the heap is word-aligned - same as in Script::init()
+ if (script->size & 2)
+ offset++;
}
- return channelMask;
+ return make_reg(1, offset);
}
-byte SoundResource::getInitialVoiceCount(byte channel) {
- byte *data = _innerResource->data;
+Common::String ResourceManager::findSierraGameId() {
+ // In SCI0-SCI1, the heap is embedded in the script. In SCI1.1+, it's separated
+ Resource *heap = 0;
+ int nameSelector = 3;
- if (_soundVersion > SCI_VERSION_0_LATE)
- return 0; // TODO
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ heap = findResource(ResourceId(kResourceTypeScript, 0), false);
+ } else {
+ heap = findResource(ResourceId(kResourceTypeHeap, 0), false);
+ nameSelector += 5;
+ }
- data++; // Skip over digital sample flag
+ if (!heap)
+ return "";
- if (_soundVersion == SCI_VERSION_0_EARLY)
- return data[channel] >> 4;
- else
- return data[channel * 2];
+ int16 gameObjectOffset = findGameObject(false).offset;
+
+ if (!gameObjectOffset)
+ return "";
+
+ // Seek to the name selector of the first export
+ byte *seeker = heap->data + READ_UINT16(heap->data + gameObjectOffset + nameSelector * 2);
+ Common::String sierraId;
+ sierraId += (const char *)seeker;
+
+ return sierraId;
}
} // End of namespace Sci
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 48b5f095b1..43e61eaadb 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -26,8 +26,9 @@
#ifndef SCI_SCICORE_RESOURCE_H
#define SCI_SCICORE_RESOURCE_H
-#include "common/str.h"
#include "common/fs.h"
+#include "common/macresman.h"
+#include "common/str.h"
#include "sci/graphics/helpers.h" // for ViewType
#include "sci/decompressor.h"
@@ -108,14 +109,31 @@ enum ResourceType {
kResourceTypeUnknown1, // Translation, currently unsupported
kResourceTypeUnknown2,
kResourceTypeRobot,
- kResourceTypeInvalid
+ kResourceTypeInvalid,
+
+ // Mac-only resources, these resource types are self-defined
+ // Numbers subject to change
+ kResourceTypeMacIconBarPictN = -1, // IBIN resources (icon bar, not selected)
+ kResourceTypeMacIconBarPictS = -2, // IBIS resources (icon bar, selected)
+ kResourceTypeMacPict = -3 // PICT resources (inventory)
};
const char *getResourceTypeName(ResourceType restype);
class ResourceManager;
-struct ResourceSource;
+
+struct ResourceSource {
+ ResSourceType source_type;
+ bool scanned;
+ Common::String location_name; // FIXME: Replace by FSNode ?
+ const Common::FSNode *resourceFile;
+ int volume_number;
+ ResourceSource *associated_map;
+ uint32 audioCompressionType;
+ int32 *audioCompressionOffsetMapping;
+ Common::MacResManager macResMan;
+};
class ResourceId {
public:
@@ -127,7 +145,7 @@ public:
ResourceId(ResourceType type_, uint16 number_, uint32 tuple_ = 0)
: type(type_), number(number_), tuple(tuple_) {
- if ((type < kResourceTypeView) || (type > kResourceTypeInvalid))
+ if (type < kResourceTypeMacPict || type > kResourceTypeInvalid)
type = kResourceTypeInvalid;
}
@@ -273,6 +291,19 @@ public:
// Detects, if standard font of current game includes extended characters (>0x80)
bool detectFontExtended();
+ /**
+ * Finds the internal Sierra ID of the current game from script 0
+ */
+ Common::String findSierraGameId();
+
+ /**
+ * Finds the location of the game object from script 0
+ * @param addSci11ScriptOffset: Adjust the return value for SCI1.1 and newer
+ * games. Needs to be false when the heap is accessed directly inside
+ * findSierraGameId().
+ */
+ reg_t findGameObject(bool addSci11ScriptOffset = true);
+
protected:
// Maximum number of bytes to allow being allocated for resources
// Note: maxMemory will not be interpreted as a hard limit, only as a restriction
@@ -290,8 +321,8 @@ protected:
ResourceMap _resMap;
Common::List<Common::File *> _volumeFiles; ///< list of opened volume files
ResourceSource *_audioMapSCI1; ///< Currently loaded audio map for SCI1
- ResVersion _volVersion; ///< RESOURCE.0xx version
- ResVersion _mapVersion; ///< RESOURCE.MAP version
+ ResVersion _volVersion; ///< resource.0xx version
+ ResVersion _mapVersion; ///< resource.map version
/**
* Initializes the resource manager
@@ -327,7 +358,7 @@ protected:
*/
ResourceSource *addExternalMap(const char *file_name, int volume_nr = 0);
- ResourceSource *addExternalMap(const Common::FSNode *mapFile);
+ ResourceSource *addExternalMap(const Common::FSNode *mapFile, int volume_nr = 0);
/**
* Add an internal (i.e., resource) map to the resource manager's list of sources.
@@ -362,13 +393,13 @@ protected:
*/
const char *versionDescription(ResVersion version) const;
- Common::File *getVolumeFile(const char *filename);
+ Common::SeekableReadStream *getVolumeFile(ResourceSource *source);
void loadResource(Resource *res);
- bool loadPatch(Resource *res, Common::File &file);
+ bool loadPatch(Resource *res, Common::SeekableReadStream *file);
bool loadFromPatchFile(Resource *res);
- bool loadFromWaveFile(Resource *res, Common::File &file);
- bool loadFromAudioVolumeSCI1(Resource *res, Common::File &file);
- bool loadFromAudioVolumeSCI11(Resource *res, Common::File &file);
+ bool loadFromWaveFile(Resource *res, Common::SeekableReadStream *file);
+ bool loadFromAudioVolumeSCI1(Resource *res, Common::SeekableReadStream *file);
+ bool loadFromAudioVolumeSCI11(Resource *res, Common::SeekableReadStream *file);
void freeOldResources();
int decompress(Resource *res, Common::SeekableReadStream *file);
int readResourceInfo(Resource *res, Common::SeekableReadStream *file, uint32&szPacked, ResourceCompression &compression);
@@ -421,7 +452,10 @@ protected:
* Reads patch files from a local directory.
*/
void readResourcePatches(ResourceSource *source);
- void processPatch(ResourceSource *source, ResourceType restype, int resnumber);
+#ifdef ENABLE_SCI32
+ void readResourcePatchesBase36(ResourceSource *source);
+#endif
+ void processPatch(ResourceSource *source, ResourceType restype, uint16 resnumber, uint32 tuple = 0);
/**
* Process wave files as patches for Audio resources
@@ -481,6 +515,7 @@ public:
Track *getDigitalTrack();
int getChannelFilterMask(int hardwareMask, bool wantsRhythm);
byte getInitialVoiceCount(byte channel);
+ bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); }
private:
SciVersion _soundVersion;
@@ -488,6 +523,9 @@ private:
Track *_tracks;
Resource *_innerResource;
ResourceManager *_resMan;
+ uint16 _channelsUsed;
+
+ void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); }
};
} // End of namespace Sci
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
new file mode 100644
index 0000000000..57efbdcb38
--- /dev/null
+++ b/engines/sci/resource_audio.cpp
@@ -0,0 +1,711 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Resource library
+
+#include "common/file.h"
+
+#include "sci/resource.h"
+#include "sci/util.h"
+
+namespace Sci {
+
+void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) {
+ Common::SeekableReadStream *fileStream = getVolumeFile(source);
+
+ if (!fileStream) {
+ warning("Failed to open %s", source->location_name.c_str());
+ return;
+ }
+
+ fileStream->seek(0, SEEK_SET);
+ uint32 compressionType = fileStream->readUint32BE();
+ switch (compressionType) {
+ case MKID_BE('MP3 '):
+ case MKID_BE('OGG '):
+ case MKID_BE('FLAC'):
+ // Detected a compressed audio volume
+ source->audioCompressionType = compressionType;
+ // Now read the whole offset mapping table for later usage
+ int32 recordCount = fileStream->readUint32LE();
+ if (!recordCount)
+ error("compressed audio volume doesn't contain any entries!");
+ int32 *offsetMapping = new int32[(recordCount + 1) * 2];
+ source->audioCompressionOffsetMapping = offsetMapping;
+ for (int recordNo = 0; recordNo < recordCount; recordNo++) {
+ *offsetMapping++ = fileStream->readUint32LE();
+ *offsetMapping++ = fileStream->readUint32LE();
+ }
+ // Put ending zero
+ *offsetMapping++ = 0;
+ *offsetMapping++ = fileStream->size();
+ }
+
+ if (source->resourceFile)
+ delete fileStream;
+}
+
+bool ResourceManager::loadFromWaveFile(Resource *res, Common::SeekableReadStream *file) {
+ res->data = new byte[res->size];
+
+ uint32 really_read = file->read(res->data, res->size);
+ if (really_read != res->size)
+ error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
+
+ res->_status = kResStatusAllocated;
+ return true;
+}
+
+bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::SeekableReadStream *file) {
+ // Check for WAVE files here
+ uint32 riffTag = file->readUint32BE();
+ if (riffTag == MKID_BE('RIFF')) {
+ res->_headerSize = 0;
+ res->size = file->readUint32LE();
+ file->seek(-8, SEEK_CUR);
+ return loadFromWaveFile(res, file);
+ }
+ file->seek(-4, SEEK_CUR);
+
+ ResourceType type = (ResourceType)(file->readByte() & 0x7f);
+ if (((res->_id.type == kResourceTypeAudio || res->_id.type == kResourceTypeAudio36) && (type != kResourceTypeAudio))
+ || ((res->_id.type == kResourceTypeSync || res->_id.type == kResourceTypeSync36) && (type != kResourceTypeSync))) {
+ warning("Resource type mismatch loading %s", res->_id.toString().c_str());
+ res->unalloc();
+ return false;
+ }
+
+ res->_headerSize = file->readByte();
+
+ if (type == kResourceTypeAudio) {
+ if (res->_headerSize != 11 && res->_headerSize != 12) {
+ warning("Unsupported audio header");
+ res->unalloc();
+ return false;
+ }
+
+ // Load sample size
+ file->seek(7, SEEK_CUR);
+ res->size = file->readUint32LE();
+ // Adjust offset to point at the header data again
+ file->seek(-11, SEEK_CUR);
+ }
+
+ return loadPatch(res, file);
+}
+
+bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::SeekableReadStream *file) {
+ res->data = new byte[res->size];
+
+ if (res->data == NULL) {
+ error("Can't allocate %d bytes needed for loading %s", res->size, res->_id.toString().c_str());
+ }
+
+ unsigned int really_read = file->read(res->data, res->size);
+ if (really_read != res->size)
+ warning("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
+
+ res->_status = kResStatusAllocated;
+ return true;
+}
+
+void ResourceManager::addNewGMPatch(const Common::String &gameId) {
+ Common::String gmPatchFile;
+
+ if (gameId == "ecoquest")
+ gmPatchFile = "ECO1GM.PAT";
+ else if (gameId == "hoyle3")
+ gmPatchFile = "HOY3GM.PAT";
+ else if (gameId == "hoyle3")
+ gmPatchFile = "HOY3GM.PAT";
+ else if (gameId == "lsl1sci")
+ gmPatchFile = "LL1_GM.PAT";
+ else if (gameId == "lsl5")
+ gmPatchFile = "LL5_GM.PAT";
+ else if (gameId == "longbow")
+ gmPatchFile = "ROBNGM.PAT";
+ else if (gameId == "sq1sci")
+ gmPatchFile = "SQ1_GM.PAT";
+ else if (gameId == "sq4")
+ gmPatchFile = "SQ4_GM.PAT";
+ else if (gameId == "fairytales")
+ gmPatchFile = "TALEGM.PAT";
+
+ if (!gmPatchFile.empty() && Common::File::exists(gmPatchFile)) {
+ ResourceSource *psrcPatch = new ResourceSource;
+ psrcPatch->source_type = kSourcePatch;
+ psrcPatch->resourceFile = 0;
+ psrcPatch->location_name = gmPatchFile;
+ processPatch(psrcPatch, kResourceTypePatch, 4);
+ }
+}
+
+void ResourceManager::readWaveAudioPatches() {
+ // Here we do check for SCI1.1+ so we can patch wav files in as audio resources
+ Common::ArchiveMemberList files;
+ SearchMan.listMatchingMembers(files, "*.wav");
+
+ for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
+ Common::String name = (*x)->getName();
+
+ if (isdigit(name[0])) {
+ int number = atoi(name.c_str());
+ ResourceSource *psrcPatch = new ResourceSource;
+ psrcPatch->source_type = kSourceWave;
+ psrcPatch->resourceFile = 0;
+ psrcPatch->location_name = name;
+ psrcPatch->volume_number = 0;
+ psrcPatch->audioCompressionType = 0;
+
+ ResourceId resId = ResourceId(kResourceTypeAudio, number);
+
+ Resource *newrsc = NULL;
+
+ // Prepare destination, if neccessary
+ if (_resMap.contains(resId) == false) {
+ newrsc = new Resource;
+ _resMap.setVal(resId, newrsc);
+ } else
+ newrsc = _resMap.getVal(resId);
+
+ // Get the size of the file
+ Common::SeekableReadStream *stream = (*x)->createReadStream();
+ uint32 fileSize = stream->size();
+ delete stream;
+
+ // Overwrite everything, because we're patching
+ newrsc->_id = resId;
+ newrsc->_status = kResStatusNoMalloc;
+ newrsc->_source = psrcPatch;
+ newrsc->size = fileSize;
+ newrsc->_headerSize = 0;
+ debugC(1, kDebugLevelResMan, "Patching %s - OK", psrcPatch->location_name.c_str());
+ }
+ }
+}
+
+void ResourceManager::removeAudioResource(ResourceId resId) {
+ // Remove resource, unless it was loaded from a patch
+ if (_resMap.contains(resId)) {
+ Resource *res = _resMap.getVal(resId);
+
+ if (res->_source->source_type == kSourceAudioVolume) {
+ if (res->_status == kResStatusLocked) {
+ warning("Failed to remove resource %s (still in use)", resId.toString().c_str());
+ } else {
+ if (res->_status == kResStatusEnqueued)
+ removeFromLRU(res);
+
+ _resMap.erase(resId);
+ delete res;
+ }
+ }
+ }
+}
+
+// Early SCI1.1 65535.MAP structure (uses RESOURCE.AUD):
+// =========
+// 6-byte entries:
+// w nEntry
+// dw offset
+
+// Late SCI1.1 65535.MAP structure (uses RESOURCE.SFX):
+// =========
+// 5-byte entries:
+// w nEntry
+// tb offset (cumulative)
+
+// Early SCI1.1 MAP structure:
+// ===============
+// 10-byte entries:
+// b noun
+// b verb
+// b cond
+// b seq
+// dw offset
+// w syncSize + syncAscSize
+
+// Late SCI1.1 MAP structure:
+// ===============
+// Header:
+// dw baseOffset
+// Followed by 7 or 11-byte entries:
+// b noun
+// b verb
+// b cond
+// b seq
+// tb cOffset (cumulative offset)
+// w syncSize (iff seq has bit 7 set)
+// w syncAscSize (iff seq has bit 6 set)
+
+int ResourceManager::readAudioMapSCI11(ResourceSource *map) {
+ bool isEarly = true;
+ uint32 offset = 0;
+ Resource *mapRes = findResource(ResourceId(kResourceTypeMap, map->volume_number), false);
+
+ if (!mapRes) {
+ warning("Failed to open %i.MAP", map->volume_number);
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ }
+
+ ResourceSource *src = getVolume(map, 0);
+
+ if (!src)
+ return SCI_ERROR_NO_RESOURCE_FILES_FOUND;
+
+ byte *ptr = mapRes->data;
+
+ if (map->volume_number == 65535) {
+ // Heuristic to detect late SCI1.1 map format
+ if ((mapRes->size >= 6) && (ptr[mapRes->size - 6] != 0xff))
+ isEarly = false;
+
+ while (ptr < mapRes->data + mapRes->size) {
+ uint16 n = READ_LE_UINT16(ptr);
+ ptr += 2;
+
+ if (n == 0xffff)
+ break;
+
+ if (isEarly) {
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+ } else {
+ offset += READ_LE_UINT24(ptr);
+ ptr += 3;
+ }
+
+ addResource(ResourceId(kResourceTypeAudio, n), src, offset);
+ }
+ } else {
+ // Heuristic to detect late SCI1.1 map format
+ if ((mapRes->size >= 11) && (ptr[mapRes->size - 11] == 0xff))
+ isEarly = false;
+
+ if (!isEarly) {
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+ }
+
+ while (ptr < mapRes->data + mapRes->size) {
+ uint32 n = READ_BE_UINT32(ptr);
+ int syncSize = 0;
+ ptr += 4;
+
+ if (n == 0xffffffff)
+ break;
+
+ if (isEarly) {
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+ } else {
+ offset += READ_LE_UINT24(ptr);
+ ptr += 3;
+ }
+
+ if (isEarly || (n & 0x80)) {
+ syncSize = READ_LE_UINT16(ptr);
+ ptr += 2;
+
+ if (syncSize > 0)
+ addResource(ResourceId(kResourceTypeSync36, map->volume_number, n & 0xffffff3f), src, offset, syncSize);
+ }
+
+ if (n & 0x40) {
+ syncSize += READ_LE_UINT16(ptr);
+ ptr += 2;
+ }
+
+ addResource(ResourceId(kResourceTypeAudio36, map->volume_number, n & 0xffffff3f), src, offset + syncSize);
+ }
+ }
+
+ return 0;
+}
+
+// AUDIOnnn.MAP contains 10-byte entries:
+// Early format:
+// w 5 bits resource type and 11 bits resource number
+// dw 7 bits volume number and 25 bits offset
+// dw size
+// Later format:
+// w nEntry
+// dw offset+volume (as in resource.map)
+// dw size
+// ending with 10 0xFFs
+int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) {
+ Common::File file;
+
+ if (!file.open(map->location_name))
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+
+ bool oldFormat = (file.readUint16LE() >> 11) == kResourceTypeAudio;
+ file.seek(0);
+
+ while (1) {
+ uint16 n = file.readUint16LE();
+ uint32 offset = file.readUint32LE();
+ uint32 size = file.readUint32LE();
+
+ if (file.eos() || file.err()) {
+ warning("Error while reading %s", map->location_name.c_str());
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ }
+
+ if (n == 0xffff)
+ break;
+
+ byte volume_nr;
+
+ if (oldFormat) {
+ n &= 0x07ff; // Mask out resource type
+ volume_nr = offset >> 25; // most significant 7 bits
+ offset &= 0x01ffffff; // least significant 25 bits
+ } else {
+ volume_nr = offset >> 28; // most significant 4 bits
+ offset &= 0x0fffffff; // least significant 28 bits
+ }
+
+ ResourceSource *src = getVolume(map, volume_nr);
+
+ if (src) {
+ if (unload)
+ removeAudioResource(ResourceId(kResourceTypeAudio, n));
+ else
+ addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
+ } else {
+ warning("Failed to find audio volume %i", volume_nr);
+ }
+ }
+
+ return 0;
+}
+
+void ResourceManager::setAudioLanguage(int language) {
+ if (_audioMapSCI1) {
+ if (_audioMapSCI1->volume_number == language) {
+ // This language is already loaded
+ return;
+ }
+
+ // We already have a map loaded, so we unload it first
+ readAudioMapSCI1(_audioMapSCI1, true);
+
+ // Remove all volumes that use this map from the source list
+ Common::List<ResourceSource *>::iterator it = _sources.begin();
+ while (it != _sources.end()) {
+ ResourceSource *src = *it;
+ if (src->associated_map == _audioMapSCI1) {
+ it = _sources.erase(it);
+ delete src;
+ } else {
+ ++it;
+ }
+ }
+
+ // Remove the map itself from the source list
+ _sources.remove(_audioMapSCI1);
+ delete _audioMapSCI1;
+
+ _audioMapSCI1 = NULL;
+ }
+
+ char filename[9];
+ snprintf(filename, 9, "AUDIO%03d", language);
+
+ Common::String fullname = Common::String(filename) + ".MAP";
+ if (!Common::File::exists(fullname)) {
+ warning("No audio map found for language %i", language);
+ return;
+ }
+
+ _audioMapSCI1 = addSource(NULL, kSourceExtAudioMap, fullname.c_str(), language);
+
+ // Search for audio volumes for this language and add them to the source list
+ Common::ArchiveMemberList files;
+ SearchMan.listMatchingMembers(files, Common::String(filename) + ".0??");
+ for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
+ const Common::String name = (*x)->getName();
+ const char *dot = strrchr(name.c_str(), '.');
+ int number = atoi(dot + 1);
+
+ addSource(_audioMapSCI1, kSourceAudioVolume, name.c_str(), number);
+ }
+
+ scanNewSources();
+}
+
+int ResourceManager::getAudioLanguage() const {
+ return (_audioMapSCI1 ? _audioMapSCI1->volume_number : 0);
+}
+
+SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersion soundVersion) : _resMan(resMan), _soundVersion(soundVersion) {
+ Resource *resource = _resMan->findResource(ResourceId(kResourceTypeSound, resNumber), true);
+ int trackNr, channelNr;
+ if (!resource)
+ return;
+
+ _innerResource = resource;
+
+ byte *data, *data2;
+ byte *dataEnd;
+ Channel *channel, *sampleChannel;
+
+ _channelsUsed = 0;
+
+ switch (_soundVersion) {
+ case SCI_VERSION_0_EARLY:
+ case SCI_VERSION_0_LATE:
+ // SCI0 only has a header of 0x11/0x21 byte length and the actual midi track follows afterwards
+ _trackCount = 1;
+ _tracks = new Track[_trackCount];
+ _tracks->digitalChannelNr = -1;
+ _tracks->type = 0; // Not used for SCI0
+ _tracks->channelCount = 1;
+ // Digital sample data included? -> Add an additional channel
+ if (resource->data[0] == 2)
+ _tracks->channelCount++;
+ _tracks->channels = new Channel[_tracks->channelCount];
+ memset(_tracks->channels, 0, sizeof(Channel) * _tracks->channelCount);
+ channel = &_tracks->channels[0];
+ if (_soundVersion == SCI_VERSION_0_EARLY) {
+ channel->data = resource->data + 0x11;
+ channel->size = resource->size - 0x11;
+ } else {
+ channel->data = resource->data + 0x21;
+ channel->size = resource->size - 0x21;
+ }
+ if (_tracks->channelCount == 2) {
+ // Digital sample data included
+ _tracks->digitalChannelNr = 1;
+ sampleChannel = &_tracks->channels[1];
+ // we need to find 0xFC (channel terminator) within the data
+ data = channel->data;
+ dataEnd = channel->data + channel->size;
+ while ((data < dataEnd) && (*data != 0xfc))
+ data++;
+ // Skip any following 0xFCs as well
+ while ((data < dataEnd) && (*data == 0xfc))
+ data++;
+ // Now adjust channels accordingly
+ sampleChannel->data = data;
+ sampleChannel->size = channel->size - (data - channel->data);
+ channel->size = data - channel->data;
+ // Read sample header information
+ //Offset 14 in the header contains the frequency as a short integer. Offset 32 contains the sample length, also as a short integer.
+ _tracks->digitalSampleRate = READ_LE_UINT16(sampleChannel->data + 14);
+ _tracks->digitalSampleSize = READ_LE_UINT16(sampleChannel->data + 32);
+ _tracks->digitalSampleStart = 0;
+ _tracks->digitalSampleEnd = 0;
+ sampleChannel->data += 44; // Skip over header
+ sampleChannel->size -= 44;
+ }
+ break;
+
+ case SCI_VERSION_1_EARLY:
+ case SCI_VERSION_1_LATE:
+ data = resource->data;
+ // Count # of tracks
+ _trackCount = 0;
+ while ((*data++) != 0xFF) {
+ _trackCount++;
+ while (*data != 0xFF)
+ data += 6;
+ data++;
+ }
+ _tracks = new Track[_trackCount];
+ data = resource->data;
+ for (trackNr = 0; trackNr < _trackCount; trackNr++) {
+ // Track info starts with track type:BYTE
+ // Then the channel information gets appended Unknown:WORD, ChannelOffset:WORD, ChannelSize:WORD
+ // 0xFF:BYTE as terminator to end that track and begin with another track type
+ // Track type 0xFF is the marker signifying the end of the tracks
+
+ _tracks[trackNr].type = *data++;
+ // Counting # of channels used
+ data2 = data;
+ _tracks[trackNr].channelCount = 0;
+ while (*data2 != 0xFF) {
+ data2 += 6;
+ _tracks[trackNr].channelCount++;
+ }
+ _tracks[trackNr].channels = new Channel[_tracks[trackNr].channelCount];
+ _tracks[trackNr].digitalChannelNr = -1; // No digital sound associated
+ _tracks[trackNr].digitalSampleRate = 0;
+ _tracks[trackNr].digitalSampleSize = 0;
+ _tracks[trackNr].digitalSampleStart = 0;
+ _tracks[trackNr].digitalSampleEnd = 0;
+ if (_tracks[trackNr].type != 0xF0) { // Digital track marker - not supported currently
+ for (channelNr = 0; channelNr < _tracks[trackNr].channelCount; channelNr++) {
+ channel = &_tracks[trackNr].channels[channelNr];
+ channel->prio = READ_LE_UINT16(data);
+ channel->data = resource->data + READ_LE_UINT16(data + 2) + 2;
+ channel->size = READ_LE_UINT16(data + 4) - 2; // Not counting channel header
+ channel->number = *(channel->data - 2);
+ setChannelUsed(channel->number);
+ channel->poly = *(channel->data - 1);
+ channel->time = channel->prev = 0;
+ if (channel->number == 0xFE) { // Digital channel
+ _tracks[trackNr].digitalChannelNr = channelNr;
+ _tracks[trackNr].digitalSampleRate = READ_LE_UINT16(channel->data);
+ _tracks[trackNr].digitalSampleSize = READ_LE_UINT16(channel->data + 2);
+ _tracks[trackNr].digitalSampleStart = READ_LE_UINT16(channel->data + 4);
+ _tracks[trackNr].digitalSampleEnd = READ_LE_UINT16(channel->data + 6);
+ channel->data += 8; // Skip over header
+ channel->size -= 8;
+ }
+ data += 6;
+ }
+ } else {
+ // Skip over digital track
+ data += 6;
+ }
+ data++; // Skipping 0xFF that closes channels list
+ }
+ break;
+
+ default:
+ error("SoundResource: SCI version %d is unsupported", _soundVersion);
+ }
+}
+
+SoundResource::~SoundResource() {
+ for (int trackNr = 0; trackNr < _trackCount; trackNr++)
+ delete[] _tracks[trackNr].channels;
+ delete[] _tracks;
+
+ _resMan->unlockResource(_innerResource);
+}
+
+#if 0
+SoundResource::Track* SoundResource::getTrackByNumber(uint16 number) {
+ if (_soundVersion <= SCI_VERSION_0_LATE)
+ return &_tracks[0];
+
+ if (/*number >= 0 &&*/number < _trackCount)
+ return &_tracks[number];
+ return NULL;
+}
+#endif
+
+SoundResource::Track *SoundResource::getTrackByType(byte type) {
+ if (_soundVersion <= SCI_VERSION_0_LATE)
+ return &_tracks[0];
+
+ for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
+ if (_tracks[trackNr].type == type)
+ return &_tracks[trackNr];
+ }
+ return NULL;
+}
+
+SoundResource::Track *SoundResource::getDigitalTrack() {
+ for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
+ if (_tracks[trackNr].digitalChannelNr != -1)
+ return &_tracks[trackNr];
+ }
+ return NULL;
+}
+
+// Gets the filter mask for SCI0 sound resources
+int SoundResource::getChannelFilterMask(int hardwareMask, bool wantsRhythm) {
+ byte *data = _innerResource->data;
+ int channelMask = 0;
+
+ if (_soundVersion > SCI_VERSION_0_LATE)
+ return 0;
+
+ data++; // Skip over digital sample flag
+
+ for (int channelNr = 0; channelNr < 16; channelNr++) {
+ channelMask = channelMask >> 1;
+
+ byte flags;
+
+ if (_soundVersion == SCI_VERSION_0_EARLY) {
+ // Each channel is specified by a single byte
+ // Upper 4 bits of the byte is a voices count
+ // Lower 4 bits -> bit 0 set: use for AdLib
+ // bit 1 set: use for PCjr
+ // bit 2 set: use for PC speaker
+ // bit 3 set and bit 0 clear: control channel (15)
+ // bit 3 set and bit 0 set: rhythm channel (9)
+ // Note: control channel is dynamically assigned inside the drivers,
+ // but seems to be fixed at 15 in the song data.
+ flags = *data++;
+
+ // Get device bits
+ flags &= 0x7;
+ } else {
+ // Each channel is specified by 2 bytes
+ // 1st byte is voices count
+ // 2nd byte is play mask, which specifies if the channel is supposed to be played
+ // by the corresponding hardware
+
+ // Skip voice count
+ data++;
+
+ flags = *data++;
+ }
+
+ bool play;
+ switch (channelNr) {
+ case 15:
+ // Always play control channel
+ play = true;
+ break;
+ case 9:
+ // Play rhythm channel when requested
+ play = wantsRhythm;
+ break;
+ default:
+ // Otherwise check for flag
+ play = flags & hardwareMask;
+ }
+
+ if (play) {
+ // This Channel is supposed to be played by the hardware
+ channelMask |= 0x8000;
+ }
+ }
+
+ return channelMask;
+}
+
+byte SoundResource::getInitialVoiceCount(byte channel) {
+ byte *data = _innerResource->data;
+
+ if (_soundVersion > SCI_VERSION_0_LATE)
+ return 0; // TODO
+
+ data++; // Skip over digital sample flag
+
+ if (_soundVersion == SCI_VERSION_0_EARLY)
+ return data[channel] >> 4;
+ else
+ return data[channel * 2];
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 4862d0579a..929bdf3307 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -43,6 +43,7 @@
#include "sci/sound/audio.h"
#include "sci/sound/soundcmd.h"
#include "sci/graphics/gui.h"
+#include "sci/graphics/maciconbar.h"
#include "sci/graphics/ports.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/cursor.h"
@@ -55,8 +56,6 @@
namespace Sci {
-extern int g_loadFromLauncher;
-
SciEngine *g_sci = 0;
@@ -97,6 +96,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc)
DebugMan.addDebugChannel(kDebugLevelOnStartup, "OnStartup", "Enter debugger at start of game");
_gamestate = 0;
+ _gfxMacIconBar = 0;
const Common::FSNode gameDataDir(ConfMan.get("path"));
@@ -124,6 +124,7 @@ SciEngine::~SciEngine() {
delete _console;
delete _resMan;
delete _features;
+ delete _gfxMacIconBar;
g_sci = 0;
}
@@ -170,6 +171,9 @@ Common::Error SciEngine::run() {
else
screen = new GfxScreen(_resMan, 320, 200, upscaledHires);
+ if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1)
+ _gfxMacIconBar = new GfxMacIconBar();
+
GfxPalette *palette = new GfxPalette(_resMan, screen);
GfxCache *cache = new GfxCache(_resMan, screen, palette);
GfxCursor *cursor = new GfxCursor(_resMan, palette, screen);
@@ -184,7 +188,7 @@ Common::Error SciEngine::run() {
_features = new GameFeatures(segMan, _kernel);
- _gamestate = new EngineState(_vocabulary, segMan);
+ _gamestate = new EngineState(segMan);
_gamestate->_event = new SciEvent(_resMan);
@@ -222,16 +226,11 @@ Common::Error SciEngine::run() {
}
// Add the after market GM patches for the specified game, if they exist
- _resMan->addNewGMPatch(_gamestate->_gameId);
+ _resMan->addNewGMPatch(getGameID());
script_adjust_opcode_formats(_gamestate);
_kernel->loadKernelNames(getGameID());
- // Set the savegame dir (actually, we set it to a fake value,
- // since we cannot let the game control where saves are stored)
- assert(_gamestate->sys_strings->_strings[SYS_STRING_SAVEDIR]._value != 0);
- strcpy(_gamestate->sys_strings->_strings[SYS_STRING_SAVEDIR]._value, "");
-
SciVersion soundVersion = _features->detectDoSoundType();
_gamestate->_soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, soundVersion);
@@ -258,9 +257,9 @@ Common::Error SciEngine::run() {
// Check whether loading a savestate was requested
if (ConfMan.hasKey("save_slot")) {
- g_loadFromLauncher = ConfMan.getInt("save_slot");
+ _gamestate->loadFromLauncher = ConfMan.getInt("save_slot");
} else {
- g_loadFromLauncher = -1;
+ _gamestate->loadFromLauncher = -1;
}
game_run(&_gamestate); // Run the game
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index fdd10bcd04..685f05e685 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -65,7 +65,7 @@ class GfxPalette;
class GfxPorts;
class GfxScreen;
class SciGui;
-
+class GfxMacIconBar;
#ifdef ENABLE_SCI32
class SciGui32;
@@ -206,6 +206,7 @@ public:
GfxPorts *_gfxPorts; // Port managment for 16-bit gfx
GfxScreen *_gfxScreen;
SciGui *_gui; /* Currently active Gui */
+ GfxMacIconBar *_gfxMacIconBar; // Mac Icon Bar manager
#ifdef ENABLE_SCI32
SciGui32 *_gui32; // GUI for SCI32 games
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 331561eea4..7748c0505b 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -235,6 +235,7 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
uint32 audioCompressionType = audioRes->getAudioCompressionType();
if (audioCompressionType) {
+#if (defined(USE_MAD) || defined(USE_VORBIS) || defined(USE_FLAC))
// Compressed audio made by our tool
byte *compressedData = (byte *)malloc(audioRes->size);
assert(compressedData);
@@ -261,6 +262,9 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
#endif
break;
}
+#else
+ error("Compressed audio file encountered, but no appropriate decoder is compiled in");
+#endif
} else {
// Original source file
if (audioRes->_headerSize > 0) {
@@ -332,11 +336,11 @@ void AudioPlayer::setSoundSync(ResourceId id, reg_t syncObjAddr, SegManager *seg
_syncOffset = 0;
if (_syncResource) {
- PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncCue), 0);
+ writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), 0);
} else {
warning("setSoundSync: failed to find resource %s", id.toString().c_str());
// Notify the scripts to stop sound sync
- PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncCue), SIGNAL_OFFSET);
+ writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), SIGNAL_OFFSET);
}
}
@@ -352,8 +356,8 @@ void AudioPlayer::doSoundSync(reg_t syncObjAddr, SegManager *segMan) {
_syncOffset += 2;
}
- PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncTime), syncTime);
- PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncCue), syncCue);
+ writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncTime), syncTime);
+ writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), syncCue);
}
}
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index 2068ea9a33..3ee8a3a83d 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -60,6 +60,9 @@ MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion) :
_dataincToAdd = 0;
_resetOnPause = false;
_channelsUsed = 0;
+
+ for (int i = 0; i < 16; i++)
+ _channelRemap[i] = i;
}
MidiParser_SCI::~MidiParser_SCI() {
@@ -85,7 +88,6 @@ bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, in
_tracks[0] = _mixedData;
setTrack(0);
_loopTick = 0;
- _channelsUsed = 0;
if (_soundVersion <= SCI_VERSION_0_LATE) {
// Set initial voice count
@@ -120,17 +122,20 @@ void MidiParser_SCI::unloadMusic() {
// Center the pitch wheels and hold pedal in preparation for the next piece of music
if (_driver) {
for (int i = 0; i < 16; ++i) {
- if (_channelsUsed & (1 << i)) {
+ if (isChannelUsed(i)) {
_driver->send(0xE0 | i, 0, 0x40); // Reset pitch wheel
_driver->send(0xB0 | i, 0x40, 0); // Reset hold pedal
}
}
}
+
+ for (int i = 0; i < 16; i++)
+ _channelRemap[i] = i;
}
void MidiParser_SCI::parseNextEvent(EventInfo &info) {
// Monitor which channels are used by this song
- _channelsUsed |= (1 << info.channel());
+ setChannelUsed(info.channel());
// Set signal AFTER waiting for delta, otherwise we would set signal too soon resulting in all sorts of bugs
if (_dataincAdd) {
@@ -322,7 +327,7 @@ byte MidiParser_SCI::midiGetNextChannel(long ticker) {
for (int i = 0; i < _track->channelCount; i++) {
if (_track->channels[i].time == -1) // channel ended
continue;
- next = *_track->channels[i].data; // when the next event shoudl occur
+ next = *_track->channels[i].data; // when the next event should occur
if (next == 0xF8) // 0xF8 means 240 ticks delay
next = 240;
next += _track->channels[i].time;
@@ -389,9 +394,18 @@ byte *MidiParser_SCI::midiMixChannels() {
channel->time = -1; // FIXME
break;
default: // MIDI command
- if (command & 0x80)
+ if (command & 0x80) {
par1 = *channel->data++;
- else {// running status
+
+ // TODO: Fix remapping
+
+#if 0
+ // Remap channel. Keep the upper 4 bits (command code) and change
+ // the lower 4 bits (channel)
+ byte remappedChannel = _channelRemap[par1 & 0xF];
+ par1 = (par1 & 0xF0) | (remappedChannel & 0xF);
+#endif
+ } else {// running status
par1 = command;
command = channel->prev;
}
diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h
index f95c71ce2f..9d4b5a39da 100644
--- a/engines/sci/sound/midiparser_sci.h
+++ b/engines/sci/sound/midiparser_sci.h
@@ -71,7 +71,18 @@ public:
jumpToTick(0);
}
+ void remapChannel(byte channel, byte newChannel) {
+ assert(channel < 0xF); // don't touch special SCI channel 15
+ assert(newChannel < 0xF); // don't touch special SCI channel 15
+ _channelRemap[channel] = newChannel;
+ }
+
+ void clearUsedChannels() { _channelsUsed = 0; }
+
protected:
+ bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); }
+ void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); }
+
void parseNextEvent(EventInfo &info);
byte *midiMixChannels();
byte *midiFilterChannels(int channelMask);
@@ -93,6 +104,8 @@ protected:
// A 16-bit mask, containing the channels used
// by the currently parsed song
uint16 _channelsUsed;
+
+ byte _channelRemap[16];
};
} // End of namespace Sci
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 66f5ce9710..fa5716e7cc 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -37,9 +37,6 @@
namespace Sci {
-// When defined, volume fading immediately sets the final sound volume
-#define DISABLE_VOLUME_FADING
-
SciMusic::SciMusic(SciVersion soundVersion)
: _soundVersion(soundVersion), _soundOn(true), _masterVolume(0) {
@@ -115,8 +112,6 @@ void SciMusic::clearPlayList() {
}
void SciMusic::pauseAll(bool pause) {
- Common::StackLock lock(_mutex);
-
const MusicList::iterator end = _playList.end();
for (MusicList::iterator i = _playList.begin(); i != end; ++i) {
soundToggle(*i, pause);
@@ -170,14 +165,29 @@ void SciMusic::setReverb(byte reverb) {
_pMidiDrv->setReverb(reverb);
}
-static int f_compare(const void *arg1, const void *arg2) {
- return ((const MusicEntry *)arg2)->priority - ((const MusicEntry *)arg1)->priority;
+static bool musicEntryCompare(const MusicEntry *l, const MusicEntry *r) {
+ return (l->priority > r->priority);
}
void SciMusic::sortPlayList() {
- MusicEntry ** pData = _playList.begin();
- qsort(pData, _playList.size(), sizeof(MusicEntry *), &f_compare);
+ // Sort the play list in descending priority order
+ Common::sort(_playList.begin(), _playList.end(), musicEntryCompare);
}
+
+void SciMusic::findUsedChannels() {
+ // Reset list
+ for (int k = 0; k < 16; k++)
+ _usedChannels[k] = false;
+
+ const MusicList::const_iterator end = _playList.end();
+ for (MusicList::const_iterator i = _playList.begin(); i != end; ++i) {
+ for (int channel = 0; channel < 16; channel++) {
+ if ((*i)->soundRes && (*i)->soundRes->isChannelUsed(channel))
+ _usedChannels[channel] = true;
+ }
+ }
+}
+
void SciMusic::soundInitSnd(MusicEntry *pSnd) {
int channelFilterMask = 0;
SoundResource::Track *track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId());
@@ -221,6 +231,27 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
pSnd->pauseCounter = 0;
+ // TODO: Fix channel remapping. This doesn't quite work... (e.g. no difference in LSL1VGA)
+#if 0
+ // Remap channels
+ findUsedChannels();
+
+ pSnd->pMidiParser->clearUsedChannels();
+
+ for (int i = 0; i < 16; i++) {
+ if (_usedChannels[i] && pSnd->soundRes->isChannelUsed(i)) {
+ int16 newChannel = getNextUnusedChannel();
+ if (newChannel >= 0) {
+ _usedChannels[newChannel] = true;
+ debug("Remapping channel %d to %d\n", i, newChannel);
+ pSnd->pMidiParser->remapChannel(i, newChannel);
+ } else {
+ warning("Attempt to remap channel %d, but no unused channels exist", i);
+ }
+ }
+ }
+#endif
+
// Find out what channels to filter for SCI0
channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel());
pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
@@ -243,14 +274,14 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
uint playListCount = _playList.size();
uint playListNo = playListCount;
- bool alreadyPlaying = false;
+ MusicEntry *alreadyPlaying = NULL;
// searching if sound is already in _playList
for (uint i = 0; i < playListCount; i++) {
if (_playList[i] == pSnd)
playListNo = i;
if ((_playList[i]->status == kSoundPlaying) && (_playList[i]->pMidiParser))
- alreadyPlaying = true;
+ alreadyPlaying = _playList[i];
}
if (playListNo == playListCount) { // not found
_playList.push_back(pSnd);
@@ -261,13 +292,20 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
if (pSnd->pMidiParser) {
if ((_soundVersion <= SCI_VERSION_0_LATE) && (alreadyPlaying)) {
- // if any music is already playing, SCI0 queues music and plays it after the current music has finished
- // done by SoundCommandParser::updateSci0Cues()
- // Example of such case: iceman room 14
- // FIXME: this code is supposed to also take a look at priority and pause currently playing sound accordingly
- pSnd->isQueued = true;
- pSnd->status = kSoundPaused;
- return;
+ // Music already playing in SCI0?
+ if (pSnd->priority > alreadyPlaying->priority) {
+ // And new priority higher? pause previous music and play new one immediately
+ // Example of such case: lsl3, when getting points (jingle is played then)
+ soundPause(alreadyPlaying);
+ alreadyPlaying->isQueued = true;
+ } else {
+ // And new priority equal or lower? queue up music and play it afterwards done by
+ // SoundCommandParser::updateSci0Cues()
+ // Example of such case: iceman room 14
+ pSnd->isQueued = true;
+ pSnd->status = kSoundPaused;
+ return;
+ }
}
}
@@ -298,6 +336,8 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
void SciMusic::soundStop(MusicEntry *pSnd) {
pSnd->status = kSoundStopped;
+ if (_soundVersion <= SCI_VERSION_0_LATE)
+ pSnd->isQueued = false;
if (pSnd->pStreamAud)
_pMixer->stopHandle(pSnd->hCurrentAud);
@@ -380,7 +420,12 @@ void SciMusic::soundResume(MusicEntry *pSnd) {
return;
if (pSnd->status != kSoundPaused)
return;
- soundPlay(pSnd);
+ if (pSnd->pStreamAud) {
+ _pMixer->pauseHandle(pSnd->hCurrentAud, false);
+ pSnd->status = kSoundPlaying;
+ } else {
+ soundPlay(pSnd);
+ }
}
void SciMusic::soundToggle(MusicEntry *pSnd, bool pause) {
@@ -522,15 +567,17 @@ void MusicEntry::doFade() {
fadeStep = 0;
fadeCompleted = true;
}
-
- // Only process MIDI streams in this thread, not digital sound effects
- if (pMidiParser) {
-#ifdef DISABLE_VOLUME_FADING
- // Signal fading to stop...
+#ifdef ENABLE_SCI32
+ // Disable fading for SCI32 - sound drivers have issues when fading in (gabriel knight 1 sierra title)
+ if (getSciVersion() >= SCI_VERSION_2) {
volume = fadeTo;
fadeStep = 0;
fadeCompleted = true;
+ }
#endif
+
+ // Only process MIDI streams in this thread, not digital sound effects
+ if (pMidiParser) {
pMidiParser->setVolume(volume);
}
diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h
index 8f08065b99..83cd59e89b 100644
--- a/engines/sci/sound/music.h
+++ b/engines/sci/sound/music.h
@@ -197,7 +197,6 @@ public:
Common::Mutex _mutex;
protected:
- byte findAudEntry(uint16 nAud, byte&oVolume, uint32& oOffset, uint32&oSize);
void sortPlayList();
SciVersion _soundVersion;
@@ -211,10 +210,20 @@ protected:
bool _bMultiMidi;
private:
static void miditimerCallback(void *p);
+ void findUsedChannels();
+ int16 getNextUnusedChannel() const {
+ for (int i = 0; i < 16; i++) {
+ if (!_usedChannels[i])
+ return i;
+ }
+
+ return -1;
+ }
MusicList _playList;
bool _soundOn;
byte _masterVolume;
+ bool _usedChannels[16];
};
} // End of namespace Sci
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index 925f3b2e1a..ece4c1430c 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -50,9 +50,9 @@ namespace Sci {
#ifdef USE_OLD_MUSIC_FUNCTIONS
static void script_set_priority(ResourceManager *resMan, SegManager *segMan, SfxState *state, reg_t obj, int priority) {
- int song_nr = GET_SEL32V(segMan, obj, SELECTOR(number));
+ int song_nr = readSelectorValue(segMan, obj, SELECTOR(number));
Resource *song = resMan->findResource(ResourceId(kResourceTypeSound, song_nr), 0);
- int flags = GET_SEL32V(segMan, obj, SELECTOR(flags));
+ int flags = readSelectorValue(segMan, obj, SELECTOR(flags));
if (priority == -1) {
if (song->data[0] == 0xf0)
@@ -64,7 +64,7 @@ static void script_set_priority(ResourceManager *resMan, SegManager *segMan, Sfx
} else flags |= SCI1_SOUND_FLAG_SCRIPTED_PRI;
state->sfx_song_renice(FROBNICATE_HANDLE(obj), priority);
- PUT_SEL32V(segMan, obj, SELECTOR(flags), flags);
+ writeSelectorValue(segMan, obj, SELECTOR(flags), flags);
}
SongIterator *build_iterator(ResourceManager *resMan, int song_nr, SongIteratorType type, songit_id_t id) {
@@ -98,27 +98,27 @@ void process_sound_events(EngineState *s) { /* Get all sound events, apply their
case SI_LOOP:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x looped (to %d)",
PRINT_REG(obj), cue);
- /* PUT_SEL32V(segMan, obj, SELECTOR(loops), GET_SEL32V(segMan, obj, SELECTOR(loop));; - 1);*/
- PUT_SEL32V(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ /* writeSelectorValue(segMan, obj, SELECTOR(loops), readSelectorValue(segMan, obj, SELECTOR(loop));; - 1);*/
+ writeSelectorValue(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
break;
case SI_RELATIVE_CUE:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received relative cue %d",
PRINT_REG(obj), cue);
- PUT_SEL32V(segMan, obj, SELECTOR(signal), cue + 0x7f);
+ writeSelectorValue(segMan, obj, SELECTOR(signal), cue + 0x7f);
break;
case SI_ABSOLUTE_CUE:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received absolute cue %d",
PRINT_REG(obj), cue);
- PUT_SEL32V(segMan, obj, SELECTOR(signal), cue);
+ writeSelectorValue(segMan, obj, SELECTOR(signal), cue);
break;
case SI_FINISHED:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x finished",
PRINT_REG(obj));
- PUT_SEL32V(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- PUT_SEL32V(segMan, obj, SELECTOR(state), kSoundStopped);
+ writeSelectorValue(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(segMan, obj, SELECTOR(state), kSoundStopped);
break;
default:
@@ -253,7 +253,7 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
if (!obj.segment)
return;
- int resourceId = GET_SEL32V(_segMan, obj, SELECTOR(number));
+ int resourceId = readSelectorValue(_segMan, obj, SELECTOR(number));
#ifdef USE_OLD_MUSIC_FUNCTIONS
@@ -267,7 +267,7 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
SongIteratorType type = (_soundVersion <= SCI_VERSION_0_LATE) ? SCI_SONG_ITERATOR_TYPE_SCI0 : SCI_SONG_ITERATOR_TYPE_SCI1;
if (_soundVersion <= SCI_VERSION_0_LATE) {
- if (GET_SEL32V(_segMan, obj, SELECTOR(nodePtr))) {
+ if (readSelectorValue(_segMan, obj, SELECTOR(nodePtr))) {
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
_state->sfx_remove_song(handle);
}
@@ -281,11 +281,11 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
// Notify the engine
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundInitialized);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized);
else
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
- PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
+ writeSelector(_segMan, obj, SELECTOR(handle), obj);
#else
@@ -302,10 +302,10 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
newSound->soundRes = 0;
newSound->soundObj = obj;
- newSound->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
- newSound->priority = GET_SEL32V(_segMan, obj, SELECTOR(pri)) & 0xFF;
- if (_soundVersion >= SCI_VERSION_1_LATE)
- newSound->volume = CLIP<int>(GET_SEL32V(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX);
+ newSound->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
+ newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(pri)) & 0xFF;
+ if (_soundVersion >= SCI_VERSION_1_EARLY)
+ newSound->volume = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX);
// In SCI1.1 games, sound effects are started from here. If we can find
// a relevant audio resource, play it, otherwise switch to synthesized
@@ -327,11 +327,11 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
if (newSound->soundRes || newSound->pStreamAud) {
// Notify the engine
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundInitialized);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized);
else
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
- PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
+ writeSelector(_segMan, obj, SELECTOR(handle), obj);
}
#endif
@@ -346,30 +346,30 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
if (_soundVersion <= SCI_VERSION_0_LATE) {
_state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
- _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, SELECTOR(loop)));
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundPlaying);
+ _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundPlaying);
} else if (_soundVersion == SCI_VERSION_1_EARLY) {
_state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
- _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, SELECTOR(loop)));
- _state->sfx_song_renice(handle, GET_SEL32V(_segMan, obj, SELECTOR(pri)));
+ _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
+ _state->sfx_song_renice(handle, readSelectorValue(_segMan, obj, SELECTOR(pri)));
RESTORE_BEHAVIOR rb = (RESTORE_BEHAVIOR) value; /* Too lazy to look up a default value for this */
_state->_songlib.setSongRestoreBehavior(handle, rb);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
} else if (_soundVersion == SCI_VERSION_1_LATE) {
- int looping = GET_SEL32V(_segMan, obj, SELECTOR(loop));
- //int vol = GET_SEL32V(_segMan, obj, SELECTOR(vol));
- int pri = GET_SEL32V(_segMan, obj, SELECTOR(pri));
+ int looping = readSelectorValue(_segMan, obj, SELECTOR(loop));
+ //int vol = readSelectorValue(_segMan, obj, SELECTOR(vol));
+ int pri = readSelectorValue(_segMan, obj, SELECTOR(pri));
int sampleLen = 0;
Song *song = _state->_songlib.findSong(handle);
- int songNumber = GET_SEL32V(_segMan, obj, SELECTOR(number));
+ int songNumber = readSelectorValue(_segMan, obj, SELECTOR(number));
- if (GET_SEL32V(_segMan, obj, SELECTOR(nodePtr)) && (song && songNumber != song->_resourceNum)) {
+ if (readSelectorValue(_segMan, obj, SELECTOR(nodePtr)) && (song && songNumber != song->_resourceNum)) {
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
_state->sfx_remove_song(handle);
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
}
- if (!GET_SEL32V(_segMan, obj, SELECTOR(nodePtr)) && obj.segment) {
+ if (!readSelectorValue(_segMan, obj, SELECTOR(nodePtr)) && obj.segment) {
// In SCI1.1 games, sound effects are started from here. If we can find
// a relevant audio resource, play it, otherwise switch to synthesized
// effects. If the resource exists, play it using map 65535 (sound
@@ -387,7 +387,7 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
warning("Could not open song number %d", songNumber);
// Send a "stop handle" event so that the engine won't wait forever here
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
return;
}
debugC(2, kDebugLevelSound, "Initializing song number %d", songNumber);
@@ -395,15 +395,15 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
handle), 0, handle, songNumber);
}
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
- PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
+ writeSelector(_segMan, obj, SELECTOR(handle), obj);
}
if (obj.segment) {
_state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
_state->sfx_song_set_loops(handle, looping);
_state->sfx_song_renice(handle, pri);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
}
}
@@ -415,7 +415,7 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
return;
}
- int resourceId = obj.segment ? GET_SEL32V(_segMan, obj, SELECTOR(number)) : -1;
+ int resourceId = obj.segment ? readSelectorValue(_segMan, obj, SELECTOR(number)) : -1;
if (musicSlot->resourceId != resourceId) { // another sound loaded into struct
cmdDisposeSound(obj, value);
@@ -423,25 +423,25 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
// Find slot again :)
musicSlot = _music->getSlot(obj);
}
- int16 loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
+ int16 loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
debugC(2, kDebugLevelSound, "cmdPlaySound: resource number %d, loop %d", resourceId, loop);
- PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
+ writeSelector(_segMan, obj, SELECTOR(handle), obj);
if (_soundVersion >= SCI_VERSION_1_EARLY) {
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
- PUT_SEL32V(_segMan, obj, SELECTOR(min), 0);
- PUT_SEL32V(_segMan, obj, SELECTOR(sec), 0);
- PUT_SEL32V(_segMan, obj, SELECTOR(frame), 0);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), 0);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
+ writeSelectorValue(_segMan, obj, SELECTOR(min), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(sec), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(frame), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
} else {
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundPlaying);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundPlaying);
}
- musicSlot->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
- musicSlot->priority = GET_SEL32V(_segMan, obj, SELECTOR(priority));
- if (_soundVersion >= SCI_VERSION_1_LATE)
- musicSlot->volume = GET_SEL32V(_segMan, obj, SELECTOR(vol));
+ musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
+ musicSlot->priority = readSelectorValue(_segMan, obj, SELECTOR(priority));
+ if (_soundVersion >= SCI_VERSION_1_EARLY)
+ musicSlot->volume = readSelectorValue(_segMan, obj, SELECTOR(vol));
_music->soundPlay(musicSlot);
#endif
@@ -458,7 +458,7 @@ void SoundCommandParser::changeSoundStatus(reg_t obj, int newStatus) {
if (obj.segment) {
_state->sfx_song_set_status(handle, newStatus);
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(state), newStatus);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), newStatus);
}
}
#endif
@@ -475,7 +475,7 @@ void SoundCommandParser::cmdDisposeSound(reg_t obj, int16 value) {
_state->sfx_remove_song(handle);
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0x0000);
+ writeSelectorValue(_segMan, obj, SELECTOR(handle), 0x0000);
}
#else
@@ -489,11 +489,11 @@ void SoundCommandParser::cmdDisposeSound(reg_t obj, int16 value) {
cmdStopSound(obj, value);
_music->soundKill(musicSlot);
- PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
if (_soundVersion >= SCI_VERSION_1_EARLY)
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
else
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundStopped);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundStopped);
#endif
}
@@ -509,7 +509,7 @@ void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFin
changeSoundStatus(obj, SOUND_STATUS_STOPPED);
if (_soundVersion >= SCI_VERSION_1_EARLY)
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
#else
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
@@ -518,9 +518,9 @@ void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFin
}
if (_soundVersion <= SCI_VERSION_0_LATE) {
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundStopped);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundStopped);
} else {
- PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
}
// Set signal selector in sound SCI0 games only, when the sample has finished playing
@@ -530,7 +530,7 @@ void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFin
// sfx drivers included
// We need to set signal in sound SCI1+ games all the time
if ((_soundVersion > SCI_VERSION_0_LATE) || sampleFinishedPlaying)
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
musicSlot->dataInc = 0;
musicSlot->signal = 0;
@@ -565,7 +565,7 @@ void SoundCommandParser::cmdPauseSound(reg_t obj, int16 value) {
if (_soundVersion <= SCI_VERSION_0_LATE) {
// Always pause the sound in SCI0 games. It's resumed in cmdResumeSound()
- PUT_SEL32V(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPaused);
+ writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPaused);
_music->soundPause(musicSlot);
} else {
_music->soundToggle(musicSlot, value);
@@ -590,7 +590,7 @@ void SoundCommandParser::cmdResumeSound(reg_t obj, int16 value) {
return;
}
- PUT_SEL32V(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPlaying);
+ writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPlaying);
_music->soundResume(musicSlot);
#endif
}
@@ -630,13 +630,12 @@ void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) {
#ifdef USE_OLD_MUSIC_FUNCTIONS
SongHandle handle = FROBNICATE_HANDLE(obj);
if (_soundVersion != SCI_VERSION_1_LATE) {
- /*s->sound_server->command(s, SOUND_COMMAND_FADE_HANDLE, obj, 120);*/ /* Fade out in 2 secs */
/* FIXME: The next couple of lines actually STOP the handle, rather
** than fading it! */
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(state), SOUND_STATUS_STOPPED);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), SOUND_STATUS_STOPPED);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
} else {
fade_params_t fade;
fade.final_volume = _argv[2].toUint16();
@@ -651,11 +650,11 @@ void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) {
/* FIXME: The next couple of lines actually STOP the handle, rather
** than fading it! */
if (_argv[5].toUint16()) {
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
} else {
// FIXME: Support fade-and-continue. For now, send signal right away.
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
}
}
#else
@@ -692,7 +691,7 @@ void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) {
// If sound is not playing currently, set signal directly
if (musicSlot->status != kSoundPlaying) {
warning("cmdFadeSound: fading requested, but sound is currently not playing");
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
}
debugC(2, kDebugLevelSound, "cmdFadeSound: to %d, step %d, ticker %d", musicSlot->fadeTo, musicSlot->fadeStep, musicSlot->fadeTickerStep);
@@ -714,8 +713,8 @@ void SoundCommandParser::cmdUpdateSound(reg_t obj, int16 value) {
#ifdef USE_OLD_MUSIC_FUNCTIONS
SongHandle handle = FROBNICATE_HANDLE(obj);
if (_soundVersion <= SCI_VERSION_0_LATE && obj.segment) {
- _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, SELECTOR(loop)));
- script_set_priority(_resMan, _segMan, _state, obj, GET_SEL32V(_segMan, obj, SELECTOR(pri)));
+ _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
+ script_set_priority(_resMan, _segMan, _state, obj, readSelectorValue(_segMan, obj, SELECTOR(pri)));
}
#else
MusicEntry *musicSlot = _music->getSlot(obj);
@@ -724,11 +723,11 @@ void SoundCommandParser::cmdUpdateSound(reg_t obj, int16 value) {
return;
}
- musicSlot->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
- int16 objVol = CLIP<int>(GET_SEL32V(_segMan, obj, SELECTOR(vol)), 0, 255);
+ musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
+ int16 objVol = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, 255);
if (objVol != musicSlot->volume)
_music->soundSetVolume(musicSlot, objVol);
- uint32 objPrio = GET_SEL32V(_segMan, obj, SELECTOR(pri));
+ uint32 objPrio = readSelectorValue(_segMan, obj, SELECTOR(pri));
if (objPrio != musicSlot->priority)
_music->soundSetPriority(musicSlot, objPrio);
@@ -755,7 +754,7 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
debugC(2, kDebugLevelSound, "--- [CUE] %04x:%04x Absolute Cue: %d",
PRINT_REG(obj), signal);
debugC(2, kDebugLevelSound, "abs-signal %04X", signal);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), signal);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), signal);
break;
case SI_RELATIVE_CUE:
@@ -765,17 +764,17 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
/* FIXME to match commented-out semantics
* below, with proper storage of dataInc and
* signal in the iterator code. */
- PUT_SEL32V(_segMan, obj, SELECTOR(dataInc), signal);
+ writeSelectorValue(_segMan, obj, SELECTOR(dataInc), signal);
debugC(2, kDebugLevelSound, "rel-signal %04X", signal);
if (_soundVersion == SCI_VERSION_1_EARLY)
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), signal);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), signal);
else
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), signal + 127);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), signal + 127);
break;
case SI_FINISHED:
debugC(2, kDebugLevelSound, "--- [FINISHED] %04x:%04x", PRINT_REG(obj));
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
break;
case SI_LOOP:
@@ -784,30 +783,30 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
//switch (signal) {
//case 0x00:
- // if (dataInc != GET_SEL32V(segMan, obj, SELECTOR(dataInc))) {
- // PUT_SEL32V(segMan, obj, SELECTOR(dataInc), dataInc);
- // PUT_SEL32V(segMan, obj, SELECTOR(signal), dataInc+0x7f);
+ // if (dataInc != readSelectorValue(segMan, obj, SELECTOR(dataInc))) {
+ // writeSelectorValue(segMan, obj, SELECTOR(dataInc), dataInc);
+ // writeSelectorValue(segMan, obj, SELECTOR(signal), dataInc+0x7f);
// } else {
- // PUT_SEL32V(segMan, obj, SELECTOR(signal), signal);
+ // writeSelectorValue(segMan, obj, SELECTOR(signal), signal);
// }
// break;
//case 0xFF: // May be unnecessary
// s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
// break;
//default :
- // if (dataInc != GET_SEL32V(segMan, obj, SELECTOR(dataInc))) {
- // PUT_SEL32V(segMan, obj, SELECTOR(dataInc), dataInc);
- // PUT_SEL32V(segMan, obj, SELECTOR(signal), dataInc + 0x7f);
+ // if (dataInc != readSelectorValue(segMan, obj, SELECTOR(dataInc))) {
+ // writeSelectorValue(segMan, obj, SELECTOR(dataInc), dataInc);
+ // writeSelectorValue(segMan, obj, SELECTOR(signal), dataInc + 0x7f);
// } else {
- // PUT_SEL32V(segMan, obj, SELECTOR(signal), signal);
+ // writeSelectorValue(segMan, obj, SELECTOR(signal), signal);
// }
// break;
//}
if (_soundVersion == SCI_VERSION_1_EARLY) {
- PUT_SEL32V(_segMan, obj, SELECTOR(min), min);
- PUT_SEL32V(_segMan, obj, SELECTOR(sec), sec);
- PUT_SEL32V(_segMan, obj, SELECTOR(frame), frame);
+ writeSelectorValue(_segMan, obj, SELECTOR(min), min);
+ writeSelectorValue(_segMan, obj, SELECTOR(sec), sec);
+ writeSelectorValue(_segMan, obj, SELECTOR(frame), frame);
}
#else
MusicEntry *musicSlot = _music->getSlot(obj);
@@ -828,7 +827,7 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
musicSlot->loop -= currentLoopCounter - musicSlot->sampleLoopCounter;
musicSlot->sampleLoopCounter = currentLoopCounter;
}
- if (!_music->soundIsActive(musicSlot)) {
+ if ((!_music->soundIsActive(musicSlot)) && (musicSlot->status != kSoundPaused)) {
processStopSound(obj, 0, true);
} else {
_music->updateAudioStreamTicker(musicSlot);
@@ -841,14 +840,14 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
} else if (musicSlot->pMidiParser) {
// Update MIDI slots
if (musicSlot->signal == 0) {
- if (musicSlot->dataInc != GET_SEL32V(_segMan, obj, SELECTOR(dataInc))) {
+ if (musicSlot->dataInc != readSelectorValue(_segMan, obj, SELECTOR(dataInc))) {
if (_kernel->_selectorCache.dataInc > -1)
- PUT_SEL32V(_segMan, obj, SELECTOR(dataInc), musicSlot->dataInc);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), musicSlot->dataInc + 127);
+ writeSelectorValue(_segMan, obj, SELECTOR(dataInc), musicSlot->dataInc);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), musicSlot->dataInc + 127);
}
} else {
// Sync the signal of the sound object
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), musicSlot->signal);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), musicSlot->signal);
// We need to do this especially because state selector needs to get updated
if (musicSlot->signal == SIGNAL_OFFSET)
cmdStopSound(obj, 0);
@@ -856,14 +855,14 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
} else {
// Slot actually has no data (which would mean that a sound-resource w/ unsupported data is used
// (example lsl5 - sound resource 744 - it's roland exclusive
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
// If we don't set signal here, at least the switch to the mud wrestling room in lsl5 will not work
}
if (musicSlot->fadeCompleted) {
musicSlot->fadeCompleted = false;
// We need signal for sci0 at least in iceman as well (room 14, fireworks)
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
if (_soundVersion <= SCI_VERSION_0_LATE) {
cmdStopSound(obj, 0);
} else {
@@ -874,14 +873,14 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
// Sync loop selector for SCI0
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(loop), musicSlot->loop);
+ writeSelectorValue(_segMan, obj, SELECTOR(loop), musicSlot->loop);
musicSlot->signal = 0;
if (_soundVersion >= SCI_VERSION_1_EARLY) {
- PUT_SEL32V(_segMan, obj, SELECTOR(min), musicSlot->ticker / 3600);
- PUT_SEL32V(_segMan, obj, SELECTOR(sec), musicSlot->ticker % 3600 / 60);
- PUT_SEL32V(_segMan, obj, SELECTOR(frame), musicSlot->ticker);
+ writeSelectorValue(_segMan, obj, SELECTOR(min), musicSlot->ticker / 3600);
+ writeSelectorValue(_segMan, obj, SELECTOR(sec), musicSlot->ticker % 3600 / 60);
+ writeSelectorValue(_segMan, obj, SELECTOR(frame), musicSlot->ticker);
}
#endif
@@ -927,18 +926,13 @@ void SoundCommandParser::cmdStopAllSounds(reg_t obj, int16 value) {
#ifndef USE_OLD_MUSIC_FUNCTIONS
Common::StackLock(_music->_mutex);
- // FIXME: this can't be right, it's called in iceman (room 14) when the door sound has done playing
- // stopping sounds can't be right, because music is starting afterwards in ssci. can't be resume queued
- // song(s), because music is playing even when this call is nuked inside ssci.
- return;
-
const MusicList::iterator end = _music->getPlayListEnd();
for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) {
if (_soundVersion <= SCI_VERSION_0_LATE) {
- PUT_SEL32V(_segMan, (*i)->soundObj, SELECTOR(state), kSoundStopped);
+ writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(state), kSoundStopped);
} else {
- PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0);
- PUT_SEL32V(_segMan, (*i)->soundObj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
+ writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(signal), SIGNAL_OFFSET);
}
(*i)->dataInc = 0;
@@ -969,7 +963,7 @@ void SoundCommandParser::cmdSetSoundVolume(reg_t obj, int16 value) {
if (musicSlot->volume != value) {
musicSlot->volume = value;
_music->soundSetVolume(musicSlot, value);
- PUT_SEL32V(_segMan, obj, SELECTOR(vol), value);
+ writeSelectorValue(_segMan, obj, SELECTOR(vol), value);
}
#endif
}
@@ -996,12 +990,12 @@ void SoundCommandParser::cmdSetSoundPriority(reg_t obj, int16 value) {
warning("cmdSetSoundPriority: Attempt to unset song priority when there is no built-in value");
//pSnd->prio=0;field_15B=0
- PUT_SEL32V(_segMan, obj, SELECTOR(flags), GET_SEL32V(_segMan, obj, SELECTOR(flags)) & 0xFD);
+ writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) & 0xFD);
} else {
// Scripted priority
//pSnd->field_15B=1;
- PUT_SEL32V(_segMan, obj, SELECTOR(flags), GET_SEL32V(_segMan, obj, SELECTOR(flags)) | 2);
+ writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) | 2);
//DoSOund(0xF,hobj,w)
}
#endif
@@ -1012,7 +1006,7 @@ void SoundCommandParser::cmdSetSoundLoop(reg_t obj, int16 value) {
return;
#ifdef USE_OLD_MUSIC_FUNCTIONS
- if (!GET_SEL32(_segMan, obj, SELECTOR(nodePtr)).isNull()) {
+ if (!readSelector(_segMan, obj, SELECTOR(nodePtr)).isNull()) {
SongHandle handle = FROBNICATE_HANDLE(obj);
_state->sfx_song_set_loops(handle, value);
}
@@ -1037,7 +1031,7 @@ void SoundCommandParser::cmdSetSoundLoop(reg_t obj, int16 value) {
musicSlot->loop = 1; // actually plays the music once
}
- PUT_SEL32V(_segMan, obj, SELECTOR(loop), musicSlot->loop);
+ writeSelectorValue(_segMan, obj, SELECTOR(loop), musicSlot->loop);
#endif
}
@@ -1058,8 +1052,11 @@ void SoundCommandParser::updateSci0Cues() {
for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) {
// Is the sound stopped, and the sound object updated too? If yes, skip
// this sound, as SCI0 only allows one active song
- if (((*i)->isQueued) && (!pWaitingForPlay)) {
+ if ((*i)->isQueued) {
pWaitingForPlay = (*i);
+ // FIXME (?) - in iceman 2 songs are queued when playing the door sound - if we use the first song for resuming
+ // then it's the wrong one. Both songs have same priority. Maybe the new sound function in sci0
+ // is somehow responsible
continue;
}
if ((*i)->signal == 0 && (*i)->status != kSoundPlaying)
@@ -1105,11 +1102,11 @@ void SoundCommandParser::reconstructPlayList(int savegame_version) {
}
if ((*i)->status == kSoundPlaying) {
if (savegame_version < 14) {
- (*i)->dataInc = GET_SEL32V(_segMan, (*i)->soundObj, SELECTOR(dataInc));
- (*i)->signal = GET_SEL32V(_segMan, (*i)->soundObj, SELECTOR(signal));
+ (*i)->dataInc = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(dataInc));
+ (*i)->signal = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(signal));
if (_soundVersion >= SCI_VERSION_1_LATE)
- (*i)->volume = GET_SEL32V(_segMan, (*i)->soundObj, SELECTOR(vol));
+ (*i)->volume = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(vol));
}
cmdPlaySound((*i)->soundObj, 0);
@@ -1145,7 +1142,7 @@ void SoundCommandParser::startNewSound(int number) {
MusicEntry *song = *_music->getPlayListStart();
reg_t soundObj = song->soundObj;
cmdDisposeSound(soundObj, 0);
- PUT_SEL32V(_segMan, soundObj, SELECTOR(number), number);
+ writeSelectorValue(_segMan, soundObj, SELECTOR(number), number);
cmdInitSound(soundObj, 0);
cmdPlaySound(soundObj, 0);
#endif
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 757171b24c..0e0c0e129e 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -845,7 +845,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
offsX = offsY = 0;
} else {
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
- assert(charOffs < 0x10000);
+ assert(charOffs < 0x14000);
if (!charOffs)
return;
charPtr = _fontPtr + charOffs;
diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp
index a0975839d6..ea29e25a1f 100644
--- a/engines/scumm/debugger.cpp
+++ b/engines/scumm/debugger.cpp
@@ -870,7 +870,7 @@ bool ScummDebugger::Cmd_Passcode(int argc, const char **argv) {
_detach_now = true;
} else {
- DebugPrintf("Use 'passcode <SEGA CD Passcode>'\n");
+ DebugPrintf("Current Passcode is %d \nUse 'passcode <SEGA CD Passcode>'\n",_vm->_scummVars[411]);
return true;
}
return false;
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 1f153094c1..d9c24ddca2 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -233,19 +233,6 @@ protected:
#endif
-class ConfigDialog : public GUI::OptionsDialog {
-protected:
-#ifdef SMALL_SCREEN_DEVICE
- GUI::Dialog *_keysDialog;
-#endif
-
-public:
- ConfigDialog();
- ~ConfigDialog();
-
- virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
-};
-
#pragma mark -
ScummDialog::ScummDialog(int x, int y, int w, int h) : GUI::Dialog(x, y, w, h) {
@@ -258,223 +245,31 @@ ScummDialog::ScummDialog(String name) : GUI::Dialog(name) {
#pragma mark -
-enum {
- kSaveCmd = 'SAVE',
- kLoadCmd = 'LOAD',
- kPlayCmd = 'PLAY',
- kOptionsCmd = 'OPTN',
- kHelpCmd = 'HELP',
- kAboutCmd = 'ABOU',
- kQuitCmd = 'QUIT',
- kChooseCmd = 'CHOS'
-};
-
-ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm)
- : ScummDialog("ScummMain"), _vm(scumm) {
-
- new GUI::ButtonWidget(this, "ScummMain.Resume", "Resume", kPlayCmd, 'P');
-
- _loadButton = new GUI::ButtonWidget(this, "ScummMain.Load", "Load", kLoadCmd, 'L');
- _saveButton = new GUI::ButtonWidget(this, "ScummMain.Save", "Save", kSaveCmd, 'S');
-
- new GUI::ButtonWidget(this, "ScummMain.Options", "Options", kOptionsCmd, 'O');
#ifndef DISABLE_HELP
- new GUI::ButtonWidget(this, "ScummMain.Help", "Help", kHelpCmd, 'H');
-#endif
- new GUI::ButtonWidget(this, "ScummMain.About", "About", kAboutCmd, 'A');
-
- new GUI::ButtonWidget(this, "ScummMain.Quit", "Quit", kQuitCmd, 'Q');
- //
- // Create the sub dialog(s)
- //
- _aboutDialog = new GUI::AboutDialog();
- _optionsDialog = new ConfigDialog();
-#ifndef DISABLE_HELP
+ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm)
+ : MainMenuDialog(scumm) {
_helpDialog = new HelpDialog(scumm->_game);
-#endif
- _saveDialog = new GUI::SaveLoadChooser("Save game:", "Save");
- _saveDialog->setSaveMode(true);
- _loadDialog = new GUI::SaveLoadChooser("Load game:", "Load");
- _loadDialog->setSaveMode(false);
+ _helpButton->setEnabled(true);
}
ScummMenuDialog::~ScummMenuDialog() {
- delete _aboutDialog;
- delete _optionsDialog;
-#ifndef DISABLE_HELP
delete _helpDialog;
-#endif
- delete _saveDialog;
- delete _loadDialog;
-}
-
-int ScummMenuDialog::runModal() {
- _loadButton->setEnabled(_vm->canLoadGameStateCurrently());
- _saveButton->setEnabled(_vm->canSaveGameStateCurrently());
- return ScummDialog::runModal();
-}
-
-void ScummMenuDialog::reflowLayout() {
- _loadButton->setEnabled(_vm->canLoadGameStateCurrently());
- _saveButton->setEnabled(_vm->canSaveGameStateCurrently());
- Dialog::reflowLayout();
}
void ScummMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
- case kSaveCmd:
- save();
- break;
- case kLoadCmd:
- load();
- break;
- case kPlayCmd:
- close();
- break;
- case kOptionsCmd:
- _optionsDialog->runModal();
- break;
- case kAboutCmd:
- _aboutDialog->runModal();
- break;
-#ifndef DISABLE_HELP
case kHelpCmd:
_helpDialog->runModal();
break;
-#endif
- case kQuitCmd:
- _vm->quitGame();
- close();
- break;
default:
- ScummDialog::handleCommand(sender, cmd, data);
- }
-}
-
-void ScummMenuDialog::save() {
- Common::String gameId = ConfMan.get("gameid");
-
- const EnginePlugin *plugin = 0;
- EngineMan.findGame(gameId, &plugin);
-
- int idx = _saveDialog->runModal(plugin, ConfMan.getActiveDomainName());
- if (idx >= 0) {
- String result(_saveDialog->getResultString());
- char buffer[20];
- const char *str;
- if (result.empty()) {
- // If the user was lazy and entered no save name, come up with a default name.
- sprintf(buffer, "Save %d", idx);
- str = buffer;
- } else
- str = result.c_str();
- _vm->requestSave(idx, str);
- close();
- }
-}
-
-void ScummMenuDialog::load() {
- Common::String gameId = ConfMan.get("gameid");
-
- const EnginePlugin *plugin = 0;
- EngineMan.findGame(gameId, &plugin);
-
- int idx = _loadDialog->runModal(plugin, ConfMan.getActiveDomainName());
- if (idx >= 0) {
- _vm->requestLoad(idx);
- close();
+ MainMenuDialog::handleCommand(sender, cmd, data);
}
}
#pragma mark -
enum {
- kKeysCmd = 'KEYS'
-};
-
-// FIXME: We use the empty string as domain name here. This tells the
-// ConfigManager to use the 'default' domain for all its actions. We do that
-// to get as close as possible to editing the 'active' settings.
-//
-// However, that requires bad & evil hacks in the ConfigManager code,
-// and even then still doesn't work quite correctly.
-// For example, if the transient domain contains 'false' for the 'fullscreen'
-// flag, but the user used a hotkey to switch to windowed mode, then the dialog
-// will display the wrong value anyway.
-//
-// Proposed solution consisting of multiple steps:
-// 1) Add special code to the open() code that reads out everything stored
-// in the transient domain that is controlled by this dialog, and updates
-// the dialog accordingly.
-// 2) Even more code is added to query the backend for current settings, like
-// the fullscreen mode flag etc., and also updates the dialog accordingly.
-// 3) The domain being edited is set to the active game domain.
-// 4) If the dialog is closed with the "OK" button, then we remove everything
-// stored in the transient domain (or at least everything corresponding to
-// switches in this dialog.
-// If OTOH the dialog is closed with "Cancel" we do no such thing.
-//
-// These changes will achieve two things at once: Allow us to get rid of using
-// "" as value for the domain, and in fact provide a somewhat better user
-// experience at the same time.
-ConfigDialog::ConfigDialog()
- : GUI::OptionsDialog("", "ScummConfig") {
-
- //
- // Sound controllers
- //
-
- addVolumeControls(this, "ScummConfig.");
-
- //
- // Some misc options
- //
-
- // SCUMM has a talkspeed range of 0-9
- addSubtitleControls(this, "ScummConfig.", 9);
-
- //
- // Add the buttons
- //
-
- new GUI::ButtonWidget(this, "ScummConfig.Ok", "OK", GUI::kOKCmd, 'O');
- new GUI::ButtonWidget(this, "ScummConfig.Cancel", "Cancel", GUI::kCloseCmd, 'C');
-#ifdef SMALL_SCREEN_DEVICE
- new GUI::ButtonWidget(this, "ScummConfig.Keys", "Keys", kKeysCmd, 'K');
- _keysDialog = NULL;
-#endif
-}
-
-ConfigDialog::~ConfigDialog() {
-#ifdef SMALL_SCREEN_DEVICE
- delete _keysDialog;
-#endif
-}
-
-void ConfigDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
- switch (cmd) {
- case kKeysCmd:
-#ifdef SMALL_SCREEN_DEVICE
- //
- // Create the sub dialog(s)
- //
- _keysDialog = new GUI::KeysDialog();
- _keysDialog->runModal();
- delete _keysDialog;
- _keysDialog = NULL;
-#endif
- break;
- default:
- GUI::OptionsDialog::handleCommand (sender, cmd, data);
- }
-}
-
-#ifndef DISABLE_HELP
-
-#pragma mark -
-
-enum {
kNextCmd = 'NEXT',
kPrevCmd = 'PREV'
};
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 7889027dcf..41a8ec83c1 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -27,9 +27,8 @@
#include "common/str.h"
#include "gui/dialog.h"
-#include "gui/options.h"
#include "gui/widget.h"
-#include "gui/saveload.h"
+#include "engines/dialogs.h"
#include "scumm/detection.h"
@@ -52,32 +51,17 @@ protected:
typedef Common::String String;
};
-class ScummMenuDialog : public ScummDialog {
+#ifndef DISABLE_HELP
+class ScummMenuDialog : public MainMenuDialog {
public:
ScummMenuDialog(ScummEngine *scumm);
~ScummMenuDialog();
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
- virtual void reflowLayout();
-
- int runModal();
protected:
- ScummEngine *_vm;
-
- GUI::Dialog *_aboutDialog;
- GUI::Dialog *_optionsDialog;
-#ifndef DISABLE_HELP
GUI::Dialog *_helpDialog;
-#endif
- GUI::SaveLoadChooser *_saveDialog;
- GUI::SaveLoadChooser *_loadDialog;
-
- GUI::ButtonWidget *_loadButton;
- GUI::ButtonWidget *_saveButton;
-
- void save();
- void load();
};
+#endif
/**
* A dialog which displays an arbitrary message to the user and returns
diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp
index 886ee99e57..c259c3ffd2 100644
--- a/engines/scumm/he/resource_he.cpp
+++ b/engines/scumm/he/resource_he.cpp
@@ -633,8 +633,10 @@ Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary
wr[c].children = fi->first_resource + (FROM_LE_32(dirent[c].offset_to_data) & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY);
/* fill in wr->id, wr->numeric_id */
- if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name)))
+ if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name))) {
+ free(wr);
return NULL;
+ }
}
return wr;
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 8a9570f534..dc3a5d26b3 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -508,7 +508,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, 0);
- scummMenuDialog(); // Display GUI
+ openMainMenuDialog(); // Display global main menu
if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, 0);
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index 9b7e0798eb..cc382d9621 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -1,5 +1,5 @@
/*
- This file was generated by the md5table tool on Sun May 9 20:53:55 2010
+ This file was generated by the md5table tool on Mon May 24 13:24:24 2010
DO NOT EDIT MANUALLY!
*/
@@ -170,11 +170,13 @@ static const MD5Table md5table[] = {
{ "3af61c5edf8e15b43dbafd285b2e9777", "puttcircus", "", "Demo", -1, Common::HE_ISR, Common::kPlatformWindows },
{ "3b301b7892f883ce42ab4be6a274fea6", "samnmax", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformPC },
{ "3b832f4a90740bf22e9b8ed42ca0128c", "freddi4", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows },
+ { "3c4c471342bd95505a42334367d8f127", "puttmoon", "HE 70", "", 12161, Common::RU_RUS, Common::kPlatformWindows },
{ "3cce1913a3bc586b51a75c3892ff18dd", "indy3", "VGA", "VGA", -1, Common::RU_RUS, Common::kPlatformPC },
{ "3d219e7546039543307b55a91282bf18", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatformPC },
{ "3de99ef0523f8ca7958faa3afccd035a", "spyfox", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "3df6ead57930488bc61e6e41901d0e97", "fbear", "HE 62", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
{ "3e48298920fab9b7aec5a971e1bd1fab", "pajama3", "", "Demo", -1, Common::EN_GRB, Common::kPlatformWindows },
+ { "3e861421f494711bc6f619d4aba60285", "airport", "", "", 93231, Common::RU_RUS, Common::kPlatformWindows },
{ "40564ec47da48a67787d1f9bd043902a", "maniac", "V2 Demo", "V2 Demo", 1988, Common::EN_ANY, Common::kPlatformPC },
{ "4167a92a1d46baa4f4127d918d561f88", "tentacle", "", "CD", 7932, Common::EN_ANY, Common::kPlatformUnknown },
{ "41958e24d03181ff9a381a66d048a581", "ft", "", "", -1, Common::PT_BRA, Common::kPlatformUnknown },
@@ -243,6 +245,7 @@ static const MD5Table md5table[] = {
{ "5bd335265a61caa3d78956ad9f88ba23", "football", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown },
{ "5c21fc49aee8f46e58fef21579e614a1", "thinker1", "", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "5d88b9d6a88e6f8e90cded9d01b7f082", "loom", "VGA", "VGA", 8307, Common::EN_ANY, Common::kPlatformPC },
+ { "5dda73606533d66a4c3f4f9ea6e842af", "farm", "", "", 87061, Common::RU_RUS, Common::kPlatformWindows },
{ "5e8fb66971a60e523e5afbc4c129c0e8", "socks", "HE 85", "", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "5ebb57234b2fe5c5dff641e00184ad81", "freddi", "HE 73", "", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "5fbe557049892eb4b709d90916ec97ca", "indy3", "EGA", "EGA", 5361, Common::EN_ANY, Common::kPlatformPC },
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 2359d4a04f..bb50ce7bb2 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -108,7 +108,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_language(dr.language),
_debugger(0),
_currentScript(0xFF), // Let debug() work on init stage
- _messageDialog(0), _pauseDialog(0), _scummMenuDialog(0), _versionDialog(0) {
+ _messageDialog(0), _pauseDialog(0), _versionDialog(0) {
if (_game.platform == Common::kPlatformNES) {
_gdi = new GdiNES(this);
@@ -140,7 +140,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_fileHandle = 0;
-
// Init all vars
_v0ObjectIndex = false;
_v0ObjectInInventory = false;
@@ -152,7 +151,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_sound = NULL;
memset(&vm, 0, sizeof(vm));
_pauseDialog = NULL;
- _scummMenuDialog = NULL;
_versionDialog = NULL;
_fastMode = 0;
_actors = NULL;
@@ -552,6 +550,12 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
for (int i = 0; i < ARRAYSIZE(debugChannels); ++i)
DebugMan.addDebugChannel(debugChannels[i].flag, debugChannels[i].channel, debugChannels[i].desc);
+#ifndef DISABLE_HELP
+ // Create custom GMM dialog providing a help subdialog
+ assert(!_mainMenuDialog);
+ _mainMenuDialog = new ScummMenuDialog(this);
+#endif
+
g_eventRec.registerRandomSource(_rnd, "scumm");
}
@@ -572,7 +576,6 @@ ScummEngine::~ScummEngine() {
delete _charset;
delete _messageDialog;
delete _pauseDialog;
- delete _scummMenuDialog;
delete _versionDialog;
delete _fileHandle;
@@ -2437,13 +2440,6 @@ void ScummEngine::versionDialog() {
runDialog(*_versionDialog);
}
-void ScummEngine::scummMenuDialog() {
- if (!_scummMenuDialog)
- _scummMenuDialog = new ScummMenuDialog(this);
- runDialog(*_scummMenuDialog);
- syncSoundSettings();
-}
-
void ScummEngine::confirmExitDialog() {
ConfirmDialog d(this, 6);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 885ab790de..42322ba5a2 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -530,7 +530,6 @@ protected:
Dialog *_pauseDialog;
Dialog *_messageDialog;
Dialog *_versionDialog;
- Dialog *_scummMenuDialog;
virtual int runDialog(Dialog &dialog);
void confirmExitDialog();
@@ -538,7 +537,6 @@ protected:
void pauseDialog();
void messageDialog(const char *message);
void versionDialog();
- void scummMenuDialog();
char displayMessage(const char *altButton, const char *message, ...) GCC_PRINTF(3, 4);
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index c0e7be7758..441e622184 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -23,7 +23,6 @@
*
*/
-
#include "common/file.h"
#include "sword1/sword1.h"
#include "sword1/animation.h"
@@ -72,6 +71,9 @@ MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSys
_bgSoundStream = NULL;
_decoderType = decoderType;
_decoder = decoder;
+
+ _white = 255;
+ _black = 0;
}
MoviePlayer::~MoviePlayer() {
@@ -254,9 +256,35 @@ bool MoviePlayer::playVideo() {
if (frame)
_vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
- if (_decoder->hasDirtyPalette())
+ if (_decoder->hasDirtyPalette()) {
_decoder->setSystemPalette();
+ uint32 maxWeight = 0;
+ uint32 minWeight = 0xFFFFFFFF;
+ uint32 weight;
+ byte r, g, b;
+
+ byte *palette = _decoder->getPalette();
+
+ for (int i = 0; i < 256; i++) {
+ r = *palette++;
+ g = *palette++;
+ b = *palette++;
+
+ weight = 3 * r * r + 6 * g * g + 2 * b * b;
+
+ if (weight >= maxWeight) {
+ maxWeight = weight;
+ _white = i;
+ }
+
+ if (weight <= minWeight) {
+ minWeight = weight;
+ _black = i;
+ }
+ }
+ }
+
Graphics::Surface *screen = _vm->_system->lockScreen();
performPostProcessing((byte *)screen->pixels);
_vm->_system->unlockScreen();
@@ -267,17 +295,19 @@ bool MoviePlayer::playVideo() {
while (_vm->_system->getEventManager()->pollEvent(event))
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
return false;
+
+ _vm->_system->delayMillis(10);
}
return !_vm->shouldQuit();
}
byte MoviePlayer::findBlackPalIndex() {
- return 0;
+ return _black;
}
byte MoviePlayer::findWhitePalIndex() {
- return 0xff;
+ return _white;
}
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h
index 82343f2800..193d5cf7ca 100644
--- a/engines/sword1/animation.h
+++ b/engines/sword1/animation.h
@@ -85,6 +85,7 @@ protected:
OSystem *_system;
Common::Array<MovieText *> _movieTexts;
int _textX, _textY, _textWidth, _textHeight;
+ byte _white, _black;
DecoderType _decoderType;
Graphics::VideoDecoder *_decoder;
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index c3f3e796b2..10895b2ec1 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -51,6 +51,9 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, A
_bgSoundStream = NULL;
_decoderType = decoderType;
_decoder = decoder;
+
+ _white = 255;
+ _black = 0;
}
MoviePlayer:: ~MoviePlayer() {
@@ -280,9 +283,35 @@ bool MoviePlayer::playVideo() {
if (frame)
_vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
- if (_decoder->hasDirtyPalette())
+ if (_decoder->hasDirtyPalette()) {
_decoder->setSystemPalette();
+ uint32 maxWeight = 0;
+ uint32 minWeight = 0xFFFFFFFF;
+ uint32 weight;
+ byte r, g, b;
+
+ byte *palette = _decoder->getPalette();
+
+ for (int i = 0; i < 256; i++) {
+ r = *palette++;
+ g = *palette++;
+ b = *palette++;
+
+ weight = 3 * r * r + 6 * g * g + 2 * b * b;
+
+ if (weight >= maxWeight) {
+ maxWeight = weight;
+ _white = i;
+ }
+
+ if (weight <= minWeight) {
+ minWeight = weight;
+ _black = i;
+ }
+ }
+ }
+
Graphics::Surface *screen = _vm->_system->lockScreen();
performPostProcessing((byte *)screen->pixels);
_vm->_system->unlockScreen();
@@ -293,17 +322,19 @@ bool MoviePlayer::playVideo() {
while (_vm->_system->getEventManager()->pollEvent(event))
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
return false;
+
+ _vm->_system->delayMillis(10);
}
return !_vm->shouldQuit();
}
byte MoviePlayer::findBlackPalIndex() {
- return 0;
+ return _black;
}
byte MoviePlayer::findWhitePalIndex() {
- return 0xff;
+ return _white;
}
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index bbf83e264c..ee32b1d5f2 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -87,6 +87,7 @@ protected:
uint32 _currentMovieText;
byte *_textSurface;
int _textX, _textY;
+ byte _white, _black;
DecoderType _decoderType;
Graphics::VideoDecoder *_decoder;
diff --git a/engines/testbed/gfxtests.cpp b/engines/testbed/gfxtests.cpp
index 092e56ab39..2eeb7125b2 100644
--- a/engines/testbed/gfxtests.cpp
+++ b/engines/testbed/gfxtests.cpp
@@ -1,8 +1,10 @@
#include "testbed/gfxtests.h"
+#include "testbed/graphics.h"
#include "testbed/testsuite.h"
#include "graphics/fontman.h"
#include "graphics/surface.h"
+#include "graphics/cursorman.h"
namespace Testbed {
@@ -13,13 +15,13 @@ bool testFullScreenMode() {
Common::Point pt(0,100);
Common::Rect rect = Testsuite::writeOnScreen("Testing fullscreen mode", pt);
- g_system->delayMillis(1000);
bool isFeaturePresent;
bool isFeatureEnabled;
isFeaturePresent = g_system->hasFeature(OSystem::kFeatureFullscreenMode);
isFeatureEnabled = g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
+ g_system->delayMillis(1000);
if (isFeaturePresent) {
//Toggle
@@ -43,7 +45,96 @@ bool testFullScreenMode() {
}
bool testAspectRatio() {
+ Testsuite::displayMessage("Testing Aspect Ratio Correction. \n \
+ With this feature enabled games running at 320x200 should be scaled upto 320x240 pixels");
+
+ Common::Point pt(0,100);
+ Common::Rect rect = Testsuite::writeOnScreen("Testing Aspect ratio correction", pt);
+
+ bool isFeaturePresent;
+ bool isFeatureEnabled;
+
+ isFeaturePresent = g_system->hasFeature(OSystem::kFeatureAspectRatioCorrection);
+ isFeatureEnabled = g_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection);
+ g_system->delayMillis(1000);
+
+ if (isFeaturePresent) {
+ //Toggle
+
+ g_system->beginGFXTransaction();
+ g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, !isFeatureEnabled);
+ g_system->endGFXTransaction();
+
+ g_system->delayMillis(1000);
+
+ g_system->beginGFXTransaction();
+ g_system->setFeatureState(OSystem::kFeatureAspectRatioCorrection, isFeatureEnabled);
+ g_system->endGFXTransaction();
+ }
+ else {
+ Testsuite::displayMessage("feature not supported");
+ }
+
+ Testsuite::clearScreen(rect);
return true;
}
+bool testPalettizedCursors() {
+ Testsuite::displayMessage("Testing Cursors. You should expect to see a red colored cursor.\n");
+
+ Common::Point pt(0,100);
+ Common::Rect rect = Testsuite::writeOnScreen("Testing Palettized Cursors", pt);
+
+ bool isFeaturePresent;
+ bool isFeatureEnabled;
+
+ isFeaturePresent = g_system->hasFeature(OSystem::kFeatureCursorHasPalette);
+ isFeatureEnabled = g_system->getFeatureState(OSystem::kFeatureCursorHasPalette);
+ g_system->delayMillis(1000);
+
+ if (isFeaturePresent) {
+ byte palette[3 * 4]; // Black, white and yellow
+ palette[0] = palette[1] = palette[2] = 0;
+ palette[4] = palette[5] = palette[6] = 255;
+ palette[8] = palette[9] = 255;
+ palette[10] = 0;
+
+ byte buffer[10 * 10];
+ memset(buffer, 2, 10 * 10);
+
+ CursorMan.pushCursorPalette(palette, 0, 3);
+ CursorMan.pushCursor(buffer, 10, 10, 40, 40, 2, 1);
+ CursorMan.showMouse(true);
+ g_system->updateScreen();
+ }
+ else {
+ Testsuite::displayMessage("feature not supported");
+ }
+ Testsuite::clearScreen(rect);
+ return true;
+}
+
+bool testCopyRectToScreen() {
+ Testsuite::displayMessage("Testing Blitting a Bitmap to screen. \n\
+ You should expect to see a 20x40 yellow horizontal rectangle centred at the screen.");
+
+ GFXTestSuite::setCustomColor(255, 255, 0);
+ byte buffer[20 * 40];
+ memset(buffer, 2, 20 * 40);
+
+ uint x = g_system->getWidth() / 2 - 20;
+ uint y = g_system->getHeight() / 2 - 10;
+
+ g_system->copyRectToScreen(buffer, 40, x, y, 40, 20);
+ g_system->updateScreen();
+ g_system->delayMillis(1000);
+
+ Common::Rect rect(x, y, x+40, y+20);
+ Testsuite::clearScreen(rect);
+
+ return true;
+
+}
+
+
}
diff --git a/engines/testbed/gfxtests.h b/engines/testbed/gfxtests.h
index 7f5ae7d8af..bd219411e9 100644
--- a/engines/testbed/gfxtests.h
+++ b/engines/testbed/gfxtests.h
@@ -6,6 +6,8 @@ namespace Testbed {
// will contain function declarations for GFX tests
bool testFullScreenMode();
bool testAspectRatio();
+bool testPalettizedCursors();
+bool testCopyRectToScreen();
// add more here
}
diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp
index a5658a1213..ea1c1b1130 100644
--- a/engines/testbed/graphics.cpp
+++ b/engines/testbed/graphics.cpp
@@ -3,19 +3,20 @@
namespace Testbed {
+byte GFXTestSuite::_palette[3 * 4] = {0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 0};
+
GFXTestSuite::GFXTestSuite() {
// Initialize color palettes
// Te fourth field is for alpha channel which is unused
// Assuming 8bpp as of now
- _palette[0] =_palette[1] =_palette[2] = 0;
- _palette[4] =_palette[5] =_palette[6] = 255;
- _palette[8] =_palette[9] =_palette[10] = 255;
g_system->setPalette(_palette, 0, 3);
g_system->grabPalette(_palette, 0, 3);
// Add tests here
- addTest("FullScreenMode", &testFullScreenMode);
- addTest("AspectRatio", &testAspectRatio);
+// addTest("FullScreenMode", &testFullScreenMode);
+// addTest("AspectRatio", &testAspectRatio);
+ addTest("PalettizedCursors", &testPalettizedCursors);
+// addTest("BlitBitmaps", &testCopyRectToScreen);
}
const char *GFXTestSuite::getName() {
diff --git a/engines/testbed/graphics.h b/engines/testbed/graphics.h
index 5dcd02abac..eb84310db7 100644
--- a/engines/testbed/graphics.h
+++ b/engines/testbed/graphics.h
@@ -19,7 +19,7 @@ public:
~GFXTestSuite(){}
void execute();
const char *getName();
- void setCustomColor(uint r, uint g, uint b);
+ static void setCustomColor(uint r, uint g, uint b);
private:
/**
@@ -29,7 +29,7 @@ private:
* 1 (R:255, G:255, B:255) White (kColorWhite)
* 2 (R:255, G:255, B:255) your customized color (by default white) (kColorCustom)
*/
- byte _palette[3 * 4];
+ static byte _palette[3 * 4];
};
} // End of namespace Testbed
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index de573feee2..60eb08a2dd 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -288,7 +288,8 @@ void LoadFile(MEMHANDLE *pH) {
}
// extract and zero terminate the filename
- Common::strlcpy(szFilename, pH->szName, sizeof(pH->szName));
+ memcpy(szFilename, pH->szName, sizeof(pH->szName));
+ szFilename[sizeof(pH->szName)] = 0;
if (f.open(szFilename)) {
// read the data
diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp
index b90ace4613..b010ad1fcb 100644
--- a/engines/tinsel/saveload.cpp
+++ b/engines/tinsel/saveload.cpp
@@ -180,7 +180,8 @@ static void syncSavedMover(Common::Serializer &s, SAVED_MOVER &sm) {
static void syncSavedActor(Common::Serializer &s, SAVED_ACTOR &sa) {
s.syncAsUint16LE(sa.actorID);
s.syncAsUint16LE(sa.zFactor);
- s.syncAsUint32LE(sa.bAlive);
+ s.syncAsUint16LE(sa.bAlive);
+ s.syncAsUint16LE(sa.bHidden);
s.syncAsUint32LE(sa.presFilm);
s.syncAsUint16LE(sa.presRnum);
s.syncAsUint16LE(sa.presPlayX);
diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp
index 68f5301a80..633ed2790d 100644
--- a/engines/tucker/sequences.cpp
+++ b/engines/tucker/sequences.cpp
@@ -491,7 +491,6 @@ AnimationSequencePlayer::AnimationSequencePlayer(OSystem *system, Audio::Mixer *
_offscreenBuffer = (uint8 *)malloc(kScreenWidth * kScreenHeight);
_updateScreenWidth = 0;
_updateScreenPicture = false;
- _updateScreenOffset = 0;
_picBufPtr = _pic2BufPtr = 0;
}
@@ -537,9 +536,9 @@ void AnimationSequencePlayer::mainLoop() {
}
// budttle2.flc is shorter in french version ; start the background music
// earlier and skip any sounds effects
- if (_seqNum == 19 && _flicPlayer[0].getFrameCount() == 127) {
+ if (_seqNum == 19 && _flicPlayer[0].getFrameCount() == 126) {
_soundSeqDataIndex = 6;
- _frameCounter = 79;
+ _frameCounter = 80;
}
}
(this->*(_updateFunc[_updateFuncIndex].play))();
@@ -765,10 +764,10 @@ void AnimationSequencePlayer::openAnimation(int index, const char *fileName) {
}
}
-bool AnimationSequencePlayer::decodeNextAnimationFrame(int index) {
+bool AnimationSequencePlayer::decodeNextAnimationFrame(int index, bool copyDirtyRects) {
::Graphics::Surface *surface = _flicPlayer[index].decodeNextFrame();
- if (_seqNum == 19) {
+ if (!copyDirtyRects) {
for (uint16 y = 0; (y < surface->h) && (y < kScreenHeight); y++)
memcpy(_offscreenBuffer + y * kScreenWidth, (byte *)surface->pixels + y * surface->pitch, surface->w);
} else {
@@ -807,13 +806,13 @@ void AnimationSequencePlayer::playIntroSeq19_20() {
// cogs, and is being replayed when an intro credit appears
::Graphics::Surface *surface = 0;
- if (_flicPlayer[0].getCurFrame() >= 117) {
+ if (_flicPlayer[0].getCurFrame() >= 115) {
surface = _flicPlayer[1].decodeNextFrame();
if (_flicPlayer[1].endOfVideo())
_flicPlayer[1].reset();
}
- bool framesLeft = decodeNextAnimationFrame(0);
+ bool framesLeft = decodeNextAnimationFrame(0, false);
if (surface)
for (int i = 0; i < kScreenWidth * kScreenHeight; ++i)
@@ -841,19 +840,28 @@ void AnimationSequencePlayer::displayLoadingScreen() {
void AnimationSequencePlayer::initPicPart4() {
_updateScreenWidth = 320;
_updateScreenPicture = true;
- _updateScreenOffset = 0;
+ _updateScreenCounter = 0;
+ _updateScreenIndex = -1;
}
void AnimationSequencePlayer::drawPicPart4() {
- static const uint8 offsetsTable[77] = {
- 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
- 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3,
- 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1
- };
- _updateScreenWidth = _updateScreenWidth - offsetsTable[_updateScreenOffset];
- ++_updateScreenOffset;
+ static const uint8 offsets[] = { 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1 };
+ if (_updateScreenIndex == -1) {
+ for (int i = 0; i < 256; ++i) {
+ if (memcmp(_animationPalette + i * 4, _picBufPtr + 32 + i * 3, 3) != 0) {
+ memcpy(_animationPalette + i * 4, _picBufPtr + 32 + i * 3, 3);
+ _animationPalette[i * 4 + 3] = 0;
+ }
+ }
+ }
+ if (_updateScreenCounter == 0) {
+ static const uint8 counter[] = { 1, 2, 3, 4, 5, 35, 5, 4, 3, 2, 1 };
+ ++_updateScreenIndex;
+ assert(_updateScreenIndex < ARRAYSIZE(counter));
+ _updateScreenCounter = counter[_updateScreenIndex];
+ }
+ --_updateScreenCounter;
+ _updateScreenWidth -= offsets[_updateScreenIndex];
for (int y = 0; y < 200; ++y) {
memcpy(_offscreenBuffer + y * 320, _picBufPtr + 800 + y * 640 + _updateScreenWidth, 320);
}
@@ -875,7 +883,7 @@ void AnimationSequencePlayer::loadIntroSeq3_4() {
void AnimationSequencePlayer::playIntroSeq3_4() {
if (!_updateScreenPicture) {
bool framesLeft = decodeNextAnimationFrame(0);
- if (_flicPlayer[0].getCurFrame() == 707) {
+ if (_flicPlayer[0].getCurFrame() == 705) {
initPicPart4();
}
if (!framesLeft) {
@@ -914,17 +922,10 @@ void AnimationSequencePlayer::drawPic2Part10() {
}
void AnimationSequencePlayer::drawPic1Part10() {
- ::Graphics::Surface *surface = _flicPlayer[0].decodeNextFrame();
- _flicPlayer[0].copyDirtyRectsToBuffer(_offscreenBuffer, kScreenWidth);
- ++_frameCounter;
-
- if (_flicPlayer[0].hasDirtyPalette())
- getRGBPalette(0);
-
int offset = 0;
for (int y = 0; y < kScreenHeight; ++y) {
for (int x = 0; x < kScreenWidth; ++x) {
- byte color = *((byte *)surface->pixels + offset);
+ byte color = _offscreenBuffer[offset];
if (color == 0)
color = _picBufPtr[800 + y * 640 + _updateScreenWidth + x];
@@ -943,22 +944,24 @@ void AnimationSequencePlayer::loadIntroSeq9_10() {
}
void AnimationSequencePlayer::playIntroSeq9_10() {
- if (_flicPlayer[0].getCurFrame() >= 265 && _flicPlayer[0].getCurFrame() <= 296) {
+ const int nextFrame = _flicPlayer[0].getCurFrame() + 1;
+ if (nextFrame >= 263 && nextFrame <= 294) {
+ decodeNextAnimationFrame(0, false);
drawPic1Part10();
_updateScreenWidth += 6;
- } else if (_flicPlayer[0].getCurFrame() == 985) {
+ } else if (nextFrame == 983) {
decodeNextAnimationFrame(0);
drawPic2Part10();
- } else if (_flicPlayer[0].getCurFrame() >= 989 && _flicPlayer[0].getCurFrame() <= 997) {
+ } else if (nextFrame >= 987 && nextFrame <= 995) {
+ decodeNextAnimationFrame(0, false);
drawPic1Part10();
_updateScreenWidth -= 25;
if (_updateScreenWidth < 0) {
_updateScreenWidth = 0;
}
- }
-
- if (_flicPlayer[0].endOfVideo())
+ } else if (!decodeNextAnimationFrame(0)) {
_changeToNextSequence = true;
+ }
}
void AnimationSequencePlayer::loadIntroSeq21_22() {
diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h
index d9810c7929..86f5843e77 100644
--- a/engines/tucker/tucker.h
+++ b/engines/tucker/tucker.h
@@ -934,7 +934,7 @@ private:
void unloadAnimation();
uint8 *loadPicture(const char *fileName);
void openAnimation(int index, const char *fileName);
- bool decodeNextAnimationFrame(int index);
+ bool decodeNextAnimationFrame(int index, bool copyDirtyRects = true);
void loadIntroSeq17_18();
void playIntroSeq17_18();
void loadIntroSeq19_20();
@@ -975,7 +975,8 @@ private:
uint8 *_offscreenBuffer;
int _updateScreenWidth;
int _updateScreenPicture;
- int _updateScreenOffset;
+ int _updateScreenCounter;
+ int _updateScreenIndex;
int _frameCounter;
int _frameTime;
uint32 _lastFrameTime;