diff options
author | Christopher Page | 2008-08-10 21:58:18 +0000 |
---|---|---|
committer | Christopher Page | 2008-08-10 21:58:18 +0000 |
commit | fcc00f20b93d719c9f7bce848ed7c3600be982b9 (patch) | |
tree | 48b9fd1c842cb376985a91592ef7b062fed0cfa7 | |
parent | ce3d1e1a7d9ec9860d3fc42d8127a1634051d950 (diff) | |
parent | 9d0b0523cf119fdc400bf477c2f9d6f4f37ddce6 (diff) | |
download | scummvm-rg350-fcc00f20b93d719c9f7bce848ed7c3600be982b9.tar.gz scummvm-rg350-fcc00f20b93d719c9f7bce848ed7c3600be982b9.tar.bz2 scummvm-rg350-fcc00f20b93d719c9f7bce848ed7c3600be982b9.zip |
Merged revisions 33719,33721-33723,33725-33727,33729-33730,33733,33736,33742,33754,33756,33758,33761,33763,33766 via svnmerge from
https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk
svn-id: r33769
32 files changed, 442 insertions, 213 deletions
diff --git a/backends/platform/wii/Makefile b/backends/platform/wii/Makefile index a52ceb1774..d17a7cb41e 100644 --- a/backends/platform/wii/Makefile +++ b/backends/platform/wii/Makefile @@ -1,26 +1,32 @@ +# this enables port specific debug messages and redirects stdout/err over +# usbgecko in memcard slot b DEBUG_WII = 1 -ENABLE_SCUMM = 1 -ENABLE_SCUMM_7_8 = 1 -ENABLE_HE = 1 -# ENABLE_AGI = 1 -ENABLE_AGOS = 1 -ENABLE_CINE = 1 -ENABLE_CRUISE = 1 -ENABLE_DRASCULA = 1 -ENABLE_GOB = 1 -ENABLE_IGOR = 1 -ENABLE_KYRA = 1 -ENABLE_LURE = 1 -ENABLE_M4 = 1 -ENABLE_MADE = 1 -ENABLE_PARALLACTION = 1 -ENABLE_QUEEN = 1 -ENABLE_SAGA = 1 -ENABLE_SKY = 1 -ENABLE_SWORD1 = 1 -ENABLE_SWORD2 = 1 -ENABLE_TOUCHE = 1 +# builds a gamecube version. cleanup object files before flipping this +GAMECUBE = 0 + +ENABLE_SCUMM = STATIC_PLUGIN +ENABLE_SCUMM_7_8 = STATIC_PLUGIN +ENABLE_HE = STATIC_PLUGIN +# ENABLE_AGI = STATIC_PLUGIN +ENABLE_AGOS = STATIC_PLUGIN +ENABLE_CINE = STATIC_PLUGIN +ENABLE_CRUISE = STATIC_PLUGIN +ENABLE_DRASCULA = STATIC_PLUGIN +ENABLE_GOB = STATIC_PLUGIN +ENABLE_IGOR = STATIC_PLUGIN +ENABLE_KYRA = STATIC_PLUGIN +ENABLE_LURE = STATIC_PLUGIN +ENABLE_M4 = STATIC_PLUGIN +ENABLE_MADE = STATIC_PLUGIN +ENABLE_PARALLACTION = STATIC_PLUGIN +ENABLE_QUEEN = STATIC_PLUGIN +ENABLE_SAGA = STATIC_PLUGIN +ENABLE_SKY = STATIC_PLUGIN +ENABLE_SWORD1 = STATIC_PLUGIN +ENABLE_SWORD2 = STATIC_PLUGIN +ENABLE_TINSEL = STATIC_PLUGIN +ENABLE_TOUCHE = STATIC_PLUGIN DISABLE_HQ_SCALERS = 1 DISABLE_SCALERS = 1 @@ -30,7 +36,11 @@ USE_MAD = 1 USE_TREMOR = 1 USE_FLAC = 1 USE_MPEG2 = 1 +ifeq ($(GAMECUBE),1) +USE_MT32EMU = 0 +else USE_MT32EMU = 1 +endif srcdir = ../../.. VPATH = $(srcdir) @@ -54,21 +64,28 @@ MKDIR = mkdir -p RM = rm -f CP = cp -f +ifeq ($(GAMECUBE),1) +TARGET = scummvm-gc +MACHDEP = -DGEKKO -DGAMECUBE -mogc -mcpu=750 -meabi -mhard-float \ + -ffunction-sections -fdata-sections -fmodulo-sched +LIBDIR = $(DEVKITPRO)/libogc/lib/cube +LIBS = -lstdc++ -lfat -logc -lm +else TARGET = scummvm-wii - MACHDEP = -DGEKKO -mrvl -mcpu=750 -meabi -mhard-float \ -ffunction-sections -fdata-sections -fmodulo-sched +LIBDIR = $(DEVKITPRO)/libogc/lib/wii +LIBS = -lstdc++ -lfat -lwiiuse -lbte -logc -lm +endif INCDIR = $(srcdir) . $(srcdir)/engines/ $(DEVKITPRO)/libogc/include -LIBDIR = $(DEVKITPRO)/libogc/lib/wii CXXFLAGS = -g -Os -Wall $(MACHDEP) -D__WII__ -Wno-multichar -Wno-long-long \ - -Wno-unknown-pragmas -Wno-reorder -fno-exceptions -fno-rtti + -Wno-unknown-pragmas -Wno-reorder -fno-exceptions -fno-rtti CXXFLAGS += $(addprefix -I,$(INCDIR)) LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(TARGET).elf.map LDFLAGS += $(addprefix -L,$(LIBDIR)) -LIBS = -lstdc++ -lfat -lwiiuse -lbte -logc -lm CXXFLAGS += -I$(DEVKITPRO)/3rd/wii/include LDFLAGS += -L$(DEVKITPRO)/3rd/wii/lib @@ -137,20 +154,26 @@ distclean: distclean-wii distclean-wii: @-$(RM) dist +ifeq ($(GAMECUBE),1) upload: $(DEVKITPPC)/bin/wiiload $(TARGET).dol +endif dist: - $(MKDIR) dist/apps/scummvm - $(CP) $(TARGET).dol dist/apps/scummvm/boot.dol - $(CP) $(DISTPATH)/meta.xml dist/apps/scummvm/ - $(CP) $(DISTPATH)/icon.png dist/apps/scummvm/ - $(CP) $(DISTPATH)/READMII dist/apps/scummvm/ - $(CP) $(srcdir)/AUTHORS dist/apps/scummvm/ - $(CP) $(srcdir)/COPYING dist/apps/scummvm/ - $(CP) $(srcdir)/COPYRIGHT dist/apps/scummvm/ - $(CP) $(srcdir)/NEWS dist/apps/scummvm/ - $(CP) $(srcdir)/README dist/apps/scummvm/ - $(CP) $(DIST_FILES_THEMES) dist/apps/scummvm/ - $(CP) $(DIST_FILES_ENGINEDATA) dist/apps/scummvm/ + $(MKDIR) dist/scummvm +ifeq ($(GAMECUBE),1) + $(CP) $(TARGET).dol dist/scummvm/ +else + $(CP) $(TARGET).dol dist/scummvm/boot.dol + $(CP) $(DISTPATH)/meta.xml dist/scummvm/ + $(CP) $(DISTPATH)/icon.png dist/scummvm/ + $(CP) $(DISTPATH)/READMII dist/scummvm/ + $(CP) $(srcdir)/AUTHORS dist/scummvm/ + $(CP) $(srcdir)/COPYING dist/scummvm/ + $(CP) $(srcdir)/COPYRIGHT dist/scummvm/ + $(CP) $(srcdir)/NEWS dist/scummvm/ + $(CP) $(srcdir)/README dist/scummvm/ + $(CP) $(DIST_FILES_THEMES) dist/scummvm/ + $(CP) $(DIST_FILES_ENGINEDATA) dist/scummvm/ +endif diff --git a/backends/platform/wii/main.cpp b/backends/platform/wii/main.cpp index 5753ecefe4..8bb1bff904 100644 --- a/backends/platform/wii/main.cpp +++ b/backends/platform/wii/main.cpp @@ -62,7 +62,9 @@ int main(int argc, char *argv[]) { printf("startup\n"); SYS_SetResetCallback(reset_cb); +#ifndef GAMECUBE SYS_SetPowerCallback(power_cb); +#endif if (!fatInitDefault()) { printf("fatInitDefault failed\n"); @@ -75,7 +77,7 @@ int main(int argc, char *argv[]) { if (!strcmp(buf, "fat:/")) chdir("/apps/scummvm"); - //fatEnableReadAhead(PI_DEFAULT, 32, 128); + fatEnableReadAhead(PI_DEFAULT, 32, 128); } g_system = new OSystem_Wii(); diff --git a/backends/platform/wii/osystem.cpp b/backends/platform/wii/osystem.cpp index 9e708345c5..3ec32126f0 100644 --- a/backends/platform/wii/osystem.cpp +++ b/backends/platform/wii/osystem.cpp @@ -89,8 +89,12 @@ OSystem_Wii::~OSystem_Wii() { void OSystem_Wii::initBackend() { _startup_time = gettime(); + + char buf[MAXPATHLEN]; + if (!getcwd(buf, MAXPATHLEN)) + strcpy(buf, "/"); - _savefile = new DefaultSaveFileManager(); + _savefile = new DefaultSaveFileManager(buf); _mixer = new Audio::MixerImpl(this); _timer = new DefaultTimerManager(); diff --git a/backends/platform/wii/osystem.h b/backends/platform/wii/osystem.h index 7fbc560b1a..71bf9bce2e 100644 --- a/backends/platform/wii/osystem.h +++ b/backends/platform/wii/osystem.h @@ -22,9 +22,9 @@ #ifndef _WII_OSYSTEM_H_ #define _WII_OSYSTEM_H_ -#include "common/system.h" #include "base/main.h" - +#include "common/system.h" +#include "common/fs.h" #include "common/rect.h" #include "common/events.h" diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp index 932599004d..95047ecf5c 100644 --- a/backends/platform/wince/CEActionsPocket.cpp +++ b/backends/platform/wince/CEActionsPocket.cpp @@ -129,11 +129,13 @@ void CEActionsPocket::initInstanceGame() { bool is_parallaction = (gameid == "parallaction"); bool is_lure = (gameid == "lure"); bool is_feeble = (gameid == "feeble"); + bool is_drascula = (strncmp(gameid.c_str(), "drascula",8) == 0); GUI_Actions::initInstanceGame(); // See if a right click mapping could be needed - if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || is_samnmax || is_cine || is_touche || is_parallaction) + if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || + is_samnmax || is_cine || is_touche || is_parallaction || is_drascula) _right_click_needed = true; // See if a "hide toolbar" mapping could be needed @@ -153,7 +155,7 @@ void CEActionsPocket::initInstanceGame() { } else if (is_sky) { _action_enabled[POCKET_ACTION_SAVE] = true; _key_action[POCKET_ACTION_SAVE].setKey(Common::ASCII_F5, SDLK_F5); - } else if (is_cine) { + } else if (is_cine || is_drascula) { _action_enabled[POCKET_ACTION_SAVE] = true; _key_action[POCKET_ACTION_SAVE].setKey(Common::ASCII_F10, SDLK_F10); // F10 } else if (is_agi) { @@ -171,7 +173,8 @@ void CEActionsPocket::initInstanceGame() { // Skip if (!is_cine && !is_parallaction) _action_enabled[POCKET_ACTION_SKIP] = true; - if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_saga || is_kyra || is_touche || is_lure || is_feeble) + if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || + is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula) _key_action[POCKET_ACTION_SKIP].setKey(VK_ESCAPE); else _key_action[POCKET_ACTION_SKIP].setKey(KEY_ALL_SKIP); diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp index 6877c343e3..dbcddac98c 100644 --- a/backends/platform/wince/CEActionsSmartphone.cpp +++ b/backends/platform/wince/CEActionsSmartphone.cpp @@ -119,11 +119,13 @@ void CEActionsSmartphone::initInstanceGame() { bool is_parallaction = (gameid == "parallaction"); bool is_lure = (gameid == "lure"); bool is_feeble = (gameid == "feeble"); + bool is_drascula = (strncmp(gameid.c_str(), "drascula",8) == 0); GUI_Actions::initInstanceGame(); // See if a right click mapping could be needed - if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || is_samnmax || is_cine || is_touche || is_parallaction) + if (is_sword1 || is_sword2 || is_sky || is_queen || is_comi || is_gob || + is_samnmax || is_cine || is_touche || is_parallaction || is_drascula) _right_click_needed = true; // Initialize keys for different actions @@ -136,7 +138,7 @@ void CEActionsSmartphone::initInstanceGame() { } else if (is_sky) { _action_enabled[SMARTPHONE_ACTION_SAVE] = true; _key_action[SMARTPHONE_ACTION_SAVE].setKey(Common::ASCII_F5, SDLK_F5); - } else if (is_cine) { + } else if (is_cine || is_drascula) { _action_enabled[SMARTPHONE_ACTION_SAVE] = true; _key_action[SMARTPHONE_ACTION_SAVE].setKey(Common::ASCII_F10, SDLK_F10); //F10 } else if (is_agi) { @@ -151,7 +153,8 @@ void CEActionsSmartphone::initInstanceGame() { } // Skip _action_enabled[SMARTPHONE_ACTION_SKIP] = true; - if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || is_saga || is_kyra || is_touche || is_lure || is_feeble) + if (is_simon || is_sky || is_sword2 || is_queen || is_sword1 || is_gob || + is_saga || is_kyra || is_touche || is_lure || is_feeble || is_drascula) _key_action[SMARTPHONE_ACTION_SKIP].setKey(VK_ESCAPE); else _key_action[SMARTPHONE_ACTION_SKIP].setKey(KEY_ALL_SKIP); diff --git a/backends/platform/wince/Makefile b/backends/platform/wince/Makefile index 176971067e..4400d50e3a 100644 --- a/backends/platform/wince/Makefile +++ b/backends/platform/wince/Makefile @@ -34,9 +34,11 @@ ENABLE_SWORD1 = STATIC_PLUGIN ENABLE_SWORD2 = STATIC_PLUGIN ENABLE_TOUCHE = STATIC_PLUGIN ENABLE_PARALLACTION = STATIC_PLUGIN +ENABLE_DRASCULA = STATIC_PLUGIN #ENABLE_CRUISE = STATIC_PLUGIN -#ENABLE_DRASCULA = STATIC_PLUGIN #ENABLE_IGOR = STATIC_PLUGIN +#ENABLE_M4 = STATIC_PLUGIN +#ENABLE_MADE = STATIC_PLUGIN ######################################################################## ## Pick which libraries you want to use here diff --git a/common/config-manager.cpp b/common/config-manager.cpp index a424c4f6c7..138fcc201f 100644 --- a/common/config-manager.cpp +++ b/common/config-manager.cpp @@ -64,9 +64,9 @@ void ConfigManager::loadDefaultConfigFile() { SeekableReadStream *stream = g_system->openConfigFileForReading(); _filename.clear(); // clear the filename to indicate that we are using the default config file - // ... load it ... - assert(stream); - loadFromStream(*stream); + // ... load it, if available ... + if (stream) + loadFromStream(*stream); // ... and close it again. delete stream; diff --git a/common/system.cpp b/common/system.cpp index 3e07e4ac4c..d0548cdd2d 100644 --- a/common/system.cpp +++ b/common/system.cpp @@ -163,25 +163,15 @@ static Common::String getDefaultConfigFileName() { } Common::SeekableReadStream *OSystem::openConfigFileForReading() { - Common::File *confFile = new Common::File(); - assert(confFile); - if (!confFile->open(getDefaultConfigFileName())) { - delete confFile; - confFile = 0; - } - return confFile; + FilesystemNode file(getDefaultConfigFileName()); + return file.openForReading(); } Common::WriteStream *OSystem::openConfigFileForWriting() { #ifdef __DC__ return 0; #else - Common::DumpFile *confFile = new Common::DumpFile(); - assert(confFile); - if (!confFile->open(getDefaultConfigFileName())) { - delete confFile; - confFile = 0; - } - return confFile; + FilesystemNode file(getDefaultConfigFileName()); + return file.openForWriting(); #endif } diff --git a/dists/wii/READMII b/dists/wii/READMII index 4f157dffe7..87efe21d68 100644 --- a/dists/wii/READMII +++ b/dists/wii/READMII @@ -6,12 +6,18 @@ features not compiled in: REQUIREMENTS - - sd card - - wiimote or gamecube controller in port 1 + wii: + - sd card + - wiimote or gamecube controller in port 1 + + gamecube: + - sd card + - sd gecko adapter + - gamecube controller in port 1 INSTALL - - copy the "apps" folder to the root of your sd card + - copy the "scummvm" folder into the "/apps" folder of your sd card - copy your demos and/or games onto the same sd card each game goes into its own subdirectory, do not place those under "/apps/scummvm", and do not set the "theme" or "extra" path to that folder @@ -20,17 +26,21 @@ INSTALL RUN - either use the homebrew channel, available at + wii: + either use the homebrew channel, available at + + http://hbc.hackmii.com/ - http://hbc.hackmii.com/ + or load "/apps/scummvm/boot.dol" with your favorite loader - or load "boot.dol" with your favorite loader + gamecube: + load "/apps/scummvm/scummvm-gc.dol" with your favorite loader CONTROLS wiimote - analog stick: mouse movement + IR: mouse movement a: left mouse button b: right mouse button minus: escape diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp index 6d24c7db2c..fd0e4eaa9d 100644 --- a/engines/agos/midi.cpp +++ b/engines/agos/midi.cpp @@ -556,7 +556,11 @@ void MidiPlayer::loadXMIDI(Common::File *in, bool sfx) { error("Expected 'FORM' tag but found '%c%c%c%c' instead", buf[0], buf[1], buf[2], buf[3]); } - MidiParser *parser = MidiParser::createParser_XMIDI(); + // In the DOS version of Simon the Sorcerer 2, the music contains lots + // of XMIDI callback controller events. As far as we know, they aren't + // actually used, so we disable the callback handler explicitly. + + MidiParser *parser = MidiParser::createParser_XMIDI(NULL); parser->setMidiDriver(this); parser->setTimerRate(_driver->getBaseTempo()); if (!parser->loadMusic(p->data, size)) diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index c19435c59a..c2c815596e 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -49,7 +49,7 @@ struct AnimHeader2Struct { uint16 field_E; }; -AnimData animDataTable[NUM_MAX_ANIMDATA]; +Common::Array<AnimData> animDataTable; static const AnimDataEntry transparencyData[] = { {"ALPHA", 0xF}, diff --git a/engines/cine/anim.h b/engines/cine/anim.h index 317654064b..8b1541eb3f 100644 --- a/engines/cine/anim.h +++ b/engines/cine/anim.h @@ -150,7 +150,7 @@ public: #define NUM_MAX_ANIMDATA 255 -extern AnimData animDataTable[NUM_MAX_ANIMDATA]; +extern Common::Array<AnimData> animDataTable; void freeAnimDataTable(void); void freeAnimDataRange(byte startIdx, byte numIdx); diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 127d390f66..c30cac63a5 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -124,6 +124,22 @@ int CineEngine::modifyGameSpeed(int speedChange) { } void CineEngine::initialize() { + // Resize object table to its correct size and reset all its elements + objectTable.resize(NUM_MAX_OBJECT); + resetObjectTable(); + + // Resize animation data table to its correct size and reset all its elements + animDataTable.resize(NUM_MAX_ANIMDATA); + freeAnimDataTable(); + + // Resize zone data table to its correct size and reset all its elements + zoneData.resize(NUM_MAX_ZONE); + Common::set_to(zoneData.begin(), zoneData.end(), 0); + + // Resize zone query table to its correct size and reset all its elements + zoneQuery.resize(NUM_MAX_ZONE); + Common::set_to(zoneQuery.begin(), zoneQuery.end(), 0); + _timerDelayMultiplier = 12; // Set default speed setupOpcodes(); @@ -160,8 +176,7 @@ void CineEngine::initialize() { freeAnimDataTable(); overlayList.clear(); messageTable.clear(); - - memset(objectTable, 0, sizeof(objectTable)); + resetObjectTable(); var8 = 0; diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index b882c9760e..c6c5faf464 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -276,9 +276,11 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, byte colo /*! \brief Draw rectangle on screen * \param x Top left corner coordinate * \param y Top left corner coordinate - * \param width Rectangle width - * \param height Rectangle height + * \param width Rectangle width (Negative values draw the box horizontally flipped) + * \param height Rectangle height (Negative values draw the box vertically flipped) * \param color Fill color + * \note Rectangle's drawn width is always at least one. + * \note Rectangle's drawn height is always at least one. */ void FWRenderer::drawPlainBox(int x, int y, int width, int height, byte color) { int i; @@ -313,12 +315,18 @@ void FWRenderer::drawPlainBox(int x, int y, int width, int height, byte color) { height = 0; } - // Draw the box if it's not empty - if (width > 0 && height > 0) { - byte *dest = _backBuffer + y * 320 + x; - for (i = 0; i < height; i++) { - memset(dest + i * 320, color, width); - } + // Make width and height at least one + // which forces this function to always draw something. + // This fixes at least the showing of the oxygen gauge meter in + // Operation Stealth's first arcade sequence where this function + // is called with a height of zero. + width = MAX(1, width); + height = MAX(1, height); + + // Draw the filled rectangle + byte *dest = _backBuffer + y * 320 + x; + for (i = 0; i < height; i++) { + memset(dest + i * 320, color, width); } } @@ -428,7 +436,7 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { switch (it->type) { // color sprite case 0: - sprite = animDataTable + objectTable[it->objIdx].frame; + sprite = &animDataTable[objectTable[it->objIdx].frame]; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; memcpy(mask, sprite->mask(), len); @@ -463,7 +471,7 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { // bitmap case 4: assert(it->objIdx < NUM_MAX_OBJECT); - obj = objectTable + it->objIdx; + obj = &objectTable[it->objIdx]; if (obj->frame < 0) { return; @@ -1066,7 +1074,7 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { if (objectTable[it->objIdx].frame < 0) { break; } - sprite = animDataTable + objectTable[it->objIdx].frame; + sprite = &animDataTable[objectTable[it->objIdx].frame]; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; generateMask(sprite->data(), mask, len, objectTable[it->objIdx].part); @@ -1099,8 +1107,8 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { case 20: assert(it->objIdx < NUM_MAX_OBJECT); var5 = it->x; // A global variable updated here! - obj = objectTable + it->objIdx; - sprite = animDataTable + obj->frame; + obj = &objectTable[it->objIdx]; + sprite = &animDataTable[obj->frame]; if (obj->frame < 0 || it->x < 0 || it->x > 8 || !_bgTable[it->x].bg || sprite->_bpp != 1) { break; @@ -1109,13 +1117,24 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { maskBgOverlay(_bgTable[it->x].bg, sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, obj->x, obj->y); break; - // TODO: Figure out what this overlay type is and name it - // TODO: Check it this implementation really works correctly (Some things might be wrong, needs testing) + // FIXME: Looking at Operation Stealth's disassembly I can't find any codepath that + // will draw a type 21 overlay. But looking at the first arcade sequence's scripts + // it looks like the oxygen gauge meter is implemented using a type 21 overlay. + // So for the time being I'm simply drawing type 21 overlays as type 22 overlays + // and hoping for the best. + // TODO: Check how the original game looks under DOSBox to see if the oxygen gauge works in it + case 21: + // A filled rectangle: case 22: { + // TODO: Check it this implementation really works correctly (Some things might be wrong, needs testing). assert(it->objIdx < NUM_MAX_OBJECT); - obj = objectTable + it->objIdx; - byte transCol = obj->part & 0x0F; - drawPlainBox(obj->x, obj->y, obj->frame, obj->costume, transCol); + obj = &objectTable[it->objIdx]; + byte color = obj->part & 0x0F; + int width = obj->frame; + int height = obj->costume; + drawPlainBox(obj->x, obj->y, width, height, color); + debug(5, "renderOverlay: type=%d, x=%d, y=%d, width=%d, height=%d, color=%d", + it->type, obj->x, obj->y, width, height, color); break; } diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 9361eb3822..3b0dc80bfb 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -333,9 +333,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { // Clear the zoneQuery table (Operation Stealth specific) if (g_cine->getGameType() == Cine::GType_OS) { - for (uint i = 0; i < NUM_MAX_ZONE; i++) { - zoneQuery[i] = 0; - } + Common::set_to(zoneQuery.begin(), zoneQuery.end(), 0); } if (g_cine->getGameType() == Cine::GType_OS) { diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp index c02e01c8ce..9781975f7c 100644 --- a/engines/cine/object.cpp +++ b/engines/cine/object.cpp @@ -35,9 +35,16 @@ namespace Cine { -objectStruct objectTable[NUM_MAX_OBJECT]; +Common::Array<objectStruct> objectTable; Common::List<overlay> overlayList; +/*! \brief Resets all elements in the object table. */ +void resetObjectTable() { + for (Common::Array<objectStruct>::iterator it = objectTable.begin(); it != objectTable.end(); it++) { + it->clear(); + } +} + void loadObject(char *pObjectName) { uint16 numEntry; uint16 entrySize; diff --git a/engines/cine/object.h b/engines/cine/object.h index 7ad65eb75f..3bf6cdcc42 100644 --- a/engines/cine/object.h +++ b/engines/cine/object.h @@ -38,6 +38,17 @@ struct objectStruct { int16 costume; char name[20]; uint16 part; + + /*! \brief Sets all member variables to zero. */ + void clear() { + this->x = 0; + this->y = 0; + this->mask = 0; + this->frame = 0; + this->costume = 0; + memset(this->name, 0, sizeof(this->name)); + this->part = 0; + } }; struct overlay { @@ -52,10 +63,10 @@ struct overlay { #define NUM_MAX_OBJECT 255 #define NUM_MAX_VAR 255 -extern objectStruct objectTable[NUM_MAX_OBJECT]; - +extern Common::Array<objectStruct> objectTable; extern Common::List<overlay> overlayList; +void resetObjectTable(); void loadObject(char *pObjectName); void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4); void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue); diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 0ead13e3ab..2fe2701e52 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -124,8 +124,8 @@ static const int16 canUseOnItemTable[] = { 1, 0, 0, 1, 1, 0, 0 }; CommandeType objectListCommand[20]; int16 objListTab[20]; -uint16 zoneData[NUM_MAX_ZONE]; -uint16 zoneQuery[NUM_MAX_ZONE]; //!< Only exists in Operation Stealth +Common::Array<uint16> zoneData; +Common::Array<uint16> zoneQuery; //!< Only exists in Operation Stealth /*! \brief Move the player character using the keyboard * \param x Negative values move left, positive right, zero not at all @@ -616,16 +616,7 @@ void CineEngine::resetEngine() { relTable.clear(); scriptTable.clear(); messageTable.clear(); - - for (int i = 0; i < NUM_MAX_OBJECT; i++) { - objectTable[i].x = 0; - objectTable[i].y = 0; - objectTable[i].part = 0; - objectTable[i].name[0] = 0; - objectTable[i].frame = 0; - objectTable[i].mask = 0; - objectTable[i].costume = 0; - } + resetObjectTable(); globalVars.reset(); diff --git a/engines/cine/various.h b/engines/cine/various.h index acab15e235..926a1821d9 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -127,8 +127,8 @@ struct SelectedObjStruct { }; #define NUM_MAX_ZONE 16 -extern uint16 zoneData[NUM_MAX_ZONE]; -extern uint16 zoneQuery[NUM_MAX_ZONE]; +extern Common::Array<uint16> zoneData; +extern Common::Array<uint16> zoneQuery; void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 param5); diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp index a426857fbd..9832d58294 100644 --- a/engines/drascula/detection.cpp +++ b/engines/drascula/detection.cpp @@ -195,6 +195,38 @@ static const DrasculaGameDescription gameDescriptions[] = { }, }, + { + // Drascula Spanish version (ScummVM repacked files) + { + "drascula", + 0, + { + {"packet.001", 0, "c6a8697396e213a18472542d5f547cb4", 32847563}, + {"packet.004", 0, "a289d3cf80d50f25ec569b653248437e", 17205838}, + {NULL, 0, NULL, 0} + }, + Common::ES_ESP, + Common::kPlatformPC, + GF_PACKED + }, + }, + + { + // Drascula Italian version (ScummVM repacked files) + { + "drascula", + 0, + { + {"packet.001", 0, "c6a8697396e213a18472542d5f547cb4", 32847563}, + {"packet.005", 0, "f80e10e37000a2201eabf8dad82c7f64", 16184223}, + {NULL, 0, NULL, 0} + }, + Common::IT_ITA, + Common::kPlatformPC, + GF_PACKED + }, + }, + { AD_TABLE_END_MARKER } }; diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index 7c843892b6..2d24978f21 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -162,6 +162,12 @@ int DrasculaEngine::init() { _textmisc = 0; _textd1 = 0; + _color = 0; + blinking = 0; + leftMouseButton = 0; + rightMouseButton = 0; + *textName = 0; + if (!loadDrasculaDat()) return 1; @@ -286,6 +292,8 @@ void DrasculaEngine::endChapter() { bool DrasculaEngine::runCurrentChapter() { int n; + rightMouseButton = 0; + if (_lang == kSpanish) textSurface = extraSurface; else @@ -458,21 +466,44 @@ bool DrasculaEngine::runCurrentChapter() { } delay(25); +#ifndef _WIN32_WCE + // FIXME + // This and the following #ifndefs disable the excess updateEvents() calls *within* the game loop. + // Events such as keypresses or mouse clicks are dropped on the ground with no processing + // by these calls. They are properly handled by the implicit call through getScan() below. + // It is not a good practice to not process events and indeed this created problems with synthesized + // events in the wince port. updateEvents(); +#endif if (menuScreen == 0 && takeObject == 1) checkObjects(); +#ifdef _WIN32_WCE + if (rightMouseButton) + if (menuScreen) { +#else if (rightMouseButton == 1 && menuScreen == 1) { +#endif if (currentChapter == 2) loadPic(menuBackground, backSurface); else loadPic(99, backSurface); setPalette((byte *)&gamePalette); menuScreen = 0; +#ifndef _WIN32_WCE + // FIXME: This call here is in hope that it will catch the rightmouseup event so the + // next if block won't be executed. This too is not a good coding practice. I've recoded it + // with a mutual exclusive if block for the menu. I would commit this properly but I cannot test + // for other (see Desktop) ports right now. updateEvents(); +#endif +#ifdef _WIN32_WCE + } else { +#else } if (rightMouseButton == 1 && menuScreen == 0) { +#endif characterMoved = 0; if (trackProtagonist == 2) trackProtagonist = 1; @@ -485,7 +516,9 @@ bool DrasculaEngine::runCurrentChapter() { else loadPic("icons.alg", backSurface); menuScreen = 1; +#ifndef _WIN32_WCE updateEvents(); +#endif withoutVerb(); } @@ -671,7 +704,11 @@ void DrasculaEngine::updateEvents() { AudioCD.updateCD(); +#ifdef _WIN32_WCE + if (eventMan->pollEvent(event)) { +#else while (eventMan->pollEvent(event)) { +#endif switch (event.type) { case Common::EVENT_KEYDOWN: _keyPressed = event.kbd; @@ -989,7 +1026,7 @@ void DrasculaEngine::freeTexts(char ***ptr) { for (int lang = 0; lang < _numLangs; lang++) { if (ptr[lang]) { - free(ptr[lang][0] - DATAALIGNMENT); + free(ptr[lang][0]); free(ptr[lang]); } } diff --git a/engines/drascula/saveload.cpp b/engines/drascula/saveload.cpp index de82899462..6f88a58fbb 100644 --- a/engines/drascula/saveload.cpp +++ b/engines/drascula/saveload.cpp @@ -59,6 +59,8 @@ bool DrasculaEngine::saveLoadScreen() { select[0] = 0; + _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); + for (;;) { y = 27; copyBackground(0, 0, 0, 0, 320, 200, bgSurface, screenSurface); @@ -140,8 +142,10 @@ bool DrasculaEngine::saveLoadScreen() { } if (mouseX > 125 && mouseY > 123 && mouseX < 199 && mouseY < 149 && selectionMade == 1) { - if (!loadGame(file)) + if (!loadGame(file)) { + _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); return false; + } break; } else if (mouseX > 208 && mouseY > 123 && mouseX < 282 && mouseY < 149 && selectionMade == 1) { saveGame(file); @@ -172,6 +176,8 @@ bool DrasculaEngine::saveLoadScreen() { loadPic(roomNumber, bgSurface, HALF_PAL); selectionMade = 0; + _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); + return true; } diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index 0c9b117866..0722fb262b 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -196,14 +196,18 @@ void KyraEngine_HoF::pauseEngineIntern(bool pause) { _seqWsaChatTimeout += pausedTime; _seqWsaChatFrameTimeout += pausedTime; - for (int x = 0; x < 10; x++) { - if (_activeText[x].duration != -1) - _activeText[x].startTime += pausedTime; + if (_activeText) { + for (int x = 0; x < 10; x++) { + if (_activeText[x].duration != -1) + _activeText[x].startTime += pausedTime; + } } - for (int x = 0; x < 8; x++) { - if (_activeWSA[x].flags != -1) - _activeWSA[x].nextFrame += pausedTime; + if (_activeWSA) { + for (int x = 0; x < 8; x++) { + if (_activeWSA[x].flags != -1) + _activeWSA[x].nextFrame += pausedTime; + } } _nextIdleAnim += pausedTime; @@ -1505,15 +1509,19 @@ void KyraEngine_HoF::openTalkFile(int newFile) { _oldTalkFile = -1; } - if (newFile == 0) { + if (newFile == 0) strcpy(talkFilename, "ANYTALK.TLK"); - _res->loadPakFile(talkFilename); - } else { + else sprintf(talkFilename, "CH%dVOC.TLK", newFile); - _res->loadPakFile(talkFilename); - } _oldTalkFile = newFile; + + if (!_res->loadPakFile(talkFilename)) { + if (speechEnabled()) { + warning("Couldn't load file '%s' falling back to text only mode", talkFilename); + _configVoice = 0; + } + } } void KyraEngine_HoF::snd_playVoiceFile(int id) { @@ -1549,7 +1557,8 @@ void KyraEngine_HoF::playVoice(int high, int low) { if (!_flags.isTalkie) return; int vocFile = high * 10000 + low * 10; - snd_playVoiceFile(vocFile); + if (speechEnabled()) + snd_playVoiceFile(vocFile); } void KyraEngine_HoF::snd_playSoundEffect(int track, int volume) { diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h index 279e9e35a6..f6e887c648 100644 --- a/engines/kyra/kyra_hof.h +++ b/engines/kyra/kyra_hof.h @@ -302,8 +302,7 @@ protected: static const int8 _dosTrackMap[]; static const int _dosTrackMapSize; - const AudioDataStruct *_soundData; - + AudioDataStruct _soundData[3]; protected: // game initialization void startup(); diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp index f668ae8401..afd164958c 100644 --- a/engines/kyra/kyra_lok.cpp +++ b/engines/kyra/kyra_lok.cpp @@ -173,8 +173,7 @@ int KyraEngine_LoK::init() { initStaticResource(); - if (_soundData) - _sound->setSoundList(&_soundData[kMusicIntro]); + _sound->setSoundList(&_soundData[kMusicIntro]); _trackMap = _dosTrackMap; _trackMapSize = _dosTrackMapSize; @@ -317,8 +316,7 @@ void KyraEngine_LoK::startup() { debugC(9, kDebugLevelMain, "KyraEngine_LoK::startup()"); static const uint8 colorMap[] = { 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0 }; _screen->setTextColorMap(colorMap); - if (_soundData) - _sound->setSoundList(&_soundData[kMusicIngame]); + _sound->setSoundList(&_soundData[kMusicIngame]); _sound->loadSoundFile(0); // _screen->setFont(Screen::FID_6_FNT); _screen->setAnimBlockPtr(3750); diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h index cb3062847e..1def95ddbf 100644 --- a/engines/kyra/kyra_lok.h +++ b/engines/kyra/kyra_lok.h @@ -633,7 +633,7 @@ protected: int _soundFilesIntroSize; const int32 *_cdaTrackTable; int _cdaTrackTableSize; - const AudioDataStruct * _soundData; + AudioDataStruct _soundData[3]; // positions of the inventory static const uint16 _itemPosX[]; diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index 7097543750..45a277c400 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -508,7 +508,8 @@ void KyraEngine_MR::snd_playVoiceFile(int file) { char filename[16]; snprintf(filename, 16, "%.08u", (uint)file); - _voiceSoundChannel = _soundDigital->playSound(filename, 0xFE, Audio::Mixer::kSpeechSoundType, 255); + if (speechEnabled()) + _voiceSoundChannel = _soundDigital->playSound(filename, 0xFE, Audio::Mixer::kSpeechSoundType, 255); } bool KyraEngine_MR::snd_voiceIsPlaying() { @@ -802,7 +803,12 @@ void KyraEngine_MR::openTalkFile(int file) { } _currentTalkFile = file; - _res->loadPakFile(talkFilename); + if (!_res->loadPakFile(talkFilename)) { + if (speechEnabled()) { + warning("Couldn't load file '%s' falling back to text only mode", talkFilename); + _configVoice = 0; + } + } } #pragma mark - diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 6d61bd997f..f4f845c5f7 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -70,9 +70,9 @@ enum { struct AudioDataStruct { const char * const *_fileList; - const int _fileListLen; - const void * const _cdaTracks; - const int _cdaNumTracks; + int _fileListLen; + const void * _cdaTracks; + int _cdaNumTracks; }; // TODO: this is just the start of makeing the debug output of the kyra engine a bit more useable diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 7d7f0cd4b8..bb63c24c36 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1055,32 +1055,48 @@ void KyraEngine_LoK::initStaticResource() { static const char *tIntro98[] = { "intro%d.dat" }; static const char *tIngame98[] = { "kyram%d.dat" }; - static const AudioDataStruct soundData_PC[] = { - { _soundFilesIntro, _soundFilesIntroSize, 0, 0 }, - { _soundFiles, _soundFilesSize, 0, 0 }, - { 0, 0, 0, 0} - }; - - static const AudioDataStruct soundData_TOWNS[] = { - { _soundFiles, _soundFilesSize, _cdaTrackTable, _cdaTrackTableSize }, - { _soundFiles, _soundFilesSize, _cdaTrackTable, _cdaTrackTableSize }, - { 0, 0, 0, 0} - }; - - static const AudioDataStruct soundData_PC98[] = { - { tIntro98, 1, 0, 0 }, - { tIngame98, 1, 0, 0 }, - { 0, 0, 0, 0} - }; - - if (_flags.platform == Common::kPlatformPC) - _soundData = soundData_PC; - else if (_flags.platform == Common::kPlatformFMTowns) - _soundData = soundData_TOWNS; - else if (_flags.platform == Common::kPlatformPC98) - _soundData = soundData_PC98; - else - _soundData = 0; + if (_flags.platform == Common::kPlatformPC) { + _soundData[0]._fileList = _soundFilesIntro; + _soundData[0]._fileListLen = _soundFilesIntroSize; + _soundData[0]._cdaTracks = 0; + _soundData[0]._cdaNumTracks = 0; + _soundData[1]._fileList = _soundFiles; + _soundData[1]._fileListLen = _soundFilesSize; + _soundData[1]._cdaTracks = 0; + _soundData[1]._cdaNumTracks = 0; + _soundData[2]._fileList = 0; + _soundData[2]._fileListLen = 0; + _soundData[2]._cdaTracks = 0; + _soundData[2]._cdaNumTracks = 0; + } else if (_flags.platform == Common::kPlatformFMTowns) { + _soundData[0]._fileList = _soundFiles; + _soundData[0]._fileListLen = _soundFilesSize; + _soundData[0]._cdaTracks = _cdaTrackTable; + _soundData[0]._cdaNumTracks = _cdaTrackTableSize; + _soundData[1]._fileList = _soundFiles; + _soundData[1]._fileListLen = _soundFilesSize; + _soundData[1]._cdaTracks = _cdaTrackTable; + _soundData[1]._cdaNumTracks = _cdaTrackTableSize; + _soundData[2]._fileList = 0; + _soundData[2]._fileListLen = 0; + _soundData[2]._cdaTracks = 0; + _soundData[2]._cdaNumTracks = 0; + } else if (_flags.platform == Common::kPlatformPC98) { + _soundData[0]._fileList = tIntro98; + _soundData[0]._fileListLen = 1; + _soundData[0]._cdaTracks = 0; + _soundData[0]._cdaNumTracks = 0; + _soundData[1]._fileList = tIngame98; + _soundData[1]._fileListLen = 1; + _soundData[1]._cdaTracks = 0; + _soundData[1]._cdaNumTracks = 0; + _soundData[2]._fileList = 0; + _soundData[2]._fileListLen = 0; + _soundData[2]._cdaTracks = 0; + _soundData[2]._cdaNumTracks = 0; + } else { + memset(_soundData, 0, sizeof(_soundData)); + } } void KyraEngine_LoK::loadMouseShapes() { @@ -1282,30 +1298,46 @@ void KyraEngine_HoF::initStaticResource() { static const char *pc98MusicFileListFinale[] = { "finale%d.86" }; static const char *pc98MusicFileListIngame[] = { "km%02d.86" }; - static const AudioDataStruct soundData_PC[] = { - { _musicFileListIntro, _musicFileListIntroSize, 0, 0 }, - { _musicFileListIngame, _musicFileListIngameSize, 0, 0}, - { _musicFileListFinale, _musicFileListIntroSize, 0, 0 } - }; - - static const AudioDataStruct soundData_TOWNS[] = { - { fmtMusicFileListIntro, 1, _cdaTrackTableIntro, _cdaTrackTableIntroSize >> 1 }, - { fmtMusicFileListIngame, 1, _cdaTrackTableIngame, _cdaTrackTableIngameSize >> 1 }, - { fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 } - }; - - static const AudioDataStruct soundData_PC98[] = { - { pc98MusicFileListIntro, 1, 0, 0 }, - { pc98MusicFileListIngame, 1, 0, 0 }, - { pc98MusicFileListFinale, 1, 0, 0 } - }; - - if (_flags.platform == Common::kPlatformPC) - _soundData = soundData_PC; - else if (_flags.platform == Common::kPlatformFMTowns) - _soundData = soundData_TOWNS; - else if (_flags.platform == Common::kPlatformPC98) - _soundData = soundData_PC98; + if (_flags.platform == Common::kPlatformPC) { + _soundData[0]._fileList = _musicFileListIntro; + _soundData[0]._fileListLen = _musicFileListIntroSize; + _soundData[0]._cdaTracks = 0; + _soundData[0]._cdaNumTracks = 0; + _soundData[1]._fileList = _musicFileListIngame; + _soundData[1]._fileListLen = _musicFileListIngameSize; + _soundData[1]._cdaTracks = 0; + _soundData[1]._cdaNumTracks = 0; + _soundData[2]._fileList = _musicFileListFinale; + _soundData[2]._fileListLen = _musicFileListIntroSize; + _soundData[2]._cdaTracks = 0; + _soundData[2]._cdaNumTracks = 0; + } else if (_flags.platform == Common::kPlatformFMTowns) { + _soundData[0]._fileList = fmtMusicFileListIntro; + _soundData[0]._fileListLen = 1; + _soundData[0]._cdaTracks = _cdaTrackTableIntro; + _soundData[0]._cdaNumTracks = _cdaTrackTableIntroSize >> 1; + _soundData[1]._fileList = fmtMusicFileListIngame; + _soundData[1]._fileListLen = 1; + _soundData[1]._cdaTracks = _cdaTrackTableIngame; + _soundData[1]._cdaNumTracks = _cdaTrackTableIngameSize >> 1; + _soundData[2]._fileList = fmtMusicFileListFinale; + _soundData[2]._fileListLen = 1; + _soundData[2]._cdaTracks = _cdaTrackTableFinale; + _soundData[2]._cdaNumTracks = _cdaTrackTableFinaleSize >> 1; + } else if (_flags.platform == Common::kPlatformPC98) { + _soundData[0]._fileList = pc98MusicFileListIntro; + _soundData[0]._fileListLen = 1; + _soundData[0]._cdaTracks = 0; + _soundData[0]._cdaNumTracks = 0; + _soundData[1]._fileList = pc98MusicFileListIngame; + _soundData[1]._fileListLen = 1; + _soundData[1]._cdaTracks = 0; + _soundData[1]._cdaNumTracks = 0; + _soundData[2]._fileList = pc98MusicFileListFinale; + _soundData[2]._fileListLen = 1; + _soundData[2]._cdaTracks = 0; + _soundData[2]._cdaNumTracks = 0; + } // setup sequence data _sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize); diff --git a/sound/midiparser.h b/sound/midiparser.h index d5209acb10..304a9d9f82 100644 --- a/sound/midiparser.h +++ b/sound/midiparser.h @@ -352,6 +352,8 @@ public: }; public: + typedef void (*XMidiCallbackProc)(byte eventData, void *refCon); + MidiParser(); virtual ~MidiParser() { allNotesOff(); } @@ -370,8 +372,10 @@ public: uint32 getPPQN() { return _ppqn; } virtual uint32 getTick() { return _position._play_tick; } + static void defaultXMidiCallback(byte eventData, void *refCon); + static MidiParser *createParser_SMF(); - static MidiParser *createParser_XMIDI(); + static MidiParser *createParser_XMIDI(XMidiCallbackProc proc = defaultXMidiCallback, void *refCon = 0); static void timerCallback(void *data) { ((MidiParser *) data)->onTimer(); } }; diff --git a/sound/midiparser_xmidi.cpp b/sound/midiparser_xmidi.cpp index abc1e20076..0180322927 100644 --- a/sound/midiparser_xmidi.cpp +++ b/sound/midiparser_xmidi.cpp @@ -46,13 +46,16 @@ protected: Loop _loop[4]; int _loopCount; + XMidiCallbackProc _callbackProc; + void *_callbackData; + protected: uint32 readVLQ2(byte * &data); void resetTracking(); void parseNextEvent(EventInfo &info); public: - MidiParser_XMIDI() : _inserted_delta(0) {} + MidiParser_XMIDI(XMidiCallbackProc proc, void *data) : _inserted_delta(0), _callbackProc(proc), _callbackData(data) {} ~MidiParser_XMIDI() { } bool loadMusic(byte *data, uint32 size); @@ -103,23 +106,22 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { info.basic.param1 = *(_position._play_pos++); info.basic.param2 = *(_position._play_pos++); + // This isn't a full XMIDI implementation, but it should + // hopefully be "good enough" for most things. + + switch (info.basic.param1) { // Simplified XMIDI looping. - // - // I would really like to turn the loop events into some sort - // of NOP event (perhaps a dummy META event?), but for now we - // just pass them on to the MIDI driver. That has worked in the - // past, so it shouldn't cause any actual damage... - - if (info.basic.param1 == 0x74) { - // XMIDI_CONTROLLER_FOR_LOOP - byte *pos = _position._play_pos; - if (_loopCount < ARRAYSIZE(_loop) - 1) - _loopCount++; - - _loop[_loopCount].pos = pos; - _loop[_loopCount].repeat = info.basic.param2; - } else if (info.basic.param1 == 0x75) { - // XMIDI_CONTROLLER_NEXT_BREAK + case 0x74: { // XMIDI_CONTROLLER_FOR_LOOP + byte *pos = _position._play_pos; + if (_loopCount < ARRAYSIZE(_loop) - 1) + _loopCount++; + + _loop[_loopCount].pos = pos; + _loop[_loopCount].repeat = info.basic.param2; + break; + } + + case 0x75: // XMIDI_CONTORLLER_NEXT_BREAK if (_loopCount >= 0) { if (info.basic.param2 < 64) { // End the current loop. @@ -133,10 +135,26 @@ void MidiParser_XMIDI::parseNextEvent(EventInfo &info) { } } } - } else if (info.basic.param1 >= 0x6e && info.basic.param1 <= 0x78) { - warning("Unsupported XMIDI controller %d (0x%2x)", - info.basic.param1, info.basic.param1); + break; + + case 0x77: // XMIDI_CONTROLLER_CALLBACK_TRIG + if (_callbackProc) + _callbackProc(info.basic.param2, _callbackData); + break; + + default: + if (info.basic.param1 >= 0x6e && info.basic.param1 <= 0x78) { + warning("Unsupported XMIDI controller %d (0x%2x)", + info.basic.param1, info.basic.param1); + } + break; } + + // Should we really keep passing the XMIDI controller events to + // the MIDI driver, or should we turn them into some kind of + // NOP events? (Dummy meta events, perhaps?) Ah well, it has + // worked so far, so it shouldn't cause any damage... + break; case 0xF: // Meta or SysEx event @@ -336,4 +354,10 @@ void MidiParser_XMIDI::resetTracking() { _inserted_delta = 0; } -MidiParser *MidiParser::createParser_XMIDI() { return new MidiParser_XMIDI; } +void MidiParser::defaultXMidiCallback(byte eventData, void *data) { + warning("MidiParser: defaultXMidiCallback(%d)", eventData); +} + +MidiParser *MidiParser::createParser_XMIDI(XMidiCallbackProc proc, void *data) { + return new MidiParser_XMIDI(proc, data); +} |