From c874ff15a8e95acb85940ba5de0243b93077cc9d Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 23 May 2010 10:28:03 +0000 Subject: [PATCH 001/249] Cleaned up the game ID code: - The game ID is now obtained from ScummVM ID directly, not by converting Sierra's internal ID - Moved the code which reads the internal Sierra ID inside the resource manager - Moved the code which converts the internal Sierra ID to ScummVM's IDs together with the rest of the detection code svn-id: r49152 --- engines/sci/console.cpp | 3 +- engines/sci/detection.cpp | 172 ++++++++++++++++++++++++------- engines/sci/engine/game.cpp | 139 ------------------------- engines/sci/engine/kgraphics.cpp | 8 +- engines/sci/engine/kmisc.cpp | 4 +- engines/sci/engine/kmovement.cpp | 2 +- engines/sci/engine/kpathing.cpp | 4 +- engines/sci/engine/savegame.cpp | 1 - engines/sci/engine/state.h | 2 - engines/sci/engine/vm.cpp | 2 +- engines/sci/graphics/gui.cpp | 2 +- engines/sci/graphics/ports.cpp | 3 +- engines/sci/graphics/ports.h | 2 +- engines/sci/resource.cpp | 35 +++++++ engines/sci/resource.h | 5 + engines/sci/sci.cpp | 2 +- 16 files changed, 191 insertions(+), 195 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 540b7c84d84..f73932bcb1f 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -421,10 +421,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"); diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index beea025aeac..fc81a4671db 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -120,6 +120,140 @@ 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 + { "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(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 *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; +} + #include "sci/detection_tables.h" /** @@ -205,42 +339,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; @@ -352,7 +450,7 @@ 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 gameId = convertSierraGameId(resMan->findSierraGameId(), &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; diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 4ac2a22531f..d7fdd9be6e0 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 *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) @@ -265,10 +130,6 @@ int game_init(EngineState *s) { // 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)); #ifdef USE_OLD_MUSIC_FUNCTIONS if (s->sfx_init_flags & SFX_STATE_FLAG_NOSOUND) diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index d587790b6c4..abc7efd7438 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -525,7 +525,7 @@ 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) { + if (!strcmp(g_sci->getGameID(), "lsl1sci") && s->currentRoomNumber() == 300) { int top = GET_SEL32V(s->_segMan, object, SELECTOR(brTop)); PUT_SEL32V(s->_segMan, object, SELECTOR(brTop), top + 2); } @@ -799,7 +799,7 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) { // 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") + if (!strcmp(g_sci->getGameID(), "jones")) priority = GET_SEL32V(s->_segMan, controlObject, SELECTOR(priority)); else priority = -1; @@ -983,7 +983,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 +994,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)) diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 450dca37709..74368b8c714 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -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; } diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp index fcaf0d7ea01..5acda3a3254 100644 --- a/engines/sci/engine/kmovement.cpp +++ b/engines/sci/engine/kmovement.cpp @@ -334,7 +334,7 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) { } // 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_01) || !strcmp(g_sci->getGameID(), "iceman")) if (completed) invoke_selector(INV_SEL(s, mover, moveDone, kStopOnInvalidSelector), 0); diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index 25d967c247e..1152addeba1 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -1056,7 +1056,7 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) { // 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"); @@ -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); diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index fef2b9a19e1..2532d174a1f 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -997,7 +997,6 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { retval->_voc->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE); retval->successor = NULL; - retval->_gameId = s->_gameId; #ifdef USE_OLD_MUSIC_FUNCTIONS retval->_sound._it = NULL; diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index c4b995806f9..ad2b0f70585 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -105,8 +105,6 @@ public: SegManager *_segMan; /**< The segment manager */ Vocabulary *_voc; - Common::String _gameId; /**< Designation of the primary object (which inherits from Game) */ - /* Non-VM information */ SciEvent *_event; // Event handling diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index e2ee2e19717..bf447419e8a 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -1732,7 +1732,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- diff --git a/engines/sci/graphics/gui.cpp b/engines/sci/graphics/gui.cpp index 46f7fcd6890..29ab64ddb27 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); } diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp index ab3291dd79d..cdb6fe4ae11 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 0876d9e4424..c8ce6b34703 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/resource.cpp b/engines/sci/resource.cpp index 4888dbd4cb1..aa3b8019de0 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -2329,6 +2329,41 @@ bool ResourceManager::hasSci1Voc900() { return offset == res->size; } +#define READ_UINT16(ptr) (!isSci11Mac() ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) + +Common::String ResourceManager::findSierraGameId() { + Resource *script = 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 = 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 + SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersion soundVersion) : _resMan(resMan), _soundVersion(soundVersion) { Resource *resource = _resMan->findResource(ResourceId(kResourceTypeSound, resNumber), true); int trackNr, channelNr; diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 48b5f095b18..befda072e08 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -273,6 +273,11 @@ 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(); + 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 diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 4862d0579ac..bb5124b88bf 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -222,7 +222,7 @@ 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()); From 8ed56e1834487f44c94c6b5c5a4353bb3a889696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20Andersson?= Date: Sun, 23 May 2010 10:50:14 +0000 Subject: [PATCH 002/249] Keep the Broken Sword cutscene players from using up all available CPU. Probably a regression from the recent video decoder rewrite, but I haven't checked if it also present in other engines. svn-id: r49153 --- engines/sword1/animation.cpp | 2 ++ engines/sword2/animation.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index c0e7be7758d..a16f0006595 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -267,6 +267,8 @@ 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(); diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index c3f3e796b20..5eab7f56453 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -293,6 +293,8 @@ 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(); From 1b294306dd49fb8b97f0e74d94b6c4a89403191c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20Andersson?= Date: Sun, 23 May 2010 11:16:10 +0000 Subject: [PATCH 003/249] Another video player regression: When the palette changes, look up the lightest/darkest available colours to use as white/black for the subtitles. It is possible that we could get away with fixed values for Broken Sword 2, since it has always had subtitles. But for Broken Sword 1, subtitles is a ScummVM addition, and we can't. svn-id: r49154 --- engines/sword1/animation.cpp | 36 ++++++++++++++++++++++++++++++++---- engines/sword1/animation.h | 1 + engines/sword2/animation.cpp | 35 ++++++++++++++++++++++++++++++++--- engines/sword2/animation.h | 1 + 4 files changed, 66 insertions(+), 7 deletions(-) diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index a16f0006595..441e6221840 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(); @@ -275,11 +303,11 @@ bool MoviePlayer::playVideo() { } 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 82343f2800d..193d5cf7ca7 100644 --- a/engines/sword1/animation.h +++ b/engines/sword1/animation.h @@ -85,6 +85,7 @@ protected: OSystem *_system; Common::Array _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 5eab7f56453..10895b2ec11 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(); @@ -301,11 +330,11 @@ bool MoviePlayer::playVideo() { } 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 bbf83e264cc..ee32b1d5f24 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; From 20c654f63b29a5eb120e5d7d72d06080995a463a Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Sun, 23 May 2010 11:48:21 +0000 Subject: [PATCH 004/249] PSP: replaced SDL's timer with much simpler and more efficient PspTimer class svn-id: r49155 --- backends/platform/psp/Makefile | 3 +- backends/platform/psp/audio.cpp | 3 +- backends/platform/psp/display_manager.cpp | 3 +- backends/platform/psp/module.mk | 3 +- backends/platform/psp/osys_psp.cpp | 11 ++-- backends/platform/psp/osys_psp.h | 2 + backends/platform/psp/psp_main.cpp | 3 +- backends/platform/psp/timer.cpp | 80 +++++++++++++++++++++++ backends/platform/psp/timer.h | 47 +++++++++++++ 9 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 backends/platform/psp/timer.cpp create mode 100644 backends/platform/psp/timer.h diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index 6967973da75..6acd8e970ab 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -148,7 +148,8 @@ OBJS := powerman.o \ trace.o \ psploader.o \ pspkeyboard.o \ - audio.o + audio.o \ + timer.o # Include common Scummvm makefile include $(srcdir)/Makefile.common diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp index c19cbb52a2c..58b22518114 100644 --- a/backends/platform/psp/audio.cpp +++ b/backends/platform/psp/audio.cpp @@ -29,6 +29,7 @@ #include "common/scummsys.h" #include "backends/platform/psp/audio.h" +#include "backends/platform/psp/thread.h" //#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ //#define __PSP_DEBUG_PRINT__ /* For debug printouts */ @@ -93,7 +94,7 @@ bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, call bool PspAudio::createThread() { DEBUG_ENTER_FUNC(); - int threadId = sceKernelCreateThread("audioThread", thread, 30, 16*1024, THREAD_ATTR_USER, 0); + int threadId = sceKernelCreateThread("audioThread", thread, PRIORITY_AUDIO_THREAD, STACK_AUDIO_THREAD, THREAD_ATTR_USER, 0); if (threadId < 0) { // error PSP_ERROR("failed to create audio thread. Error code %d\n", threadId); diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp index 0982512a866..c2f21e084b3 100644 --- a/backends/platform/psp/display_manager.cpp +++ b/backends/platform/psp/display_manager.cpp @@ -34,6 +34,7 @@ #include "backends/platform/psp/default_display_client.h" #include "backends/platform/psp/cursor.h" #include "backends/platform/psp/pspkeyboard.h" +#include "backends/platform/psp/thread.h" #define USE_DISPLAY_CALLBACK // to use callback for finishing the render #include "backends/platform/psp/display_manager.h" @@ -64,7 +65,7 @@ const OSystem::GraphicsMode DisplayManager::_supportedModes[] = { void MasterGuRenderer::setupCallbackThread() { DEBUG_ENTER_FUNC(); - int thid = sceKernelCreateThread("displayCbThread", guCallbackThread, 0x11, 4*1024, THREAD_ATTR_USER, 0); + int thid = sceKernelCreateThread("displayCbThread", guCallbackThread, PRIORITY_DISPLAY_THREAD, STACK_DISPLAY_THREAD, THREAD_ATTR_USER, 0); PSP_DEBUG_PRINT("Display CB thread id is %x\n", thid); diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk index 0e5bd8737d1..461df629bfc 100644 --- a/backends/platform/psp/module.mk +++ b/backends/platform/psp/module.mk @@ -13,7 +13,8 @@ MODULE_OBJS := powerman.o \ trace.o \ psploader.o \ pspkeyboard.o \ - audio.o + audio.o \ + timer.o MODULE_DIRS += \ backends/platform/psp/ diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index 5f51135a9a3..f33081abbc1 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -60,9 +60,9 @@ static int timer_handler(int t) { void OSystem_PSP::initSDL() { #ifdef USE_PSP_AUDIO - SDL_Init(SDL_INIT_TIMER); + SDL_Init(0); #else - SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER); + SDL_Init(SDL_INIT_AUDIO); #endif } @@ -90,7 +90,7 @@ void OSystem_PSP::initBackend() { _inputHandler.init(); initSDL(); - + _savefile = new PSPSaveFileManager; _timer = new DefaultTimerManager(); @@ -308,7 +308,10 @@ void OSystem_PSP::delayMillis(uint msecs) { } void OSystem_PSP::setTimerCallback(TimerProc callback, int interval) { - SDL_SetTimer(interval, (SDL_TimerCallback)callback); + //SDL_SetTimer(interval, (SDL_TimerCallback)callback); + _pspTimer.setCallback((PspTimer::CallbackFunc)callback); + _pspTimer.setIntervalMs(interval); + _pspTimer.start(); } OSystem::MutexRef OSystem_PSP::createMutex(void) { diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h index 4d9cf31b188..413de0f5286 100644 --- a/backends/platform/psp/osys_psp.h +++ b/backends/platform/psp/osys_psp.h @@ -39,6 +39,7 @@ #include "backends/platform/psp/display_manager.h" #include "backends/platform/psp/input.h" #include "backends/platform/psp/audio.h" +#include "backends/platform/psp/timer.h" #include @@ -57,6 +58,7 @@ private: PSPKeyboard _keyboard; InputHandler _inputHandler; PspAudio _audio; + PspTimer _pspTimer; void initSDL(); diff --git a/backends/platform/psp/psp_main.cpp b/backends/platform/psp/psp_main.cpp index e5681849908..e6940eba139 100644 --- a/backends/platform/psp/psp_main.cpp +++ b/backends/platform/psp/psp_main.cpp @@ -39,6 +39,7 @@ #include #include #include "backends/platform/psp/powerman.h" +#include "backends/platform/psp/thread.h" #include "backends/plugins/psp/psp-provider.h" #include "backends/platform/psp/psppixelformat.h" @@ -140,7 +141,7 @@ int CallbackThread(SceSize /*size*/, void *arg) { /* Sets up the callback thread and returns its thread id */ int SetupCallbacks(void) { - int thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, THREAD_ATTR_USER, 0); + int thid = sceKernelCreateThread("power_thread", CallbackThread, PRIORITY_POWER_THREAD, STACK_POWER_THREAD, THREAD_ATTR_USER, 0); if (thid >= 0) { sceKernelStartThread(thid, 0, 0); } diff --git a/backends/platform/psp/timer.cpp b/backends/platform/psp/timer.cpp new file mode 100644 index 00000000000..a35bd9d8278 --- /dev/null +++ b/backends/platform/psp/timer.cpp @@ -0,0 +1,80 @@ +/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + +#include + +#include "common/scummsys.h" +#include "common/timer.h" +#include "backends/platform/psp/thread.h" +#include "backends/platform/psp/timer.h" + +//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ +//#define __PSP_DEBUG_PRINT__ /* For debug printouts */ + +#include "backends/platform/psp/trace.h" + +bool PspTimer::start() { + DEBUG_ENTER_FUNC(); + + if (!_interval || !_callback) + return false; + + _threadId = sceKernelCreateThread("timerThread", thread, PRIORITY_TIMER_THREAD, STACK_TIMER_THREAD, THREAD_ATTR_USER, 0); + + if (_threadId < 0) { // error + PSP_ERROR("failed to create timer thread. Error code %d\n", _threadId); + return false; + } + + PspTimer *_this = this; // trick to get into context when the thread starts + _init = true; + + if (sceKernelStartThread(_threadId, sizeof(uint32 *), &_this) < 0) { + PSP_ERROR("failed to start thread %d\n", _threadId); + return false; + } + + PSP_DEBUG_PRINT("created timer thread[%x]\n", _threadId); + + return true; +} + +int PspTimer::thread(SceSize, void *__this) { + DEBUG_ENTER_FUNC(); + PspTimer *_this = *(PspTimer **)__this; // get our this for the context + + _this->timerThread(); + return 0; +}; + +void PspTimer::timerThread() { + DEBUG_ENTER_FUNC(); + + while (_init) { + sceKernelDelayThread(_interval); + PSP_DEBUG_PRINT("calling callback!\n"); + _callback(); + } +}; diff --git a/backends/platform/psp/timer.h b/backends/platform/psp/timer.h new file mode 100644 index 00000000000..ec31addb727 --- /dev/null +++ b/backends/platform/psp/timer.h @@ -0,0 +1,47 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $ + * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $ + * + */ + +#ifndef PSP_TIMER_H +#define PSP_TIMER_H + +class PspTimer { +public: + typedef void (* CallbackFunc)(void); + PspTimer() : _callback(0), _interval(0), _threadId(-1), _init(false) {} + void stop() { _init = false; } + bool start(); + ~PspTimer() { stop(); } + void setCallback(CallbackFunc cb) { _callback = cb; } + void setIntervalMs(uint32 interval) { _interval = interval * 1000; } + static int thread(SceSize, void *__this); // static thread to use as bridge + void timerThread(); +private: + CallbackFunc _callback; // pointer to timer callback + uint32 _interval; + int _threadId; + bool _init; +}; + +#endif From aa4ae667a99219ef66bad260e29b468c7f6afa7e Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Sun, 23 May 2010 12:22:23 +0000 Subject: [PATCH 005/249] SCI: use priority when queuing up music in sound sci0 -> fixes lsl3 jingle issues svn-id: r49156 --- engines/sci/sound/music.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 66f5ce97105..27074e2db6a 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -243,14 +243,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 +261,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; + } } } From d27e32aa196afec2f2df20fea943a4b6978650b3 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Sun, 23 May 2010 13:22:58 +0000 Subject: [PATCH 006/249] SCI: fix regression of r49156 - if multiple songs are stored for resume-play, use the last one - fixes iceman wrong music played after going through door in room 14 - still not sure about this, added fixme svn-id: r49157 --- engines/sci/sound/soundcmd.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 925f3b2e1a0..272337148ca 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -1058,8 +1058,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) From b069b9fe9691f1285446a89152cb9e295d15807c Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Sun, 23 May 2010 16:42:49 +0000 Subject: [PATCH 007/249] SCI: reenabling "stopAllSounds" code disabled in r49101 - isn't called anymore since priority is honored so it may have been right after all svn-id: r49158 --- engines/sci/sound/soundcmd.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 272337148ca..40e36373720 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -927,11 +927,6 @@ 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) { From 9be4f6250cc88a1638299b3661b9896f4ebf57ed Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 23 May 2010 16:44:36 +0000 Subject: [PATCH 008/249] Made shrink_execution_stack() a member of EngineState svn-id: r49159 --- engines/sci/engine/kmisc.cpp | 2 +- engines/sci/engine/savegame.cpp | 2 +- engines/sci/engine/state.cpp | 9 +++++++++ engines/sci/engine/state.h | 6 ++++++ engines/sci/engine/vm.cpp | 13 ++----------- engines/sci/engine/vm.h | 6 ------ 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 74368b8c714..22295dca41f 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -39,7 +39,7 @@ 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 return NULL_REG; diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 2532d174a1f..8dc06dab018 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -1025,7 +1025,7 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { s->successor = retval; // Set successor script_abort_flag = 2; // Abort current game with replay - shrink_execution_stack(s, s->execution_stack_base + 1); + s->shrinkStackToBase(); } bool get_savegame_metadata(Common::SeekableReadStream *stream, SavegameMetadata *meta) { diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index bd78639c778..dfc4c39464e 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -135,6 +135,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::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': diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index ad2b0f70585..cc7b3713082 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -155,6 +155,12 @@ public: uint16 currentRoomNumber() const; void setRoomNumber(uint16 roomNumber); + /** + * Shrink execution stack to size. + * Contains an assert it is not already smaller. + */ + void shrinkStackToBase(); + /* System strings */ SegmentId sys_strings_segment; SystemStrings *sys_strings; diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index bf447419e8a..1e252dac466 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -724,7 +724,7 @@ 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 @@ -1183,7 +1183,7 @@ void run_vm(EngineState *s, bool restoring) { StackPtr old_fp = scriptState.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(); @@ -1756,15 +1756,6 @@ void quit_vm() { g_debugState.runningStep = 0; } -void shrink_execution_stack(EngineState *s, uint size) { - assert(s->_executionStack.size() >= size); - Common::List::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 { Object *o = segMan->getObject(obj); if (!o) return 0; diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 8e40fed8187..97a01051d64 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -468,12 +468,6 @@ int game_exit(EngineState *s); */ void quit_vm(); -/** - * Shrink execution stack to size. - * Contains an assert it is not already smaller. - */ -void shrink_execution_stack(EngineState *s, uint size); - /** * Read a PMachine instruction from a memory buffer and return its length. * From db74441d558103c626d1ec078583b0266a190e5d Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Sun, 23 May 2010 16:59:09 +0000 Subject: [PATCH 009/249] SCI: fixing crash in _vocab_add_rule when running qfg2 demo svn-id: r49160 --- engines/sci/parser/grammar.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/engines/sci/parser/grammar.cpp b/engines/sci/parser/grammar.cpp index 1cfe84076fb..070e6767cf6 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); From 7cd9a23c0d11b451979aeea66a6bb325b2d31341 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 23 May 2010 17:03:16 +0000 Subject: [PATCH 010/249] Remove the unused SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE flag svn-id: r49161 --- engines/sci/console.cpp | 16 ---------------- engines/sci/engine/kmisc.cpp | 1 - engines/sci/engine/state.h | 3 +-- engines/sci/engine/vm.cpp | 2 +- 4 files changed, 2 insertions(+), 20 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index f73932bcb1f..6bd7adfdb7c 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -920,22 +920,6 @@ 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; diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 22295dca41f..aee1d58357a 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -37,7 +37,6 @@ 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 s->shrinkStackToBase(); diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index cc7b3713082..ad9de9e13e3 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 { diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 1e252dac466..7b6763f8f23 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -1701,7 +1701,7 @@ 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->restarting_flags = SCI_GAME_WAS_RESTARTED; } else { successor = s->successor; From e321e255147fc93a76518c92bcd521771f3ca651 Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Sun, 23 May 2010 17:35:31 +0000 Subject: [PATCH 011/249] PSP: forgot to add a file svn-id: r49162 --- backends/platform/psp/thread.h | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 backends/platform/psp/thread.h diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h new file mode 100644 index 00000000000..5879d044ed7 --- /dev/null +++ b/backends/platform/psp/thread.h @@ -0,0 +1,46 @@ +/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/portdefs.h $ + * $Id: portdefs.h 38687 2009-02-21 12:08:52Z joostp $ + * + */ + +#ifndef PSP_THREAD_H +#define PSP_THREAD_H + +enum ThreadPriority { + PRIORITY_MAIN_THREAD = 36, + PRIORITY_AUDIO_THREAD = 35, // We'll alternate between this and main thread priority + PRIORITY_TIMER_THREAD = 30, + PRIORITY_POWER_THREAD = 20, + PRIORITY_DISPLAY_THREAD = 17 +}; + +enum StackSizes { + STACK_AUDIO_THREAD = 16 * 1024, + STACK_TIMER_THREAD = 4 * 1024, + STACK_DISPLAY_THREAD = 4 * 1024, + STACK_POWER_THREAD = 4 * 1024 +}; + +#endif /* PSP_THREADS_H */ + + From 2ffbd661ac8c8eba7fcc20df33fc902687b5698e Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Sun, 23 May 2010 17:40:42 +0000 Subject: [PATCH 012/249] SCI: removed hack for iceman in kDoBresen - fixes all sorts of automatic walking issues (like rescueing ambassador) in iceman, dancing at the beginning also still works - thx to [md5] svn-id: r49163 --- engines/sci/engine/kmovement.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp index 5acda3a3254..42e690422c2 100644 --- a/engines/sci/engine/kmovement.cpp +++ b/engines/sci/engine/kmovement.cpp @@ -333,8 +333,7 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) { completed = 1; } - // FIXME: find out why iceman needs this and we ask for version > SCI01 - if ((getSciVersion() > SCI_VERSION_01) || !strcmp(g_sci->getGameID(), "iceman")) + if ((getSciVersion() >= SCI_VERSION_1_EGA)) if (completed) invoke_selector(INV_SEL(s, mover, moveDone, kStopOnInvalidSelector), 0); From e2a388e2f59f689cd89995013236e90a1b004264 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 23 May 2010 18:03:23 +0000 Subject: [PATCH 013/249] SCI: Enabled saving from the ScummVM menu again svn-id: r49164 --- engines/sci/detection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index fc81a4671db..06a83a98dcb 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -525,8 +525,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 { From 2f31b05651baf87ea07bc00cced798955a5fa6be Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 23 May 2010 18:33:55 +0000 Subject: [PATCH 014/249] Move Mohawk's QuickTime code to graphics/ (and QDM2 to sound, disabled when Mohawk is not enabled) so SCI can use the code. svn-id: r49165 --- engines/mohawk/console.cpp | 2 +- engines/mohawk/graphics.cpp | 10 +- engines/mohawk/graphics.h | 8 +- engines/mohawk/jpeg.cpp | 87 -------- engines/mohawk/module.mk | 9 +- engines/mohawk/mohawk.cpp | 2 +- engines/mohawk/myst.cpp | 2 +- engines/mohawk/myst_pict.cpp | 5 +- engines/mohawk/myst_pict.h | 6 +- engines/mohawk/myst_scripts.cpp | 2 +- engines/mohawk/riven.cpp | 2 +- engines/mohawk/riven_external.cpp | 2 +- engines/mohawk/riven_scripts.cpp | 2 +- engines/mohawk/{video => }/video.cpp | 8 +- engines/mohawk/{video => }/video.h | 10 +- graphics/conversion.h | 7 - graphics/module.mk | 6 + graphics/video/avi_decoder.cpp | 3 + .../video/codecs}/cinepak.cpp | 27 +-- .../video => graphics/video/codecs}/cinepak.h | 18 +- graphics/video/codecs/mjpeg.cpp | 73 +++++++ .../jpeg.h => graphics/video/codecs/mjpeg.h | 25 ++- .../video => graphics/video/codecs}/qtrle.cpp | 16 +- .../video => graphics/video/codecs}/qtrle.h | 18 +- .../video => graphics/video/codecs}/rpza.cpp | 14 +- .../video => graphics/video/codecs}/rpza.h | 18 +- .../video => graphics/video/codecs}/smc.cpp | 6 +- .../video => graphics/video/codecs}/smc.h | 16 +- .../video/qt_decoder.cpp | 187 +++++++++--------- .../video/qt_decoder.h | 28 +-- .../mohawk/video => sound/decoders}/qdm2.cpp | 12 +- .../mohawk/video => sound/decoders}/qdm2.h | 15 +- .../video => sound/decoders}/qdm2data.h | 8 +- sound/module.mk | 1 + 34 files changed, 326 insertions(+), 329 deletions(-) delete mode 100644 engines/mohawk/jpeg.cpp rename engines/mohawk/{video => }/video.cpp (98%) rename engines/mohawk/{video => }/video.h (94%) rename {engines/mohawk/video => graphics/video/codecs}/cinepak.cpp (94%) rename {engines/mohawk/video => graphics/video/codecs}/cinepak.h (85%) create mode 100644 graphics/video/codecs/mjpeg.cpp rename engines/mohawk/jpeg.h => graphics/video/codecs/mjpeg.h (73%) rename {engines/mohawk/video => graphics/video/codecs}/qtrle.cpp (96%) rename {engines/mohawk/video => graphics/video/codecs}/qtrle.h (83%) rename {engines/mohawk/video => graphics/video/codecs}/rpza.cpp (94%) rename {engines/mohawk/video => graphics/video/codecs}/rpza.h (77%) rename {engines/mohawk/video => graphics/video/codecs}/smc.cpp (99%) rename {engines/mohawk/video => graphics/video/codecs}/smc.h (79%) rename engines/mohawk/video/qt_player.cpp => graphics/video/qt_decoder.cpp (88%) rename engines/mohawk/video/qt_player.h => graphics/video/qt_decoder.h (92%) rename {engines/mohawk/video => sound/decoders}/qdm2.cpp (99%) rename {engines/mohawk/video => sound/decoders}/qdm2.h (96%) rename {engines/mohawk/video => sound/decoders}/qdm2data.h (99%) diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp index 389665db391..149b6b6ebac 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/graphics.cpp b/engines/mohawk/graphics.cpp index 35691c36aa5..1b220c861bb 100644 --- a/engines/mohawk/graphics.cpp +++ b/engines/mohawk/graphics.cpp @@ -78,8 +78,7 @@ 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); + _jpegDecoder = new Graphics::JPEGDecoder(); _pictDecoder = new MystPICT(_jpegDecoder); } else { _jpegDecoder = 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 8d28e1ff4b3..23b1ace3472 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/video/codecs/mjpeg.h" namespace Mohawk { @@ -96,8 +96,8 @@ 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); @@ -105,7 +105,7 @@ private: MohawkEngine_Myst *_vm; MystBitmap *_bmpDecoder; MystPICT *_pictDecoder; - JPEGDecoder *_jpegDecoder; + 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 07ec54dfeaa..00000000000 --- 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/module.mk b/engines/mohawk/module.mk index b224a8b1435..8c23cdfa870 100644 --- a/engines/mohawk/module.mk +++ b/engines/mohawk/module.mk @@ -6,7 +6,6 @@ MODULE_OBJS = \ detection.o \ dialogs.o \ graphics.o \ - jpeg.o \ livingbooks.o \ mohawk.o \ myst.o \ @@ -22,13 +21,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 5bde6bbeec5..6b4d8bb2d2b 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 d1ef3b2137e..9ff301c129d 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 index 794ec9b87f9..2dfed65d2b5 100644 --- a/engines/mohawk/myst_pict.cpp +++ b/engines/mohawk/myst_pict.cpp @@ -32,7 +32,7 @@ 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) { +MystPICT::MystPICT(Graphics::JPEGDecoder *jpegDecoder) { _jpegDecoder = jpegDecoder; _pixelFormat = g_system->getScreenFormat(); } @@ -264,9 +264,6 @@ void MystPICT::decodeCompressedQuickTime(Common::SeekableReadStream *stream, Gra 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 index 0684e3352aa..90c06deee09 100644 --- a/engines/mohawk/myst_pict.h +++ b/engines/mohawk/myst_pict.h @@ -32,18 +32,18 @@ #include "graphics/pixelformat.h" #include "graphics/surface.h" -#include "mohawk/jpeg.h" +#include "graphics/video/codecs/mjpeg.h" namespace Mohawk { class MystPICT { public: - MystPICT(JPEGDecoder *jpegDecoder); + MystPICT(Graphics::JPEGDecoder *jpegDecoder); ~MystPICT() {} Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); private: - JPEGDecoder *_jpegDecoder; + Graphics::JPEGDecoder *_jpegDecoder; Common::Rect _imageRect; Graphics::PixelFormat _pixelFormat; diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp index a453bb0985f..2f6d178da8b 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 04121440348..744b3f2d2cf 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 { diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 99afacc5ce3..8b1ff45a66e 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" diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp index e809ad96422..fa6f3365421 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" diff --git a/engines/mohawk/video/video.cpp b/engines/mohawk/video.cpp similarity index 98% rename from engines/mohawk/video/video.cpp rename to engines/mohawk/video.cpp index 86ecd4dedf6..adca805763e 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 { @@ -316,7 +316,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 +346,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; diff --git a/engines/mohawk/video/video.h b/engines/mohawk/video.h similarity index 94% rename from engines/mohawk/video/video.h rename to engines/mohawk/video.h index a5d2bde65d3..8cfe1527fb5 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; diff --git a/graphics/conversion.h b/graphics/conversion.h index 149d7204c65..b6d230612ea 100644 --- a/graphics/conversion.h +++ b/graphics/conversion.h @@ -45,13 +45,6 @@ inline static void RGB2YUV(byte r, byte g, byte b, byte &y, byte &u, byte &v) { v = CLIP( ((r * 512) >> 10) - ((g * 429) >> 10) - ((b * 83) >> 10) + 128, 0, 255); } -/** Converting a color from YUV to RGB colorspace, Cinepak style. */ -inline static void CPYUV2RGB(byte y, byte u, byte v, byte &r, byte &g, byte &b) { - r = CLIP(y + 2 * (v - 128), 0, 255); - g = CLIP(y - (u - 128) / 2 - (v - 128), 0, 255); - b = CLIP(y + 2 * (u - 128), 0, 255); -} - // TODO: generic YUV to RGB blit /** diff --git a/graphics/module.mk b/graphics/module.mk index ff6d7f8f60e..8f916a5bccd 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -25,10 +25,16 @@ MODULE_OBJS := \ video/dxa_decoder.o \ video/flic_decoder.o \ video/mpeg_player.o \ + video/qt_decoder.o \ video/smk_decoder.o \ video/video_decoder.o \ + video/codecs/cinepak.o \ + video/codecs/mjpeg.o \ video/codecs/msrle.o \ video/codecs/msvideo1.o \ + video/codecs/qtrle.o \ + video/codecs/rpza.o \ + video/codecs/smc.o \ video/coktelvideo/indeo3.o \ video/coktelvideo/coktelvideo.o diff --git a/graphics/video/avi_decoder.cpp b/graphics/video/avi_decoder.cpp index 944c9700bdb..f19ca4aa283 100644 --- a/graphics/video/avi_decoder.cpp +++ b/graphics/video/avi_decoder.cpp @@ -35,6 +35,7 @@ #include "graphics/video/avi_decoder.h" // Codecs +#include "graphics/video/codecs/cinepak.h" #include "graphics/video/codecs/msvideo1.h" #include "graphics/video/codecs/msrle.h" @@ -379,6 +380,8 @@ Codec *AviDecoder::createCodec() { return new MSVideo1Decoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); case ID_RLE : return new MSRLEDecoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); + case ID_CVID: + return new CinepakDecoder(); default: warning ("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler)); } diff --git a/engines/mohawk/video/cinepak.cpp b/graphics/video/codecs/cinepak.cpp similarity index 94% rename from engines/mohawk/video/cinepak.cpp rename to graphics/video/codecs/cinepak.cpp index 2ffe6869ae8..d3448bb8f77 100644 --- a/engines/mohawk/video/cinepak.cpp +++ b/graphics/video/codecs/cinepak.cpp @@ -23,32 +23,33 @@ * */ -#include "mohawk/video/cinepak.h" +#include "graphics/video/codecs/cinepak.h" #include "common/system.h" -#include "graphics/conversion.h" // For YUV2RGB // Code here partially based off of ffmpeg ;) -namespace Mohawk { +namespace Graphics { + +// Convert a color from YUV to RGB colorspace, Cinepak style. +inline static void CPYUV2RGB(byte y, byte u, byte v, byte &r, byte &g, byte &b) { + r = CLIP(y + 2 * (v - 128), 0, 255); + g = CLIP(y - (u - 128) / 2 - (v - 128), 0, 255); + b = CLIP(y + 2 * (u - 128), 0, 255); +} #define PUT_PIXEL(offset, lum, u, v) \ - Graphics::CPYUV2RGB(lum, u, v, r, g, b); \ + 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() { +CinepakDecoder::CinepakDecoder() : 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() { @@ -57,7 +58,7 @@ CinepakDecoder::~CinepakDecoder() { delete[] _curFrame.strips; } -Graphics::Surface *CinepakDecoder::decodeImage(Common::SeekableReadStream *stream) { +Surface *CinepakDecoder::decodeImage(Common::SeekableReadStream *stream) { _curFrame.flags = stream->readByte(); _curFrame.length = (stream->readByte() << 16) + stream->readUint16BE(); _curFrame.width = stream->readUint16BE(); @@ -79,7 +80,7 @@ Graphics::Surface *CinepakDecoder::decodeImage(Common::SeekableReadStream *strea #endif if (!_curFrame.surface) { - _curFrame.surface = new Graphics::Surface(); + _curFrame.surface = new Surface(); _curFrame.surface->create(_curFrame.width, _curFrame.height, _pixelFormat.bytesPerPixel); } @@ -283,4 +284,4 @@ void CinepakDecoder::decodeVectors(Common::SeekableReadStream *stream, uint16 st } } -} // End of namespace Mohawk +} // End of namespace Graphics diff --git a/engines/mohawk/video/cinepak.h b/graphics/video/codecs/cinepak.h similarity index 85% rename from engines/mohawk/video/cinepak.h rename to graphics/video/codecs/cinepak.h index 3f4cbba17cc..92351cdba82 100644 --- a/engines/mohawk/video/cinepak.h +++ b/graphics/video/codecs/cinepak.h @@ -23,8 +23,8 @@ * */ -#ifndef CINEPAK_H -#define CINEPAK_H +#ifndef GRAPHICS_CINEPAK_H +#define GRAPHICS_CINEPAK_H #include "common/scummsys.h" #include "common/stream.h" @@ -34,7 +34,7 @@ #include "graphics/video/codecs/codec.h" -namespace Mohawk { +namespace Graphics { struct CinepakCodebook { byte y[4]; @@ -56,26 +56,26 @@ struct CinepakFrame { uint16 stripCount; CinepakStrip *strips; - Graphics::Surface *surface; + Surface *surface; }; -class CinepakDecoder : public Graphics::Codec { +class CinepakDecoder : public Codec { public: CinepakDecoder(); ~CinepakDecoder(); - Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); - Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; } + Surface *decodeImage(Common::SeekableReadStream *stream); + PixelFormat getPixelFormat() const { return _pixelFormat; } private: CinepakFrame _curFrame; int32 _y; - Graphics::PixelFormat _pixelFormat; + 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); }; -} +} // End of namespace Graphics #endif diff --git a/graphics/video/codecs/mjpeg.cpp b/graphics/video/codecs/mjpeg.cpp new file mode 100644 index 00000000000..76363036eed --- /dev/null +++ b/graphics/video/codecs/mjpeg.cpp @@ -0,0 +1,73 @@ +/* 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 "graphics/video/codecs/mjpeg.h" + +namespace Graphics { + +JPEGDecoder::JPEGDecoder() : Codec() { + _jpeg = new JPEG(); + _pixelFormat = g_system->getScreenFormat(); + _surface = NULL; +} + +JPEGDecoder::~JPEGDecoder() { + delete _jpeg; + + if (_surface) { + _surface->free(); + delete _surface; + } +} + +Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream* stream) { + _jpeg->read(stream); + Surface *ySurface = _jpeg->getComponent(1); + Surface *uSurface = _jpeg->getComponent(2); + Surface *vSurface = _jpeg->getComponent(3); + + if (!_surface) { + _surface = new Surface(); + _surface->create(ySurface->w, ySurface->h, _pixelFormat.bytesPerPixel); + } + + for (uint16 i = 0; i < _surface->h; i++) { + for (uint16 j = 0; j < _surface->w; j++) { + byte r = 0, g = 0, b = 0; + YUV2RGB(*((byte *)ySurface->getBasePtr(j, i)), *((byte *)uSurface->getBasePtr(j, i)), *((byte *)vSurface->getBasePtr(j, i)), r, g, b); + if (_pixelFormat.bytesPerPixel == 2) + *((uint16 *)_surface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b); + else + *((uint32 *)_surface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b); + } + } + + return _surface; +} + +} // End of namespace Graphics diff --git a/engines/mohawk/jpeg.h b/graphics/video/codecs/mjpeg.h similarity index 73% rename from engines/mohawk/jpeg.h rename to graphics/video/codecs/mjpeg.h index ec87b1e7af5..ab364fb5be0 100644 --- a/engines/mohawk/jpeg.h +++ b/graphics/video/codecs/mjpeg.h @@ -23,8 +23,8 @@ * */ -#ifndef MOHAWK_JPEG_H -#define MOHAWK_JPEG_H +#ifndef GRAPHICS_MJPEG_H +#define GRAPHICS_MJPEG_H #include "common/scummsys.h" #include "common/stream.h" @@ -33,27 +33,26 @@ #include "graphics/jpeg.h" #include "graphics/pixelformat.h" -namespace Mohawk { +namespace Graphics { -// Mohawk's JPEG Decoder +// Motion JPEG Decoder // Basically a wrapper around JPEG which converts to RGB and also functions // as a Codec. -class JPEGDecoder : public Graphics::Codec { +class JPEGDecoder : public Codec { public: - JPEGDecoder(bool freeSurfaceAfterUse); + JPEGDecoder(); ~JPEGDecoder(); - Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); - Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; } + Surface *decodeImage(Common::SeekableReadStream *stream); + PixelFormat getPixelFormat() const { return _pixelFormat; } private: - Graphics::PixelFormat _pixelFormat; - Graphics::JPEG *_jpeg; - Graphics::Surface *_surface; - bool _freeSurfaceAfterUse; + PixelFormat _pixelFormat; + JPEG *_jpeg; + Surface *_surface; }; -} // End of namespace Mohawk +} // End of namespace Graphics #endif diff --git a/engines/mohawk/video/qtrle.cpp b/graphics/video/codecs/qtrle.cpp similarity index 96% rename from engines/mohawk/video/qtrle.cpp rename to graphics/video/codecs/qtrle.cpp index c06dbefcb32..3e3fd4cfce6 100644 --- a/engines/mohawk/video/qtrle.cpp +++ b/graphics/video/codecs/qtrle.cpp @@ -26,7 +26,7 @@ // QuickTime RLE Decoder // Based off ffmpeg's QuickTime RLE decoder (written by Mike Melanson) -#include "mohawk/video/qtrle.h" +#include "graphics/video/codecs/qtrle.h" #include "common/scummsys.h" #include "common/stream.h" @@ -34,9 +34,9 @@ #include "graphics/colormasks.h" #include "graphics/surface.h" -namespace Mohawk { +namespace Graphics { -QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Graphics::Codec() { +QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Codec() { _bitsPerPixel = bitsPerPixel; _pixelFormat = g_system->getScreenFormat(); @@ -47,7 +47,7 @@ QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Gra debug(2, "QTRLE corrected width: %d", width); - _surface = new Graphics::Surface(); + _surface = new Surface(); _surface->create(width, height, _bitsPerPixel <= 8 ? 1 : _pixelFormat.bytesPerPixel); } @@ -239,7 +239,7 @@ void QTRLEDecoder::decode16(Common::SeekableReadStream *stream, uint32 rowPtr, u while (rleCode--) { // Convert from RGB555 to the format specified by the Overlay byte r = 0, g = 0, b = 0; - Graphics::colorToRGB >(rgb16, r, g, b); + colorToRGB >(rgb16, r, g, b); rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b); } } else { @@ -252,7 +252,7 @@ void QTRLEDecoder::decode16(Common::SeekableReadStream *stream, uint32 rowPtr, u // Convert from RGB555 to the format specified by the Overlay byte r = 0, g = 0, b = 0; - Graphics::colorToRGB >(rgb16, r, g, b); + colorToRGB >(rgb16, r, g, b); rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b); } } @@ -354,7 +354,7 @@ void QTRLEDecoder::decode32(Common::SeekableReadStream *stream, uint32 rowPtr, u } } -Graphics::Surface *QTRLEDecoder::decodeImage(Common::SeekableReadStream *stream) { +Surface *QTRLEDecoder::decodeImage(Common::SeekableReadStream *stream) { uint16 start_line = 0; uint16 height = _surface->h; @@ -417,4 +417,4 @@ QTRLEDecoder::~QTRLEDecoder() { _surface->free(); } -} // End of namespace Mohawk +} // End of namespace Graphics diff --git a/engines/mohawk/video/qtrle.h b/graphics/video/codecs/qtrle.h similarity index 83% rename from engines/mohawk/video/qtrle.h rename to graphics/video/codecs/qtrle.h index 2832bd6b24a..efbef144117 100644 --- a/engines/mohawk/video/qtrle.h +++ b/graphics/video/codecs/qtrle.h @@ -23,27 +23,27 @@ * */ -#ifndef MOHAWK_QTRLE_H -#define MOHAWK_QTRLE_H +#ifndef GRAPHICS_VIDEO_QTRLE_H +#define GRAPHICS_VIDEO_QTRLE_H #include "graphics/pixelformat.h" #include "graphics/video/codecs/codec.h" -namespace Mohawk { +namespace Graphics { -class QTRLEDecoder : public Graphics::Codec { +class QTRLEDecoder : public Codec { public: QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel); ~QTRLEDecoder(); - Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); - Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; } + Surface *decodeImage(Common::SeekableReadStream *stream); + PixelFormat getPixelFormat() const { return _pixelFormat; } private: byte _bitsPerPixel; - Graphics::Surface *_surface; - Graphics::PixelFormat _pixelFormat; + Surface *_surface; + PixelFormat _pixelFormat; void decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange); void decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp); @@ -53,6 +53,6 @@ private: void decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange); }; -} // End of namespace Mohawk +} // End of namespace Graphics #endif diff --git a/engines/mohawk/video/rpza.cpp b/graphics/video/codecs/rpza.cpp similarity index 94% rename from engines/mohawk/video/rpza.cpp rename to graphics/video/codecs/rpza.cpp index f48c055ae26..f0ed72e7306 100644 --- a/engines/mohawk/video/rpza.cpp +++ b/graphics/video/codecs/rpza.cpp @@ -25,14 +25,14 @@ // Based off ffmpeg's RPZA decoder -#include "mohawk/video/rpza.h" +#include "graphics/video/codecs/rpza.h" #include "common/system.h" #include "graphics/colormasks.h" -namespace Mohawk { +namespace Graphics { -RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Graphics::Codec() { +RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Codec() { _pixelFormat = g_system->getScreenFormat(); // We need to increase the surface size to a multiple of 4 @@ -42,7 +42,7 @@ RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Graphics::Codec() { debug(2, "RPZA corrected width: %d", width); - _surface = new Graphics::Surface(); + _surface = new Surface(); _surface->create(width, height, _pixelFormat.bytesPerPixel); } @@ -60,7 +60,7 @@ RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Graphics::Codec() { #define PUT_PIXEL(color) \ if ((int32)blockPtr < _surface->w * _surface->h) { \ byte r = 0, g = 0, b = 0; \ - Graphics::colorToRGB >(color, r, g, b); \ + colorToRGB >(color, r, g, b); \ if (_pixelFormat.bytesPerPixel == 2) \ *((uint16 *)_surface->pixels + blockPtr) = _pixelFormat.RGBToColor(r, g, b); \ else \ @@ -68,7 +68,7 @@ RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Graphics::Codec() { } \ blockPtr++ -Graphics::Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) { +Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) { uint16 colorA = 0, colorB = 0; uint16 color4[4]; @@ -205,4 +205,4 @@ Graphics::Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) return _surface; } -} // End of namespace Mohawk +} // End of namespace Graphics diff --git a/engines/mohawk/video/rpza.h b/graphics/video/codecs/rpza.h similarity index 77% rename from engines/mohawk/video/rpza.h rename to graphics/video/codecs/rpza.h index c6d0ada6f5d..e6d32feb722 100644 --- a/engines/mohawk/video/rpza.h +++ b/graphics/video/codecs/rpza.h @@ -23,27 +23,27 @@ * */ -#ifndef MOHAWK_RPZA_H -#define MOHAWK_RPZA_H +#ifndef GRAPHICS_VIDEO_RPZA_H +#define GRAPHICS_VIDEO_RPZA_H #include "graphics/pixelformat.h" #include "graphics/video/codecs/codec.h" -namespace Mohawk { +namespace Graphics { -class RPZADecoder : public Graphics::Codec { +class RPZADecoder : public Codec { public: RPZADecoder(uint16 width, uint16 height); ~RPZADecoder() { delete _surface; } - Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); - Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; } + Surface *decodeImage(Common::SeekableReadStream *stream); + PixelFormat getPixelFormat() const { return _pixelFormat; } private: - Graphics::Surface *_surface; - Graphics::PixelFormat _pixelFormat; + Surface *_surface; + PixelFormat _pixelFormat; }; -} // End of namespace Mohawk +} // End of namespace Graphics #endif diff --git a/engines/mohawk/video/smc.cpp b/graphics/video/codecs/smc.cpp similarity index 99% rename from engines/mohawk/video/smc.cpp rename to graphics/video/codecs/smc.cpp index 4a0d16dfccd..4661e3dc847 100644 --- a/engines/mohawk/video/smc.cpp +++ b/graphics/video/codecs/smc.cpp @@ -25,9 +25,9 @@ // Based off ffmpeg's SMC decoder -#include "mohawk/video/smc.h" +#include "graphics/video/codecs/smc.h" -namespace Mohawk { +namespace Graphics { #define GET_BLOCK_COUNT() \ (opcode & 0x10) ? (1 + stream->readByte()) : 1 + (opcode & 0x0F); @@ -382,4 +382,4 @@ Graphics::Surface *SMCDecoder::decodeImage(Common::SeekableReadStream *stream) { return _surface; } -} // End of namespace Mohawk +} // End of namespace Graphics diff --git a/engines/mohawk/video/smc.h b/graphics/video/codecs/smc.h similarity index 79% rename from engines/mohawk/video/smc.h rename to graphics/video/codecs/smc.h index c52226100e2..2d4355a83ee 100644 --- a/engines/mohawk/video/smc.h +++ b/graphics/video/codecs/smc.h @@ -23,12 +23,12 @@ * */ -#ifndef MOHAWK_VIDEO_SMC_H -#define MOHAWK_VIDEO_SMC_H +#ifndef GRAPHICS_VIDEO_SMC_H +#define GRAPHICS_VIDEO_SMC_H #include "graphics/video/codecs/codec.h" -namespace Mohawk { +namespace Graphics { enum { CPAIR = 2, @@ -37,16 +37,16 @@ enum { COLORS_PER_TABLE = 256 }; -class SMCDecoder : public Graphics::Codec { +class SMCDecoder : public Codec { public: SMCDecoder(uint16 width, uint16 height); ~SMCDecoder() { delete _surface; } - Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } + Surface *decodeImage(Common::SeekableReadStream *stream); + PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); } private: - Graphics::Surface *_surface; + Surface *_surface; // SMC color tables byte _colorPairs[COLORS_PER_TABLE * CPAIR]; @@ -54,6 +54,6 @@ private: byte _colorOctets[COLORS_PER_TABLE * COCTET]; }; -} // End of namespace Mohawk +} // End of namespace Graphics #endif diff --git a/engines/mohawk/video/qt_player.cpp b/graphics/video/qt_decoder.cpp similarity index 88% rename from engines/mohawk/video/qt_player.cpp rename to graphics/video/qt_decoder.cpp index 0ed05bb84dc..5351b9b6766 100644 --- a/engines/mohawk/video/qt_player.cpp +++ b/graphics/video/qt_decoder.cpp @@ -31,7 +31,7 @@ // Seek function by Gael Chardon gael.dev@4now.net // -#include "mohawk/video/qt_player.h" +#include "graphics/video/qt_decoder.h" #include "common/debug.h" #include "common/endian.h" @@ -41,22 +41,22 @@ // Audio codecs #include "sound/decoders/adpcm.h" #include "sound/decoders/raw.h" -#include "mohawk/video/qdm2.h" +#include "sound/decoders/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" +#include "graphics/video/codecs/cinepak.h" +#include "graphics/video/codecs/mjpeg.h" +#include "graphics/video/codecs/qtrle.h" +#include "graphics/video/codecs/rpza.h" +#include "graphics/video/codecs/smc.h" -namespace Mohawk { +namespace Graphics { //////////////////////////////////////////// -// QTPlayer +// QuickTimeDecoder //////////////////////////////////////////// -QTPlayer::QTPlayer() : Graphics::VideoDecoder() { +QuickTimeDecoder::QuickTimeDecoder() : VideoDecoder() { _audStream = NULL; _beginOffset = 0; _videoCodec = NULL; @@ -69,53 +69,53 @@ QTPlayer::QTPlayer() : Graphics::VideoDecoder() { _dirtyPalette = false; } -QTPlayer::~QTPlayer() { +QuickTimeDecoder::~QuickTimeDecoder() { close(); } -uint16 QTPlayer::getWidth() const { +uint16 QuickTimeDecoder::getWidth() const { if (_videoStreamIndex < 0) return 0; return _streams[_videoStreamIndex]->width / getScaleMode(); } -uint16 QTPlayer::getHeight() const { +uint16 QuickTimeDecoder::getHeight() const { if (_videoStreamIndex < 0) return 0; return _streams[_videoStreamIndex]->height / getScaleMode(); } -uint32 QTPlayer::getFrameCount() const { +uint32 QuickTimeDecoder::getFrameCount() const { if (_videoStreamIndex < 0) return 0; return _streams[_videoStreamIndex]->nb_frames; } -byte QTPlayer::getBitsPerPixel() { +byte QuickTimeDecoder::getBitsPerPixel() { if (_videoStreamIndex < 0) return 0; return _streams[_videoStreamIndex]->bits_per_sample & 0x1F; } -uint32 QTPlayer::getCodecTag() { +uint32 QuickTimeDecoder::getCodecTag() { if (_videoStreamIndex < 0) return 0; return _streams[_videoStreamIndex]->codec_tag; } -ScaleMode QTPlayer::getScaleMode() const { +ScaleMode QuickTimeDecoder::getScaleMode() const { if (_videoStreamIndex < 0) return kScaleNormal; return (ScaleMode)(_scaleMode * _streams[_videoStreamIndex]->scaleMode); } -uint32 QTPlayer::getFrameDuration() { +uint32 QuickTimeDecoder::getFrameDuration() { if (_videoStreamIndex < 0) return 0; @@ -133,14 +133,14 @@ uint32 QTPlayer::getFrameDuration() { return 0; } -Graphics::PixelFormat QTPlayer::getPixelFormat() const { +PixelFormat QuickTimeDecoder::getPixelFormat() const { if (!_videoCodec) - return Graphics::PixelFormat::createFormatCLUT8(); + return PixelFormat::createFormatCLUT8(); return _videoCodec->getPixelFormat(); } -void QTPlayer::rewind() { +void QuickTimeDecoder::rewind() { delete _videoCodec; _videoCodec = NULL; _curFrame = -1; _startTime = _nextFrameStartTime = 0; @@ -154,7 +154,7 @@ void QTPlayer::rewind() { startAudio(); } -Graphics::Codec *QTPlayer::createCodec(uint32 codecTag, byte bitsPerPixel) { +Codec *QuickTimeDecoder::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(); @@ -175,7 +175,7 @@ Graphics::Codec *QTPlayer::createCodec(uint32 codecTag, byte bitsPerPixel) { 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); + return new JPEGDecoder(); } 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"); @@ -186,24 +186,24 @@ Graphics::Codec *QTPlayer::createCodec(uint32 codecTag, byte bitsPerPixel) { return NULL; } -void QTPlayer::startAudio() { +void QuickTimeDecoder::startAudio() { if (_audStream) // No audio/audio not supported g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream); } -void QTPlayer::stopAudio() { +void QuickTimeDecoder::stopAudio() { if (_audStream) { g_system->getMixer()->stopHandle(_audHandle); _audStream = NULL; // the mixer automatically frees the stream } } -void QTPlayer::pauseVideoIntern(bool pause) { +void QuickTimeDecoder::pauseVideoIntern(bool pause) { if (_audStream) g_system->getMixer()->pauseHandle(_audHandle, pause); } -Graphics::Surface *QTPlayer::decodeNextFrame() { +Surface *QuickTimeDecoder::decodeNextFrame() { if (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1) return NULL; @@ -216,7 +216,7 @@ Graphics::Surface *QTPlayer::decodeNextFrame() { Common::SeekableReadStream *frameData = getNextFramePacket(); if (frameData) { - Graphics::Surface *frame = _videoCodec->decodeImage(frameData); + Surface *frame = _videoCodec->decodeImage(frameData); delete frameData; return scaleSurface(frame); } @@ -224,7 +224,7 @@ Graphics::Surface *QTPlayer::decodeNextFrame() { return NULL; } -Graphics::Surface *QTPlayer::scaleSurface(Graphics::Surface *frame) { +Surface *QuickTimeDecoder::scaleSurface(Surface *frame) { if (getScaleMode() == kScaleNormal) return frame; @@ -237,22 +237,22 @@ Graphics::Surface *QTPlayer::scaleSurface(Graphics::Surface *frame) { return _scaledSurface; } -bool QTPlayer::endOfVideo() const { +bool QuickTimeDecoder::endOfVideo() const { return (!_audStream || _audStream->endOfData()) && (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1); } -bool QTPlayer::needsUpdate() const { +bool QuickTimeDecoder::needsUpdate() const { return !endOfVideo() && getTimeToNextFrame() == 0; } -uint32 QTPlayer::getElapsedTime() const { +uint32 QuickTimeDecoder::getElapsedTime() const { if (_audStream) return g_system->getMixer()->getSoundElapsedTime(_audHandle); return g_system->getMillis() - _startTime; } -uint32 QTPlayer::getTimeToNextFrame() const { +uint32 QuickTimeDecoder::getTimeToNextFrame() const { if (endOfVideo() || _curFrame < 0) return 0; @@ -266,7 +266,7 @@ uint32 QTPlayer::getTimeToNextFrame() const { return nextFrameStartTime - elapsedTime; } -bool QTPlayer::load(Common::SeekableReadStream &stream) { +bool QuickTimeDecoder::load(Common::SeekableReadStream &stream) { _fd = &stream; _foundMOOV = _foundMDAT = false; _numStreams = 0; @@ -337,7 +337,7 @@ bool QTPlayer::load(Common::SeekableReadStream &stream) { if (getScaleMode() != kScaleNormal) { // We have to initialize the scaled surface - _scaledSurface = new Graphics::Surface(); + _scaledSurface = new Surface(); _scaledSurface->create(getWidth(), getHeight(), getPixelFormat().bytesPerPixel); } } @@ -345,40 +345,40 @@ bool QTPlayer::load(Common::SeekableReadStream &stream) { return true; } -void QTPlayer::initParseTable() { +void QuickTimeDecoder::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 }, + { MKID_BE('dinf'), &QuickTimeDecoder::readDefault }, + { MKID_BE('dref'), &QuickTimeDecoder::readLeaf }, + { MKID_BE('edts'), &QuickTimeDecoder::readDefault }, + { MKID_BE('elst'), &QuickTimeDecoder::readELST }, + { MKID_BE('hdlr'), &QuickTimeDecoder::readHDLR }, + { MKID_BE('mdat'), &QuickTimeDecoder::readMDAT }, + { MKID_BE('mdhd'), &QuickTimeDecoder::readMDHD }, + { MKID_BE('mdia'), &QuickTimeDecoder::readDefault }, + { MKID_BE('minf'), &QuickTimeDecoder::readDefault }, + { MKID_BE('moov'), &QuickTimeDecoder::readMOOV }, + { MKID_BE('mvhd'), &QuickTimeDecoder::readMVHD }, + { MKID_BE('smhd'), &QuickTimeDecoder::readLeaf }, + { MKID_BE('stbl'), &QuickTimeDecoder::readDefault }, + { MKID_BE('stco'), &QuickTimeDecoder::readSTCO }, + { MKID_BE('stsc'), &QuickTimeDecoder::readSTSC }, + { MKID_BE('stsd'), &QuickTimeDecoder::readSTSD }, + { MKID_BE('stss'), &QuickTimeDecoder::readSTSS }, + { MKID_BE('stsz'), &QuickTimeDecoder::readSTSZ }, + { MKID_BE('stts'), &QuickTimeDecoder::readSTTS }, + { MKID_BE('tkhd'), &QuickTimeDecoder::readTKHD }, + { MKID_BE('trak'), &QuickTimeDecoder::readTRAK }, + { MKID_BE('udta'), &QuickTimeDecoder::readLeaf }, + { MKID_BE('vmhd'), &QuickTimeDecoder::readLeaf }, + { MKID_BE('cmov'), &QuickTimeDecoder::readCMOV }, + { MKID_BE('wave'), &QuickTimeDecoder::readWAVE }, { 0, 0 } }; _parseTable = p; } -int QTPlayer::readDefault(MOVatom atom) { +int QuickTimeDecoder::readDefault(MOVatom atom) { uint32 total_size = 0; MOVatom a; int err = 0; @@ -443,14 +443,14 @@ int QTPlayer::readDefault(MOVatom atom) { return err; } -int QTPlayer::readLeaf(MOVatom atom) { +int QuickTimeDecoder::readLeaf(MOVatom atom) { if (atom.size > 1) _fd->seek(atom.size, SEEK_SET); return 0; } -int QTPlayer::readMOOV(MOVatom atom) { +int QuickTimeDecoder::readMOOV(MOVatom atom) { if (readDefault(atom) < 0) return -1; @@ -464,7 +464,7 @@ int QTPlayer::readMOOV(MOVatom atom) { return 0; // now go for mdat } -int QTPlayer::readCMOV(MOVatom atom) { +int QuickTimeDecoder::readCMOV(MOVatom atom) { #ifdef USE_ZLIB // Read in the dcom atom _fd->readUint32BE(); @@ -515,7 +515,7 @@ int QTPlayer::readCMOV(MOVatom atom) { #endif } -int QTPlayer::readMVHD(MOVatom atom) { +int QuickTimeDecoder::readMVHD(MOVatom atom) { byte version = _fd->readByte(); // version _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags @@ -570,7 +570,7 @@ int QTPlayer::readMVHD(MOVatom atom) { return 0; } -int QTPlayer::readTRAK(MOVatom atom) { +int QuickTimeDecoder::readTRAK(MOVatom atom) { MOVStreamContext *sc = new MOVStreamContext(); if (!sc) @@ -585,7 +585,7 @@ int QTPlayer::readTRAK(MOVatom atom) { } // this atom contains actual media data -int QTPlayer::readMDAT(MOVatom atom) { +int QuickTimeDecoder::readMDAT(MOVatom atom) { if (atom.size == 0) // wrong one (MP4) return 0; @@ -602,7 +602,7 @@ int QTPlayer::readMDAT(MOVatom atom) { return 0; // now go for moov } -int QTPlayer::readTKHD(MOVatom atom) { +int QuickTimeDecoder::readTKHD(MOVatom atom) { MOVStreamContext *st = _streams[_numStreams - 1]; byte version = _fd->readByte(); @@ -662,7 +662,7 @@ int QTPlayer::readTKHD(MOVatom atom) { } // edit list atom -int QTPlayer::readELST(MOVatom atom) { +int QuickTimeDecoder::readELST(MOVatom atom) { _fd->readByte(); // version _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags uint32 editCount = _streams[_numStreams - 1]->edit_count = _fd->readUint32BE(); // entries @@ -681,7 +681,7 @@ int QTPlayer::readELST(MOVatom atom) { return 0; } -int QTPlayer::readHDLR(MOVatom atom) { +int QuickTimeDecoder::readHDLR(MOVatom atom) { MOVStreamContext *st = _streams[_numStreams - 1]; _fd->readByte(); // version @@ -722,7 +722,7 @@ int QTPlayer::readHDLR(MOVatom atom) { return 0; } -int QTPlayer::readMDHD(MOVatom atom) { +int QuickTimeDecoder::readMDHD(MOVatom atom) { MOVStreamContext *st = _streams[_numStreams - 1]; byte version = _fd->readByte(); @@ -749,7 +749,7 @@ int QTPlayer::readMDHD(MOVatom atom) { return 0; } -int QTPlayer::readSTSD(MOVatom atom) { +int QuickTimeDecoder::readSTSD(MOVatom atom) { MOVStreamContext *st = _streams[_numStreams - 1]; _fd->readByte(); // version @@ -934,7 +934,7 @@ int QTPlayer::readSTSD(MOVatom atom) { return 0; } -int QTPlayer::readSTSC(MOVatom atom) { +int QuickTimeDecoder::readSTSC(MOVatom atom) { MOVStreamContext *st = _streams[_numStreams - 1]; _fd->readByte(); // version @@ -959,7 +959,7 @@ int QTPlayer::readSTSC(MOVatom atom) { return 0; } -int QTPlayer::readSTSS(MOVatom atom) { +int QuickTimeDecoder::readSTSS(MOVatom atom) { MOVStreamContext *st = _streams[_numStreams - 1]; _fd->readByte(); // version @@ -982,7 +982,7 @@ int QTPlayer::readSTSS(MOVatom atom) { return 0; } -int QTPlayer::readSTSZ(MOVatom atom) { +int QuickTimeDecoder::readSTSZ(MOVatom atom) { MOVStreamContext *st = _streams[_numStreams - 1]; _fd->readByte(); // version @@ -1014,7 +1014,7 @@ static uint32 ff_gcd(uint32 a, uint32 b) { else return a; } -int QTPlayer::readSTTS(MOVatom atom) { +int QuickTimeDecoder::readSTTS(MOVatom atom) { MOVStreamContext *st = _streams[_numStreams - 1]; uint32 duration = 0; uint32 total_sample_count = 0; @@ -1054,7 +1054,7 @@ int QTPlayer::readSTTS(MOVatom atom) { return 0; } -int QTPlayer::readSTCO(MOVatom atom) { +int QuickTimeDecoder::readSTCO(MOVatom atom) { MOVStreamContext *st = _streams[_numStreams - 1]; _fd->readByte(); // version @@ -1088,7 +1088,7 @@ int QTPlayer::readSTCO(MOVatom atom) { return 0; } -int QTPlayer::readWAVE(MOVatom atom) { +int QuickTimeDecoder::readWAVE(MOVatom atom) { if (_numStreams < 1) return 0; @@ -1107,7 +1107,7 @@ int QTPlayer::readWAVE(MOVatom atom) { return 0; } -void QTPlayer::close() { +void QuickTimeDecoder::close() { stopAudio(); delete _videoCodec; _videoCodec = 0; @@ -1126,10 +1126,10 @@ void QTPlayer::close() { // The audio stream is deleted automatically _audStream = NULL; - Graphics::VideoDecoder::reset(); + VideoDecoder::reset(); } -Common::SeekableReadStream *QTPlayer::getNextFramePacket() { +Common::SeekableReadStream *QuickTimeDecoder::getNextFramePacket() { if (_videoStreamIndex < 0) return NULL; @@ -1182,17 +1182,22 @@ Common::SeekableReadStream *QTPlayer::getNextFramePacket() { return _fd->readStream(_streams[_videoStreamIndex]->sample_sizes[getCurFrame()]); } -bool QTPlayer::checkAudioCodecSupport(uint32 tag) { +bool QuickTimeDecoder::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')) + if (tag == MKID_BE('twos') || tag == MKID_BE('raw ') || tag == MKID_BE('ima4')) return true; +#ifdef SOUND_QDM2_H + if (tag == MKID_BE('QDM2')) + return true; +#endif + warning("Audio Codec Not Supported: \'%s\'", tag2str(tag)); return false; } -Audio::AudioStream *QTPlayer::createAudioStream(Common::SeekableReadStream *stream) { +Audio::AudioStream *QuickTimeDecoder::createAudioStream(Common::SeekableReadStream *stream) { if (!stream || _audioStreamIndex < 0) return NULL; @@ -1213,9 +1218,11 @@ Audio::AudioStream *QTPlayer::createAudioStream(Common::SeekableReadStream *stre } 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); +#ifdef SOUND_QDM2_H } else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('QDM2')) { // Several Myst ME videos use this codec - return new QDM2Stream(stream, _streams[_audioStreamIndex]->extradata); + return new Audio::QDM2Stream(stream, _streams[_audioStreamIndex]->extradata); +#endif } error("Unsupported audio codec"); @@ -1223,12 +1230,12 @@ Audio::AudioStream *QTPlayer::createAudioStream(Common::SeekableReadStream *stre return NULL; } -void QTPlayer::updateAudioBuffer() { +void QuickTimeDecoder::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++) { + // Keep three streams in buffer so that if/when the first two end, it goes right into the next + for (; _audStream->numQueuedStreams() < 3 && _curAudioChunk < _streams[_audioStreamIndex]->chunk_count; _curAudioChunk++) { Common::MemoryWriteStreamDynamic *wStream = new Common::MemoryWriteStreamDynamic(); _fd->seek(_streams[_audioStreamIndex]->chunk_offsets[_curAudioChunk]); @@ -1269,4 +1276,4 @@ void QTPlayer::updateAudioBuffer() { } } -} // End of namespace Mohawk +} // End of namespace Graphics diff --git a/engines/mohawk/video/qt_player.h b/graphics/video/qt_decoder.h similarity index 92% rename from engines/mohawk/video/qt_player.h rename to graphics/video/qt_decoder.h index 6657d3edba6..dc0557b3885 100644 --- a/engines/mohawk/video/qt_player.h +++ b/graphics/video/qt_decoder.h @@ -31,8 +31,8 @@ // Seek function by Gael Chardon gael.dev@4now.net // -#ifndef MOHAWK_QT_PLAYER_H -#define MOHAWK_QT_PLAYER_H +#ifndef GRAPHICS_QT_DECODER_H +#define GRAPHICS_QT_DECODER_H #include "common/scummsys.h" #include "common/queue.h" @@ -47,7 +47,7 @@ namespace Common { class File; } -namespace Mohawk { +namespace Graphics { enum ScaleMode { kScaleNormal = 1, @@ -55,10 +55,10 @@ enum ScaleMode { kScaleQuarter = 4 }; -class QTPlayer : public Graphics::RewindableVideoDecoder { +class QuickTimeDecoder : public RewindableVideoDecoder { public: - QTPlayer(); - virtual ~QTPlayer(); + QuickTimeDecoder(); + virtual ~QuickTimeDecoder(); /** * Returns the width of the video @@ -104,12 +104,12 @@ public: void setChunkBeginOffset(uint32 offset) { _beginOffset = offset; } bool isVideoLoaded() const { return _fd != 0; } - Graphics::Surface *decodeNextFrame(); + Surface *decodeNextFrame(); bool needsUpdate() const; bool endOfVideo() const; uint32 getElapsedTime() const; uint32 getTimeToNextFrame() const; - Graphics::PixelFormat getPixelFormat() const; + PixelFormat getPixelFormat() const; // RewindableVideoDecoder API void rewind(); @@ -132,7 +132,7 @@ protected: struct ParseTable { uint32 type; - int (QTPlayer::*func)(MOVatom atom); + int (QuickTimeDecoder::*func)(MOVatom atom); }; struct MOVstts { @@ -246,13 +246,13 @@ protected: uint _curAudioChunk; Audio::SoundHandle _audHandle; - Graphics::Codec *createCodec(uint32 codecTag, byte bitsPerPixel); - Graphics::Codec *_videoCodec; + Codec *createCodec(uint32 codecTag, byte bitsPerPixel); + Codec *_videoCodec; uint32 _nextFrameStartTime; int8 _videoStreamIndex; - Graphics::Surface *_scaledSurface; - Graphics::Surface *scaleSurface(Graphics::Surface *frame); + Surface *_scaledSurface; + Surface *scaleSurface(Surface *frame); ScaleMode getScaleMode() const; void pauseVideoIntern(bool pause); @@ -277,6 +277,6 @@ protected: int readWAVE(MOVatom atom); }; -} // End of namespace Mohawk +} // End of namespace Graphics #endif diff --git a/engines/mohawk/video/qdm2.cpp b/sound/decoders/qdm2.cpp similarity index 99% rename from engines/mohawk/video/qdm2.cpp rename to sound/decoders/qdm2.cpp index b91440f00d1..dbfa130be59 100644 --- a/engines/mohawk/video/qdm2.cpp +++ b/sound/decoders/qdm2.cpp @@ -25,12 +25,14 @@ // Based off ffmpeg's QDM2 decoder -#include "mohawk/video/qdm2.h" -#include "mohawk/video/qdm2data.h" +#include "sound/decoders/qdm2.h" +#ifdef SOUND_QDM2_H + +#include "sound/decoders/qdm2data.h" #include "common/system.h" -namespace Mohawk { +namespace Audio { // Fix compilation for non C99-compliant compilers, like MSVC #ifndef int64_t @@ -3060,4 +3062,6 @@ int QDM2Stream::readBuffer(int16 *buffer, const int numSamples) { return decodedSamples; } -} // End of namespace Mohawk +} // End of namespace Audio + +#endif diff --git a/engines/mohawk/video/qdm2.h b/sound/decoders/qdm2.h similarity index 96% rename from engines/mohawk/video/qdm2.h rename to sound/decoders/qdm2.h index ffa5f77030a..77208aec524 100644 --- a/engines/mohawk/video/qdm2.h +++ b/sound/decoders/qdm2.h @@ -23,14 +23,17 @@ * */ -#ifndef MOHAWK_VIDEO_QDM2_H -#define MOHAWK_VIDEO_QDM2_H +// Only compile if Mohawk is enabled or if we're building dynamic modules +#if defined(ENABLE_MOHAWK) || defined(DYNAMIC_MODULES) + +#ifndef SOUND_QDM2_H +#define SOUND_QDM2_H #include "sound/audiostream.h" #include "common/array.h" #include "common/stream.h" -namespace Mohawk { +namespace Audio { enum { SOFTCLIP_THRESHOLD = 27600, @@ -284,6 +287,8 @@ private: int qdm2_decodeFrame(Common::SeekableReadStream *in); }; -} // End of namespace Mohawk +} // End of namespace Audio -#endif +#endif // SOUND_QDM2_H + +#endif // Mohawk/Plugins guard diff --git a/engines/mohawk/video/qdm2data.h b/sound/decoders/qdm2data.h similarity index 99% rename from engines/mohawk/video/qdm2data.h rename to sound/decoders/qdm2data.h index f1c18db41c3..4c13328dd61 100644 --- a/engines/mohawk/video/qdm2data.h +++ b/sound/decoders/qdm2data.h @@ -23,12 +23,12 @@ * */ -#ifndef MOHAWK_VIDEO_QDM2DATA_H -#define MOHAWK_VIDEO_QDM2DATA_H +#ifndef SOUND_QDM2DATA_H +#define SOUND_QDM2DATA_H #include "common/scummsys.h" -namespace Mohawk { +namespace Audio { /// VLC TABLES @@ -526,6 +526,6 @@ static const float type34_delta[10] = { // FIXME: covers 8 entries.. 0.138071194291115f,0.333333343267441f,0.60947573184967f,1.0f,0.0f, }; -} // End of namespace Mohawk +} // End of namespace Audio #endif diff --git a/sound/module.mk b/sound/module.mk index df593d8e1f0..cd1ff0df8eb 100644 --- a/sound/module.mk +++ b/sound/module.mk @@ -18,6 +18,7 @@ MODULE_OBJS := \ decoders/flac.o \ decoders/iff_sound.o \ decoders/mp3.o \ + decoders/qdm2.o \ decoders/raw.o \ decoders/vag.o \ decoders/voc.o \ From ed0e8182cee620e6abae2e9c1bc571b31833f474 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 23 May 2010 19:08:31 +0000 Subject: [PATCH 015/249] FFMpeg switched to Git, so update link to original smacker decoder. svn-id: r49166 --- graphics/video/smk_decoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/video/smk_decoder.cpp b/graphics/video/smk_decoder.cpp index 68fac32aae7..f27a70f78c8 100644 --- a/graphics/video/smk_decoder.cpp +++ b/graphics/video/smk_decoder.cpp @@ -25,7 +25,7 @@ // Based on http://wiki.multimedia.cx/index.php?title=Smacker // and the FFmpeg Smacker decoder (libavcodec/smacker.c), revision 16143 -// http://svn.ffmpeg.org/ffmpeg/trunk/libavcodec/smacker.c?revision=16143&view=markup +// http://git.ffmpeg.org/?p=ffmpeg;a=blob;f=libavcodec/smacker.c;hb=b8437a00a2f14d4a437346455d624241d726128e #include "graphics/video/smk_decoder.h" From 088ad439669c3b535bb66e8773aaf706ba70e5fa Mon Sep 17 00:00:00 2001 From: Joost Peters Date: Sun, 23 May 2010 19:24:19 +0000 Subject: [PATCH 016/249] add mips-sgi(-irix6.5) cross-compiling target svn-id: r49167 --- configure | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure b/configure index 2edcd1798b3..17da22fb8f6 100755 --- a/configure +++ b/configure @@ -1506,6 +1506,10 @@ if test -n "$_host"; then _ar="$_host-ar cru" _ranlib=$_host-ranlib ;; + mips-sgi*) + _endian=big + _need_memalign=yes + ;; motoezx) DEFINES="$DEFINES -DUNIX -DMOTOEZX" ASFLAGS="$ASFLAGS -mfpu=vfp" From e5d239b779ba24e75f1f911b023c6c94b63ffefd Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Sun, 23 May 2010 19:31:38 +0000 Subject: [PATCH 017/249] PSP: changed thread stack sizes to prevent crashes in COMI svn-id: r49168 --- backends/platform/psp/thread.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h index 5879d044ed7..d395d6713e1 100644 --- a/backends/platform/psp/thread.h +++ b/backends/platform/psp/thread.h @@ -36,8 +36,8 @@ enum ThreadPriority { enum StackSizes { STACK_AUDIO_THREAD = 16 * 1024, - STACK_TIMER_THREAD = 4 * 1024, - STACK_DISPLAY_THREAD = 4 * 1024, + STACK_TIMER_THREAD = 16 * 1024, + STACK_DISPLAY_THREAD = 2 * 1024, STACK_POWER_THREAD = 4 * 1024 }; From 734042a32ce37822551094feac81887743998b6c Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Sun, 23 May 2010 19:32:56 +0000 Subject: [PATCH 018/249] PSP: commented out new PSP audio. Still has some clicking issues svn-id: r49169 --- backends/platform/psp/osys_psp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index f33081abbc1..d29196619b8 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -48,7 +48,7 @@ #include "backends/platform/psp/trace.h" -#define USE_PSP_AUDIO +//#define USE_PSP_AUDIO #define SAMPLES_PER_SEC 44100 From 5e90f66edc816931996a72b8fca8b01a96aff31a Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 23 May 2010 19:54:17 +0000 Subject: [PATCH 019/249] Hide the QDM2 implementation and only expose it via a factory method, hopefully fixing compilation on most systems at the same time. svn-id: r49170 --- graphics/video/qt_decoder.cpp | 2 +- sound/decoders/qdm2.cpp | 260 +++++++++++++++++++++++++++++++++ sound/decoders/qdm2.h | 267 ++-------------------------------- 3 files changed, 273 insertions(+), 256 deletions(-) diff --git a/graphics/video/qt_decoder.cpp b/graphics/video/qt_decoder.cpp index 5351b9b6766..05f73526eb6 100644 --- a/graphics/video/qt_decoder.cpp +++ b/graphics/video/qt_decoder.cpp @@ -1221,7 +1221,7 @@ Audio::AudioStream *QuickTimeDecoder::createAudioStream(Common::SeekableReadStre #ifdef SOUND_QDM2_H } else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('QDM2')) { // Several Myst ME videos use this codec - return new Audio::QDM2Stream(stream, _streams[_audioStreamIndex]->extradata); + return Audio::makeQDM2Stream(stream, _streams[_audioStreamIndex]->extradata); #endif } diff --git a/sound/decoders/qdm2.cpp b/sound/decoders/qdm2.cpp index dbfa130be59..aa4eb4b40a6 100644 --- a/sound/decoders/qdm2.cpp +++ b/sound/decoders/qdm2.cpp @@ -29,11 +29,267 @@ #ifdef SOUND_QDM2_H +#include "sound/audiostream.h" #include "sound/decoders/qdm2data.h" + +#include "common/array.h" +#include "common/stream.h" #include "common/system.h" namespace Audio { +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 _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); +}; + // Fix compilation for non C99-compliant compilers, like MSVC #ifndef int64_t typedef signed long long int int64_t; @@ -3062,6 +3318,10 @@ int QDM2Stream::readBuffer(int16 *buffer, const int numSamples) { return decodedSamples; } +AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) { + return new QDM2Stream(stream, extraData); +} + } // End of namespace Audio #endif diff --git a/sound/decoders/qdm2.h b/sound/decoders/qdm2.h index 77208aec524..842ede3de08 100644 --- a/sound/decoders/qdm2.h +++ b/sound/decoders/qdm2.h @@ -29,266 +29,23 @@ #ifndef SOUND_QDM2_H #define SOUND_QDM2_H -#include "sound/audiostream.h" -#include "common/array.h" -#include "common/stream.h" +namespace Common { + class SeekableReadStream; +} namespace Audio { + class AudioStream; -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 _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); -}; +/** + * Create a new AudioStream from the QDM2 data in the given stream. + * + * @param stream the SeekableReadStream from which to read the FLAC data + * @param extraData the QuickTime extra data stream + * @return a new AudioStream, or NULL, if an error occured + */ +AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData); } // End of namespace Audio #endif // SOUND_QDM2_H - #endif // Mohawk/Plugins guard From b3bd797e019c20de1d4bfdac131e6e3e2c45860a Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 23 May 2010 21:41:13 +0000 Subject: [PATCH 020/249] Move the QDM2 code to the graphics module, removing the cyclic dependency. svn-id: r49171 --- graphics/module.mk | 1 + {sound/decoders => graphics/video/codecs}/qdm2.cpp | 12 ++++++------ {sound/decoders => graphics/video/codecs}/qdm2.h | 13 ++++++++----- .../decoders => graphics/video/codecs}/qdm2data.h | 8 ++++---- graphics/video/qt_decoder.cpp | 8 ++++---- sound/module.mk | 1 - 6 files changed, 23 insertions(+), 20 deletions(-) rename {sound/decoders => graphics/video/codecs}/qdm2.cpp (99%) rename {sound/decoders => graphics/video/codecs}/qdm2.h (86%) rename {sound/decoders => graphics/video/codecs}/qdm2data.h (99%) diff --git a/graphics/module.mk b/graphics/module.mk index 8f916a5bccd..c7f57714206 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -32,6 +32,7 @@ MODULE_OBJS := \ video/codecs/mjpeg.o \ video/codecs/msrle.o \ video/codecs/msvideo1.o \ + video/codecs/qdm2.o \ video/codecs/qtrle.o \ video/codecs/rpza.o \ video/codecs/smc.o \ diff --git a/sound/decoders/qdm2.cpp b/graphics/video/codecs/qdm2.cpp similarity index 99% rename from sound/decoders/qdm2.cpp rename to graphics/video/codecs/qdm2.cpp index aa4eb4b40a6..e12be213033 100644 --- a/sound/decoders/qdm2.cpp +++ b/graphics/video/codecs/qdm2.cpp @@ -25,18 +25,18 @@ // Based off ffmpeg's QDM2 decoder -#include "sound/decoders/qdm2.h" +#include "graphics/video/codecs/qdm2.h" -#ifdef SOUND_QDM2_H +#ifdef GRAPHICS_QDM2_H #include "sound/audiostream.h" -#include "sound/decoders/qdm2data.h" +#include "graphics/video/codecs/qdm2data.h" #include "common/array.h" #include "common/stream.h" #include "common/system.h" -namespace Audio { +namespace Graphics { enum { SOFTCLIP_THRESHOLD = 27600, @@ -3318,10 +3318,10 @@ int QDM2Stream::readBuffer(int16 *buffer, const int numSamples) { return decodedSamples; } -AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) { +Audio::AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) { return new QDM2Stream(stream, extraData); } -} // End of namespace Audio +} // End of namespace Graphics #endif diff --git a/sound/decoders/qdm2.h b/graphics/video/codecs/qdm2.h similarity index 86% rename from sound/decoders/qdm2.h rename to graphics/video/codecs/qdm2.h index 842ede3de08..c9a01a70ee5 100644 --- a/sound/decoders/qdm2.h +++ b/graphics/video/codecs/qdm2.h @@ -26,8 +26,8 @@ // Only compile if Mohawk is enabled or if we're building dynamic modules #if defined(ENABLE_MOHAWK) || defined(DYNAMIC_MODULES) -#ifndef SOUND_QDM2_H -#define SOUND_QDM2_H +#ifndef GRAPHICS_QDM2_H +#define GRAPHICS_QDM2_H namespace Common { class SeekableReadStream; @@ -35,6 +35,9 @@ namespace Common { namespace Audio { class AudioStream; +} + +namespace Graphics { /** * Create a new AudioStream from the QDM2 data in the given stream. @@ -43,9 +46,9 @@ namespace Audio { * @param extraData the QuickTime extra data stream * @return a new AudioStream, or NULL, if an error occured */ -AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData); +Audio::AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData); -} // End of namespace Audio +} // End of namespace Graphics -#endif // SOUND_QDM2_H +#endif // GRAPHICS_QDM2_H #endif // Mohawk/Plugins guard diff --git a/sound/decoders/qdm2data.h b/graphics/video/codecs/qdm2data.h similarity index 99% rename from sound/decoders/qdm2data.h rename to graphics/video/codecs/qdm2data.h index 4c13328dd61..25ed102c4e6 100644 --- a/sound/decoders/qdm2data.h +++ b/graphics/video/codecs/qdm2data.h @@ -23,12 +23,12 @@ * */ -#ifndef SOUND_QDM2DATA_H -#define SOUND_QDM2DATA_H +#ifndef GRAPHICS_QDM2DATA_H +#define GRAPHICS_QDM2DATA_H #include "common/scummsys.h" -namespace Audio { +namespace Graphics { /// VLC TABLES @@ -526,6 +526,6 @@ static const float type34_delta[10] = { // FIXME: covers 8 entries.. 0.138071194291115f,0.333333343267441f,0.60947573184967f,1.0f,0.0f, }; -} // End of namespace Audio +} // End of namespace Graphics #endif diff --git a/graphics/video/qt_decoder.cpp b/graphics/video/qt_decoder.cpp index 05f73526eb6..4a9be0b0fde 100644 --- a/graphics/video/qt_decoder.cpp +++ b/graphics/video/qt_decoder.cpp @@ -41,7 +41,7 @@ // Audio codecs #include "sound/decoders/adpcm.h" #include "sound/decoders/raw.h" -#include "sound/decoders/qdm2.h" +#include "graphics/video/codecs/qdm2.h" // Video codecs #include "graphics/video/codecs/cinepak.h" @@ -1187,7 +1187,7 @@ bool QuickTimeDecoder::checkAudioCodecSupport(uint32 tag) { if (tag == MKID_BE('twos') || tag == MKID_BE('raw ') || tag == MKID_BE('ima4')) return true; -#ifdef SOUND_QDM2_H +#ifdef GRAPHICS_QDM2_H if (tag == MKID_BE('QDM2')) return true; #endif @@ -1218,10 +1218,10 @@ Audio::AudioStream *QuickTimeDecoder::createAudioStream(Common::SeekableReadStre } 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); -#ifdef SOUND_QDM2_H +#ifdef GRAPHICS_QDM2_H } else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('QDM2')) { // Several Myst ME videos use this codec - return Audio::makeQDM2Stream(stream, _streams[_audioStreamIndex]->extradata); + return makeQDM2Stream(stream, _streams[_audioStreamIndex]->extradata); #endif } diff --git a/sound/module.mk b/sound/module.mk index cd1ff0df8eb..df593d8e1f0 100644 --- a/sound/module.mk +++ b/sound/module.mk @@ -18,7 +18,6 @@ MODULE_OBJS := \ decoders/flac.o \ decoders/iff_sound.o \ decoders/mp3.o \ - decoders/qdm2.o \ decoders/raw.o \ decoders/vag.o \ decoders/voc.o \ From 8f14c15b1afc51a860d7fae28a59cbcd4d7d4d04 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 23 May 2010 23:26:28 +0000 Subject: [PATCH 021/249] Add support for loading the QuickTime 'moov' atom from the file's resource fork, needed for SCI Mac. svn-id: r49172 --- graphics/video/qt_decoder.cpp | 68 ++++++++++++++++++++++++++++------- graphics/video/qt_decoder.h | 10 +++++- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/graphics/video/qt_decoder.cpp b/graphics/video/qt_decoder.cpp index 4a9be0b0fde..5e507720242 100644 --- a/graphics/video/qt_decoder.cpp +++ b/graphics/video/qt_decoder.cpp @@ -35,6 +35,7 @@ #include "common/debug.h" #include "common/endian.h" +#include "common/macresman.h" #include "common/util.h" #include "common/zlib.h" @@ -67,10 +68,14 @@ QuickTimeDecoder::QuickTimeDecoder() : VideoDecoder() { _fd = 0; _scaledSurface = 0; _dirtyPalette = false; + _resFork = new Common::MacResManager(); + + initParseTable(); } QuickTimeDecoder::~QuickTimeDecoder() { close(); + delete _resFork; } uint16 QuickTimeDecoder::getWidth() const { @@ -256,7 +261,7 @@ uint32 QuickTimeDecoder::getTimeToNextFrame() const { if (endOfVideo() || _curFrame < 0) return 0; - // Convert from the Sega FILM base to 1000 + // Convert from the QuickTime rate base to 1000 uint32 nextFrameStartTime = _nextFrameStartTime * 1000 / _streams[_videoStreamIndex]->time_scale; uint32 elapsedTime = getElapsedTime(); @@ -266,6 +271,41 @@ uint32 QuickTimeDecoder::getTimeToNextFrame() const { return nextFrameStartTime - elapsedTime; } +bool QuickTimeDecoder::loadFile(const Common::String &filename) { + if (!_resFork->open(filename) || !_resFork->hasDataFork()) + return false; + + _foundMOOV = _foundMDAT = false; + _numStreams = 0; + _partial = 0; + _videoStreamIndex = _audioStreamIndex = -1; + _startTime = 0; + + MOVatom atom = { 0, 0, 0xffffffff }; + + if (_resFork->hasResFork()) { + _fd = _resFork->getResource(MKID_BE('moov'), 0x80); + if (_fd) { + atom.size = _fd->size(); + if (readDefault(atom) < 0 || !_foundMOOV) + return false; + } + delete _fd; + + atom.type = 0; + atom.offset = 0; + atom.size = 0xffffffff; + } + + _fd = _resFork->getDataFork(); + + if (readDefault(atom) < 0 || !_foundMOOV || !_foundMDAT) + return false; + + init(); + return true; +} + bool QuickTimeDecoder::load(Common::SeekableReadStream &stream) { _fd = &stream; _foundMOOV = _foundMDAT = false; @@ -274,21 +314,22 @@ bool QuickTimeDecoder::load(Common::SeekableReadStream &stream) { _videoStreamIndex = _audioStreamIndex = -1; _startTime = 0; - initParseTable(); - MOVatom atom = { 0, 0, 0xffffffff }; - if (readDefault(atom) < 0 || (!_foundMOOV && !_foundMDAT)) + if (readDefault(atom) < 0 || !_foundMOOV || !_foundMDAT) { + _fd = 0; return false; + } - debug(0, "on_parse_exit_offset=%d", _fd->pos()); + init(); + return true; +} +void QuickTimeDecoder::init() { // 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]; @@ -302,14 +343,12 @@ bool QuickTimeDecoder::load(Common::SeekableReadStream &stream) { for (uint32 i = 0; i < _numStreams; i++) { MOVStreamContext *sc = _streams[i]; - if(!sc->time_rate) + if (!sc->time_rate) sc->time_rate = 1; - if(!sc->time_scale) + 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; @@ -341,8 +380,6 @@ bool QuickTimeDecoder::load(Common::SeekableReadStream &stream) { _scaledSurface->create(getWidth(), getHeight(), getPixelFormat().bytesPerPixel); } } - - return true; } void QuickTimeDecoder::initParseTable() { @@ -392,6 +429,11 @@ int QuickTimeDecoder::readDefault(MOVatom atom) { if (atom.size >= 8) { a.size = _fd->readUint32BE(); a.type = _fd->readUint32BE(); + + // Some QuickTime videos with resource forks have mdat chunks + // that are of size 0. Adjust it so it's the correct size. + if (a.size == 0) + a.size = _fd->size(); } total_size += 8; diff --git a/graphics/video/qt_decoder.h b/graphics/video/qt_decoder.h index dc0557b3885..545866f9e56 100644 --- a/graphics/video/qt_decoder.h +++ b/graphics/video/qt_decoder.h @@ -45,6 +45,7 @@ namespace Common { class File; + class MacResManager; } namespace Graphics { @@ -78,6 +79,12 @@ public: */ uint32 getFrameCount() const; + /** + * Load a video file + * @param filename the filename to load + */ + bool loadFile(const Common::String &filename); + /** * Load a QuickTime video file from a SeekableReadStream * @param stream the stream to load @@ -221,7 +228,6 @@ protected: uint32 _duration; uint32 _mdatOffset; uint32 _mdatSize; - uint32 _next_chunk_offset; MOVStreamContext *_partial; uint32 _numStreams; int _ni; @@ -230,6 +236,7 @@ protected: byte _palette[256 * 3]; bool _dirtyPalette; uint32 _beginOffset; + Common::MacResManager *_resFork; void initParseTable(); Audio::AudioStream *createAudioStream(Common::SeekableReadStream *stream); @@ -238,6 +245,7 @@ protected: uint32 getFrameDuration(); uint32 getCodecTag(); byte getBitsPerPixel(); + void init(); Audio::QueuingAudioStream *_audStream; void startAudio(); From 50847c02a6ca526a01f3eecae024e32973413a90 Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Mon, 24 May 2010 03:05:17 +0000 Subject: [PATCH 022/249] PSP: moved timer thread to backends/timer/psp svn-id: r49173 --- backends/module.mk | 1 + backends/platform/psp/Makefile | 3 +-- backends/platform/psp/module.mk | 3 +-- backends/platform/psp/osys_psp.h | 2 +- backends/{platform => timer}/psp/timer.cpp | 5 ++++- backends/{platform => timer}/psp/timer.h | 0 6 files changed, 8 insertions(+), 6 deletions(-) rename backends/{platform => timer}/psp/timer.cpp (96%) rename backends/{platform => timer}/psp/timer.h (100%) diff --git a/backends/module.mk b/backends/module.mk index 257ae0db9c1..59df56b4685 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -40,6 +40,7 @@ MODULE_OBJS := \ saves/posix/posix-saves.o \ saves/psp/psp-saves.o \ timer/default/default-timer.o \ + timer/psp/timer.o \ vkeybd/image-map.o \ vkeybd/polygon.o \ vkeybd/virtual-keyboard.o \ diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index 6acd8e970ab..6967973da75 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -148,8 +148,7 @@ OBJS := powerman.o \ trace.o \ psploader.o \ pspkeyboard.o \ - audio.o \ - timer.o + audio.o # Include common Scummvm makefile include $(srcdir)/Makefile.common diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk index 461df629bfc..0e5bd8737d1 100644 --- a/backends/platform/psp/module.mk +++ b/backends/platform/psp/module.mk @@ -13,8 +13,7 @@ MODULE_OBJS := powerman.o \ trace.o \ psploader.o \ pspkeyboard.o \ - audio.o \ - timer.o + audio.o MODULE_DIRS += \ backends/platform/psp/ diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h index 413de0f5286..3f075d01396 100644 --- a/backends/platform/psp/osys_psp.h +++ b/backends/platform/psp/osys_psp.h @@ -39,7 +39,7 @@ #include "backends/platform/psp/display_manager.h" #include "backends/platform/psp/input.h" #include "backends/platform/psp/audio.h" -#include "backends/platform/psp/timer.h" +#include "backends/timer/psp/timer.h" #include diff --git a/backends/platform/psp/timer.cpp b/backends/timer/psp/timer.cpp similarity index 96% rename from backends/platform/psp/timer.cpp rename to backends/timer/psp/timer.cpp index a35bd9d8278..55b63ba4fd0 100644 --- a/backends/platform/psp/timer.cpp +++ b/backends/timer/psp/timer.cpp @@ -23,12 +23,13 @@ * */ +#if defined (__PSP__) #include #include "common/scummsys.h" #include "common/timer.h" #include "backends/platform/psp/thread.h" -#include "backends/platform/psp/timer.h" +#include "backends/timer/psp/timer.h" //#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ //#define __PSP_DEBUG_PRINT__ /* For debug printouts */ @@ -78,3 +79,5 @@ void PspTimer::timerThread() { _callback(); } }; + +#endif /* __PSP__ */ diff --git a/backends/platform/psp/timer.h b/backends/timer/psp/timer.h similarity index 100% rename from backends/platform/psp/timer.h rename to backends/timer/psp/timer.h From 87eb782496c71fe10ac829769a8c9762f5372e6f Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Mon, 24 May 2010 06:57:58 +0000 Subject: [PATCH 023/249] PSP: switched to the way SDL does things in the audio thread to get rid of clicking. PSP's thread is still more efficient. svn-id: r49175 --- backends/platform/psp/audio.cpp | 70 +++++++++--------------------- backends/platform/psp/osys_psp.cpp | 2 +- 2 files changed, 22 insertions(+), 50 deletions(-) diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp index 58b22518114..2afc62d4503 100644 --- a/backends/platform/psp/audio.cpp +++ b/backends/platform/psp/audio.cpp @@ -23,7 +23,6 @@ * */ -#include #include #include @@ -80,7 +79,7 @@ bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, call _bufferSize = numOfSamples * numOfChannels * sizeof(uint16); // should be the right size to send the app _callback = callback; _userData = userData; - _emptyBuffers = NUM_BUFFERS; + _emptyBuffers = NUM_BUFFERS - 1; // because we'll increase in the beginning _bufferToFill = 0; _bufferToPlay = 0; @@ -134,10 +133,10 @@ void PspAudio::audioThread() { if (_paused) PSP_DEBUG_PRINT("audio thread paused\n"); while (_paused) { // delay until we stop pausing - SDL_Delay(100); + sceKernelDelayThread(100000); // 100ms + if (!_paused) + PSP_DEBUG_PRINT("audio thread unpaused\n"); } - if (!_paused) - PSP_DEBUG_PRINT("audio thread unpaused\n"); // check if the audio is playing remainingSamples = sceAudioGetChannelRestLen(_pspChannel); @@ -148,49 +147,22 @@ void PspAudio::audioThread() { isPlaying = remainingSamples ? true : false; PSP_DEBUG_PRINT("remaining samples[%d]\n", remainingSamples); + + if (!isPlaying) { + _emptyBuffers++; + } - while (true) { // really only execute once. this just helps write the logic - if (isPlaying) { - _stoppedPlayingOnceFlag = false; - - // check if a buffer is empty - if (_emptyBuffers) { // we have some empty buffers - PSP_DEBUG_PRINT("sound playing & an empty buffer. filling buffer[%d]. empty buffers[%d]\n", _bufferToFill, _emptyBuffers); - _callback(_userData, _buffers[_bufferToFill], _bufferSize); // ask mixer to fill in - nextBuffer(_bufferToFill); - _emptyBuffers--; - break; - } else { // we have no empty buffers - // calculate how long we need to sleep. time(us) = samples * 1000000 / freq - // since frequency is always 44100, we can do a shortcut: - // time(us) = samples * (10000 / 441) - uint32 sleepTime = (remainingSamples * 10000) / 441; - if (!sleepTime) - break; - PSP_DEBUG_PRINT("sound playing & no empty buffers. sleeping for %d samples for %dus\n", remainingSamples, sleepTime); - sceKernelDelayThread(sleepTime); - break; - } - } else { // we're not playing right now - if (_stoppedPlayingOnceFlag == false) { // we only want to do this when we finish playing - nextBuffer(_bufferToPlay); - _emptyBuffers++; - _stoppedPlayingOnceFlag = true; - } - - if (_emptyBuffers == NUM_BUFFERS) { // problem: we have only empty buffers! - PSP_DEBUG_PRINT("no sound playing & no full buffer. filling buffer[%d]. empty buffers[%d]\n", _bufferToFill, _emptyBuffers); - _callback(_userData, _buffers[_bufferToFill], _bufferSize); - nextBuffer(_bufferToFill); - _emptyBuffers--; - break; - } else { // we have at least one non-empty buffer - PSP_DEBUG_PRINT("no sound playing & a full buffer. playing buffer[%d]. empty buffers[%d]\n", _bufferToPlay, _emptyBuffers); - playBuffer(); - break; - } - } - } // while true + while (_emptyBuffers) { // we have some empty buffers + PSP_DEBUG_PRINT("filling buffer[%d]. empty buffers[%d]\n", _bufferToFill, _emptyBuffers); + _callback(_userData, _buffers[_bufferToFill], _bufferSize); // ask mixer to fill in + nextBuffer(_bufferToFill); + _emptyBuffers--; + break; + } + + PSP_DEBUG_PRINT("playing buffer[%d]. empty buffers[%d]\n", _bufferToPlay, _emptyBuffers); + playBuffer(); + nextBuffer(_bufferToPlay); } // while _init // destroy everything @@ -212,9 +184,9 @@ inline bool PspAudio::playBuffer() { DEBUG_ENTER_FUNC(); int ret; if (_numOfChannels == 1) - ret = sceAudioOutput(_pspChannel, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]); + ret = sceAudioOutputBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]); else - ret = sceAudioOutputPanned(_pspChannel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]); + ret = sceAudioOutputPannedBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]); if (ret < 0) { PSP_ERROR("failed to output audio. Error[%d]\n", ret); diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index d29196619b8..f33081abbc1 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -48,7 +48,7 @@ #include "backends/platform/psp/trace.h" -//#define USE_PSP_AUDIO +#define USE_PSP_AUDIO #define SAMPLES_PER_SEC 44100 From f9217ec031ff1740db0a7baca2fc486fe1d3d26f Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 24 May 2010 07:47:07 +0000 Subject: [PATCH 024/249] Added Russian airport and farm. Needs more work as crashes at attempt to opening some dictionary entries with Cyrillic characters svn-id: r49176 --- engines/scumm/scumm-md5.h | 4 +++- tools/scumm-md5.txt | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 9b7e0798eba..10a427b83fd 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 07:43:51 2010 DO NOT EDIT MANUALLY! */ @@ -175,6 +175,7 @@ static const MD5Table md5table[] = { { "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 +244,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/tools/scumm-md5.txt b/tools/scumm-md5.txt index 7b9918ba43a..48f259fef58 100644 --- a/tools/scumm-md5.txt +++ b/tools/scumm-md5.txt @@ -584,6 +584,7 @@ catalog Humongous Interactive Catalog airport Let's Explore the Airport with Buzzy d6334a5a9b61afe18c368540fdf522ca -1 en Mac - - - Joachim Eberhard 07433205acdca3bc553d0e731588b35f -1 en Windows - - - Kirben + 3e861421f494711bc6f619d4aba60285 93231 ru Windows - - - sev 7ea2da67ebabea4ac20cee9f4f9d2934 -1 en Mac - Demo - khalek 8ffd618a776a4c0d8922bb28b09f8ce8 -1 en Windows - Demo - khalek @@ -595,6 +596,7 @@ farm Let's Explore the Farm with Buzzy a5c5388da9bf0e6662fdca8813a79d13 86962 en Windows - - - George Kormendi a85856675429fe88051744f755b72f93 -1 en Windows - - - Kirben a2386da005672cbd5136f4f27a626c5f 87061 nl Windows - - - George Kormendi + 5dda73606533d66a4c3f4f9ea6e842af 87061 ru Windows - - - sev 39fd6db10d0222d817025c4d3346e3b4 -1 en Mac - Demo - Joachim Eberhard bf8b52fdd9a69c67f34e8e9fec72661c -1 en Windows HE 71 Demo - khalek, sev From cfbf1a8a673295a621ee618be86bb7c42c531a8f Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Mon, 24 May 2010 09:19:40 +0000 Subject: [PATCH 025/249] PSP: turn off psp audio thread again. Must have tested it wrong. svn-id: r49178 --- backends/platform/psp/osys_psp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index f33081abbc1..d29196619b8 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -48,7 +48,7 @@ #include "backends/platform/psp/trace.h" -#define USE_PSP_AUDIO +//#define USE_PSP_AUDIO #define SAMPLES_PER_SEC 44100 From 55e29af78a52a13269d9905c6410e70f56b5920d Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Mon, 24 May 2010 11:41:45 +0000 Subject: [PATCH 026/249] PSP: switched to using slightly faster delay and getMillis svn-id: r49179 --- backends/platform/psp/Makefile | 3 +- backends/platform/psp/module.mk | 3 +- backends/platform/psp/osys_psp.cpp | 7 ++-- backends/platform/psp/thread.cpp | 52 ++++++++++++++++++++++++++++++ backends/platform/psp/thread.h | 10 ++++++ 5 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 backends/platform/psp/thread.cpp diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index 6967973da75..7c33999b4db 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -148,7 +148,8 @@ OBJS := powerman.o \ trace.o \ psploader.o \ pspkeyboard.o \ - audio.o + audio.o \ + thread.o # Include common Scummvm makefile include $(srcdir)/Makefile.common diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk index 0e5bd8737d1..4d375bcef09 100644 --- a/backends/platform/psp/module.mk +++ b/backends/platform/psp/module.mk @@ -13,7 +13,8 @@ MODULE_OBJS := powerman.o \ trace.o \ psploader.o \ pspkeyboard.o \ - audio.o + audio.o \ + thread.o MODULE_DIRS += \ backends/platform/psp/ diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index d29196619b8..ed7fb2d3cf7 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -37,6 +37,7 @@ #include "backends/platform/psp/psppixelformat.h" #include "backends/platform/psp/osys_psp.h" #include "backends/platform/psp/powerman.h" +#include "backends/platform/psp/thread.h" #include "backends/saves/psp/psp-saves.h" #include "backends/timer/default/default-timer.h" @@ -298,17 +299,15 @@ bool OSystem_PSP::pollEvent(Common::Event &event) { return _inputHandler.getAllInputs(event); } - uint32 OSystem_PSP::getMillis() { - return SDL_GetTicks(); + return PspThread::getMillis(); } void OSystem_PSP::delayMillis(uint msecs) { - SDL_Delay(msecs); + PspThread::delayMillis(msecs); } void OSystem_PSP::setTimerCallback(TimerProc callback, int interval) { - //SDL_SetTimer(interval, (SDL_TimerCallback)callback); _pspTimer.setCallback((PspTimer::CallbackFunc)callback); _pspTimer.setIntervalMs(interval); _pspTimer.start(); diff --git a/backends/platform/psp/thread.cpp b/backends/platform/psp/thread.cpp new file mode 100644 index 00000000000..88e7b6fe386 --- /dev/null +++ b/backends/platform/psp/thread.cpp @@ -0,0 +1,52 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.h $ + * $Id: osys_psp.h 49173 2010-05-24 03:05:17Z bluddy $ + * + */ + +#include +#include +#include +#include + +#include "backends/platform/psp/thread.h" + +void PspThread::delayMillis(uint32 ms) { + sceKernelDelayThread(ms * 1000); +} + +void PspThread::delayMicros(uint32 us) { + sceKernelDelayThread(us); +} + +uint32 PspThread::getMillis() { + uint32 ticks[2]; + sceRtcGetCurrentTick((u64 *)ticks); + return (ticks[0]/1000); +} + +uint32 PspThread::getMicros() { + uint32 ticks[2]; + sceRtcGetCurrentTick((u64 *)ticks); + return ticks[0]; +} + diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h index d395d6713e1..9ed3a2e2dc0 100644 --- a/backends/platform/psp/thread.h +++ b/backends/platform/psp/thread.h @@ -26,6 +26,16 @@ #ifndef PSP_THREAD_H #define PSP_THREAD_H +#include "common/scummsys.h" + +class PspThread { +public: + static void delayMillis(uint32 ms); + static void delayMicros(uint32 us); + static uint32 getMillis(); + static uint32 getMicros(); +}; + enum ThreadPriority { PRIORITY_MAIN_THREAD = 36, PRIORITY_AUDIO_THREAD = 35, // We'll alternate between this and main thread priority From 6bda3e15db6baaa3af3d479e86dad2dd4f95084f Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 24 May 2010 12:12:27 +0000 Subject: [PATCH 027/249] Implemented the bulk of the logic for displaying timed on-screen messages svn-id: r49180 --- engines/m4/mads_logic.cpp | 11 +++ engines/m4/mads_logic.h | 1 + engines/m4/mads_scene.cpp | 54 +------------- engines/m4/mads_views.cpp | 152 +++++++++++++++++++++++++++++++++++--- engines/m4/mads_views.h | 21 +++--- 5 files changed, 167 insertions(+), 72 deletions(-) diff --git a/engines/m4/mads_logic.cpp b/engines/m4/mads_logic.cpp index 1fe5f4beb3b..ee65d3be5ca 100644 --- a/engines/m4/mads_logic.cpp +++ b/engines/m4/mads_logic.cpp @@ -245,4 +245,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 a589556a21f..774ed016a64 100644 --- a/engines/m4/mads_logic.h +++ b/engines/m4/mads_logic.h @@ -54,6 +54,7 @@ public: void setupScene(); void enterScene(); void doAction(); + void sceneStep(); }; } diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp index 4f28cdc6da9..1b8e44b5815 100644 --- a/engines/m4/mads_scene.cpp +++ b/engines/m4/mads_scene.cpp @@ -302,7 +302,9 @@ void MadsScene::update() { } void MadsScene::updateState() { + _sceneLogic.sceneStep(); _sequenceList.tick(); + _kernelMessages.update(); } int MadsScene::loadSceneSpriteSet(const char *setName) { @@ -653,56 +655,4 @@ void MadsSceneResources::load(int sId) { /*--------------------------------------------------------------------------*/ -/** - * Adds a new entry to the timed on-screen text display list - */ -/* -void MadsScreenText::draw(M4Surface *surface) { -} - -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 MadsScreenText::addTimedText(TimedText *entry) { - if ((entry->flags & TEXTFLAG_40) != 0) { - this->setActive2(entry->textDisplayIndex); - entry->flags &= 0x7F; - return; - } - - if ((entry->flags & TEXTFLAG_8) == 0) - // FIXME: Adjust timeouts for ScumVM's milli counter - entry->timeout -= 3; - - if ((entry->flags & TEXTFLAG_4) != 0) { - Text4A &rec = _text4A[entry->unk4AIndex]; - if ((rec.field25 != 0) || (rec.active == 0)) - entry->timeout = 0; - } - - if ((entry->timeout == 0) && !_abortTimedText) { - entry->flags |= TEXTFLAG_40; - - 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]; - } - } - } - - // TODO: code from 'loc_244ec' onwards -} -*/ - } // End of namespace M4 diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp index e82a9976a57..7a71509041b 100644 --- a/engines/m4/mads_views.cpp +++ b/engines/m4/mads_views.cpp @@ -324,12 +324,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() { @@ -352,8 +353,8 @@ int MadsKernelMessageList::add(const Common::Point &pt, uint fontColour, uint8 f 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; @@ -378,13 +379,13 @@ int MadsKernelMessageList::addQuote(int quoteId, int v2, uint32 timeout) { return add(Common::Point(0, 0), 0x1110, KMSG_2 | KMSG_20, v2, timeout, quoteStr); } -void MadsKernelMessageList::unk1(int msgIndex, int v1, int v2) { +void MadsKernelMessageList::unk1(int msgIndex, int numTicks, int v2) { if (msgIndex < 0) return; _entries[msgIndex].flags |= (v2 == 0) ? KMSG_8 : (KMSG_8 | KMSG_1); _entries[msgIndex].msgOffset = 0; - _entries[msgIndex].field_E = v1; + _entries[msgIndex].numTicks = numTicks; _entries[msgIndex].frameTimer2 = _madsVm->_currentTimer; const char *msgP = _entries[msgIndex].msg; @@ -405,7 +406,7 @@ void MadsKernelMessageList::setSeqIndex(int msgIndex, int seqIndex) { } void MadsKernelMessageList::remove(int msgIndex) { - MadsKernelMessageListEntry &rec = _entries[msgIndex]; + MadsKernelMessageEntry &rec = _entries[msgIndex]; if (rec.flags & KMSG_ACTIVE) { if (rec.flags & KMSG_8) { @@ -427,6 +428,135 @@ 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_40) != 0) { + _owner._textDisplay.expire(msg.textDisplayIndex); + msg.flags &= !KMSG_ACTIVE; + return; + } + + if ((msg.flags & KMSG_8) == 0) { + msg.timeout -= 3; + } + + if (msg.flags & KMSG_4) { + MadsSequenceEntry &seqEntry = _owner._sequenceList[msg.sequenceIndex]; + if (seqEntry.doneFlag || !seqEntry.active) + msg.timeout = 0; + } + + if ((msg.timeout <= 0) && (_owner._abortTimers == 0)) { + msg.flags |= KMSG_40; + if (msg.field_1C != 0) { + _owner._abortTimers = msg.field_1C; + _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_4) { + MadsSequenceEntry &seqEntry = _owner._sequenceList[msg.sequenceIndex]; + if (seqEntry.field_12) { + 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_2) { + 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_8) && (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) { + *msgP = '\0'; + msg.flags &= ~KMSG_8; + } else if (msg.flags & KMSG_1) { + *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_30) { + x1 -= (msg.flags & KMSG_20) ? 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; + } +} + //-------------------------------------------------------------------------- /** @@ -725,7 +855,7 @@ 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, char field_12, char scale, uint8 depth, int frameInc, SpriteAnimType animType, int numSprites, int frameStart) { // Find a free slot @@ -754,8 +884,8 @@ int MadsSequenceList::add(int spriteListIndex, int v0, int frameIndex, int trigg _entries[timerIndex].depth = depth; _entries[timerIndex].scale = scale; _entries[timerIndex].field_12 = field_12; - _entries[timerIndex].width = width; - _entries[timerIndex].height = height; + _entries[timerIndex].msgPos.x = msgX; + _entries[timerIndex].msgPos.y = msgY; _entries[timerIndex].numTicks = numTicks; _entries[timerIndex].extraTicks = extraTicks; @@ -796,8 +926,8 @@ void MadsSequenceList::setSpriteSlot(int timerIndex, MadsSpriteSlot &spriteSlot) spriteSlot.scale = timerEntry.scale; if (timerEntry.field_12 == 0) { - spriteSlot.xp = timerEntry.width; - spriteSlot.yp = timerEntry.height; + 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; diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h index 3b64cc77f2c..52388a99e07 100644 --- a/engines/m4/mads_views.h +++ b/engines/m4/mads_views.h @@ -139,9 +139,10 @@ public: #define TIMED_TEXT_SIZE 10 #define TEXT_4A_SIZE 30 -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_1 = 1, KMSG_2 = 2, KMSG_4 = 4, KMSG_8 = 8, KMSG_20 = 0x20, KMSG_30 = 0x30, + KMSG_40 = 0x40, KMSG_ACTIVE = 0x80}; -class MadsKernelMessageListEntry { +class MadsKernelMessageEntry { public: uint8 flags; int sequenceIndex; @@ -152,21 +153,23 @@ public: Common::Point position; int textDisplayIndex; int msgOffset; - int field_E; + int numTicks; uint32 frameTimer2; uint32 frameTimer; uint32 timeout; bool field_1C; AbortTimerMode abortMode; uint16 actionNouns[3]; - const char *msg; + char msg[100]; }; class MadsKernelMessageList { private: MadsView &_owner; - Common::Array _entries; + Common::Array _entries; Font *_talkFont; +public: + int word_8469E; public: MadsKernelMessageList(MadsView &owner); @@ -177,6 +180,8 @@ public: void setSeqIndex(int msgIndex, int seqIndex); void remove(int msgIndex); void reset(); + void update(); + void processText(int msgIndex); }; class ScreenObjectEntry { @@ -311,9 +316,7 @@ struct MadsSequenceEntry { int field_12; int field_13; - int width; - int height; - + Common::Point msgPos; int triggerCountdown; bool doneFlag; MadsSequenceSubEntries entries; @@ -338,7 +341,7 @@ 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, char field_12, char scale, uint8 depth, int frameInc, SpriteAnimType animType, int numSprites, int frameStart); void remove(int timerIndex); void setSpriteSlot(int timerIndex, MadsSpriteSlot &spriteSlot); From 35b3c3c083f0cea69de2a210379dc703ea8fca71 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 24 May 2010 13:18:00 +0000 Subject: [PATCH 028/249] Fix compilation under MinGW svn-id: r49181 --- tools/module.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/module.mk b/tools/module.mk index 4117ceac778..896a2e504bc 100644 --- a/tools/module.mk +++ b/tools/module.mk @@ -36,15 +36,15 @@ clean-tools: tools/convbdf$(EXEEXT): $(srcdir)/tools/convbdf.c $(QUIET)$(MKDIR) tools/$(DEPDIR) - $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $< + $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $< tools/md5table$(EXEEXT): $(srcdir)/tools/md5table.c $(QUIET)$(MKDIR) tools/$(DEPDIR) - $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $< + $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $< tools/make-scumm-fontdata$(EXEEXT): $(srcdir)/tools/make-scumm-fontdata.c $(QUIET)$(MKDIR) tools/$(DEPDIR) - $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $< + $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $< # # Rules to explicitly rebuild the credits / MD5 tables. From c8584b7a82a3a97a6e5fb9cddde1b98ccd512292 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 24 May 2010 13:20:35 +0000 Subject: [PATCH 029/249] Fix warnings svn-id: r49182 --- tools/md5table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/md5table.c b/tools/md5table.c index b69f3957cd8..6823607b27c 100644 --- a/tools/md5table.c +++ b/tools/md5table.c @@ -221,7 +221,7 @@ int main(int argc, char *argv[]) const int entrySize = 256; int numEntries = 0, maxEntries = 1; - char *entriesBuffer = malloc(maxEntries * entrySize); + char *entriesBuffer = (char *)malloc(maxEntries * entrySize); typedef enum { kCPPOutput, @@ -294,7 +294,7 @@ int main(int argc, char *argv[]) } else if (entry.md5) { if (numEntries >= maxEntries) { maxEntries *= 2; - entriesBuffer = realloc(entriesBuffer, maxEntries * entrySize); + entriesBuffer = (char *)realloc(entriesBuffer, maxEntries * entrySize); } if (0 == strcmp(entry.variant, "-")) entry.variant = ""; From 19f369fe3bfcd1e2bed01f8d92898d06193050ee Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 24 May 2010 13:22:52 +0000 Subject: [PATCH 030/249] Added Russian Windows release of puttmoon svn-id: r49183 --- tools/scumm-md5.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/scumm-md5.txt b/tools/scumm-md5.txt index 48f259fef58..0637c386d7e 100644 --- a/tools/scumm-md5.txt +++ b/tools/scumm-md5.txt @@ -708,6 +708,7 @@ puttmoon Putt-Putt Goes to the Moon 697c9b7c55a05d8199c48b48e379d2c8 -1 he DOS - - - sev 9dc02577bf50d4cfaf3de3fbac06fbe2 -1 en Mac - - - khalek 9c92eeaf517a31b7221ec2546ab669fd -1 en Windows HE 70 - - khalek + 3c4c471342bd95505a42334367d8f127 12161 ru Windows HE 70 - - sev aa6a91b7f6f119d1b7b1f2a4c9e24d59 6233 en DOS - Demo - 4af4a6b248103c1fe9edef619677f540 -1 en Mac - Demo - khalek From 6e66fa3726a4616b093c2ffd7227d161ab4d70a7 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 24 May 2010 13:26:16 +0000 Subject: [PATCH 031/249] sync svn-id: r49184 --- engines/scumm/scumm-md5.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 10a427b83fd..cc382d9621b 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 Mon May 24 07:43:51 2010 + This file was generated by the md5table tool on Mon May 24 13:24:24 2010 DO NOT EDIT MANUALLY! */ @@ -170,6 +170,7 @@ 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 }, From 350e3d7c053deb202ee8411f1ebda0a97a48e4e9 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Mon, 24 May 2010 13:50:19 +0000 Subject: [PATCH 032/249] SCI: remove isQueued status when sound gets stopped - fixes iceman resuming music when entering hotel complex (with bar) right at the start svn-id: r49186 --- engines/sci/sound/music.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 27074e2db6a..25d2de48bf9 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -305,6 +305,7 @@ void SciMusic::soundPlay(MusicEntry *pSnd) { void SciMusic::soundStop(MusicEntry *pSnd) { pSnd->status = kSoundStopped; + pSnd->isQueued = false; if (pSnd->pStreamAud) _pMixer->stopHandle(pSnd->hCurrentAud); From b49efb67f6e6f9d8b8107ec0de82055588fe215f Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Mon, 24 May 2010 14:47:43 +0000 Subject: [PATCH 033/249] SCI: only remove isQueued status for sound sci0 svn-id: r49187 --- engines/sci/sound/music.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 25d2de48bf9..86c7669df9e 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -305,7 +305,8 @@ void SciMusic::soundPlay(MusicEntry *pSnd) { void SciMusic::soundStop(MusicEntry *pSnd) { pSnd->status = kSoundStopped; - pSnd->isQueued = false; + if (_soundVersion <= SCI_VERSION_0_LATE) + pSnd->isQueued = false; if (pSnd->pStreamAud) _pMixer->stopHandle(pSnd->hCurrentAud); From e9db62b272409580e45e776d4dfcd358670d6ccd Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Mon, 24 May 2010 15:39:30 +0000 Subject: [PATCH 034/249] SCI: sort according to original order in kAnimate, when y and z are the same - fixes iceman half-open compartment in room 35 svn-id: r49189 --- engines/sci/graphics/animate.cpp | 11 ++++++++++- engines/sci/graphics/animate.h | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp index 71c7b7dd7f4..8a03c9579b1 100644 --- a/engines/sci/graphics/animate.cpp +++ b/engines/sci/graphics/animate.cpp @@ -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,6 +164,7 @@ void GfxAnimate::makeSortedList(List *list) { listEntry->object = curObject; // Get data from current object + listEntry->givenOrderNo = listNr; 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)); diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h index 2cc59b1767a..706b7182cf0 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; From 5ceb896b6b1d4a2d2ac83fdc5552013ab5abedc2 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 24 May 2010 16:51:33 +0000 Subject: [PATCH 035/249] Have the MacResManager ignore resources with length 0. svn-id: r49190 --- common/macresman.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/common/macresman.cpp b/common/macresman.cpp index de78cedf61f..6a6a8180836 100644 --- a/common/macresman.cpp +++ b/common/macresman.cpp @@ -439,6 +439,11 @@ Common::SeekableReadStream *MacResManager::getResource(uint32 typeID, uint16 res _stream->seek(_dataOffset + _resLists[typeNum][resNum].dataOffset); uint32 len = _stream->readUint32BE(); + + // Ignore resources with 0 length + if (!len) + return 0; + return _stream->readStream(len); } @@ -448,6 +453,11 @@ Common::SeekableReadStream *MacResManager::getResource(const Common::String &fil if (_resLists[i][j].nameOffset != -1 && filename.equalsIgnoreCase(_resLists[i][j].name)) { _stream->seek(_dataOffset + _resLists[i][j].dataOffset); uint32 len = _stream->readUint32BE(); + + // Ignore resources with 0 length + if (!len) + return 0; + return _stream->readStream(len); } } From 07ccf29ecf30b231191d6787564b675e7fb9c4a1 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 24 May 2010 16:56:56 +0000 Subject: [PATCH 036/249] Fix Russian versions of airport and farm as they use extended charset. svn-id: r49191 --- engines/scumm/charset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index 757171b24c7..0e0c0e129ee 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; From c96e234a0a48f91d52cda875485efeb644e4047f Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 24 May 2010 16:58:14 +0000 Subject: [PATCH 037/249] Fix warning svn-id: r49192 --- engines/parallaction/input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 17254cf4241..d6dd9feb19a 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) { From e39bf477173d6f0f75ddaf827338ebe0d4195525 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 24 May 2010 16:58:42 +0000 Subject: [PATCH 038/249] Fix crash when there is no drascula.dat file svn-id: r49193 --- engines/drascula/drascula.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index 276554a24c2..2c3ca63600d 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; From afd909d69e461f42b454e8b6ff89cdca145890be Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 24 May 2010 16:59:06 +0000 Subject: [PATCH 039/249] Fix bug #2827172: DRASCULA: Cursor appears ontop of ending and credits svn-id: r49194 --- engines/drascula/animation.cpp | 2 +- engines/drascula/objects.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp index 4a0b82d7466..e4bd844d75d 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/objects.cpp b/engines/drascula/objects.cpp index c4dc3df1f68..13c8a742ca4 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(); } From ad0eb0b06ef6c715280c21a1c036be5c56a3183a Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 24 May 2010 17:18:09 +0000 Subject: [PATCH 040/249] Move the PICT code to graphics/ with some updates; needed for SCI1.1 Mac. svn-id: r49195 --- engines/mohawk/graphics.cpp | 2 +- engines/mohawk/graphics.h | 4 +- engines/mohawk/module.mk | 1 - graphics/module.mk | 1 + .../mohawk/myst_pict.cpp => graphics/pict.cpp | 212 ++++++++++++------ engines/mohawk/myst_pict.h => graphics/pict.h | 56 +++-- 6 files changed, 183 insertions(+), 93 deletions(-) rename engines/mohawk/myst_pict.cpp => graphics/pict.cpp (52%) rename engines/mohawk/myst_pict.h => graphics/pict.h (57%) diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp index 1b220c861bb..2ddfb475750 100644 --- a/engines/mohawk/graphics.cpp +++ b/engines/mohawk/graphics.cpp @@ -79,7 +79,7 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : _vm(vm) { if (_vm->getFeatures() & GF_ME) { _jpegDecoder = new Graphics::JPEGDecoder(); - _pictDecoder = new MystPICT(_jpegDecoder); + _pictDecoder = new Graphics::PictDecoder(_pixelFormat); } else { _jpegDecoder = NULL; _pictDecoder = NULL; diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h index 23b1ace3472..dd1764e6d68 100644 --- a/engines/mohawk/graphics.h +++ b/engines/mohawk/graphics.h @@ -28,9 +28,9 @@ #include "mohawk/bitmap.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 { @@ -104,7 +104,7 @@ public: private: MohawkEngine_Myst *_vm; MystBitmap *_bmpDecoder; - MystPICT *_pictDecoder; + Graphics::PictDecoder *_pictDecoder; Graphics::JPEGDecoder *_jpegDecoder; Graphics::PixelFormat _pixelFormat; diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk index 8c23cdfa870..bb79d4abacd 100644 --- a/engines/mohawk/module.mk +++ b/engines/mohawk/module.mk @@ -9,7 +9,6 @@ MODULE_OBJS = \ livingbooks.o \ mohawk.o \ myst.o \ - myst_pict.o \ myst_vars.o \ myst_saveload.o \ myst_scripts.o \ diff --git a/graphics/module.mk b/graphics/module.mk index c7f57714206..75e39193704 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -13,6 +13,7 @@ MODULE_OBJS := \ iff.o \ imagedec.o \ jpeg.o \ + pict.o \ primitives.o \ scaler.o \ scaler/thumbnail_intern.o \ diff --git a/engines/mohawk/myst_pict.cpp b/graphics/pict.cpp similarity index 52% rename from engines/mohawk/myst_pict.cpp rename to graphics/pict.cpp index 2dfed65d2b5..f0dd7bbc6f5 100644 --- a/engines/mohawk/myst_pict.cpp +++ b/graphics/pict.cpp @@ -23,26 +23,38 @@ * */ -#include "common/system.h" +#include "common/stream.h" -#include "mohawk/myst_pict.h" +#include "graphics/conversion.h" +#include "graphics/jpeg.h" +#include "graphics/pict.h" +#include "graphics/surface.h" -namespace Mohawk { +namespace Graphics { // The PICT code is based off of the QuickDraw specs: -// http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-461.html +// http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-461.html +// http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-269.html -MystPICT::MystPICT(Graphics::JPEGDecoder *jpegDecoder) { - _jpegDecoder = jpegDecoder; - _pixelFormat = g_system->getScreenFormat(); +PictDecoder::PictDecoder(PixelFormat pixelFormat) { + _jpeg = new JPEG(); + _pixelFormat = pixelFormat; } -Graphics::Surface *MystPICT::decodeImage(Common::SeekableReadStream *stream) { - // Skip initial 512 bytes (all 0's) - stream->seek(512, SEEK_CUR); +PictDecoder::~PictDecoder() { + delete _jpeg; +} - // Read in the first part of the header - /* uint16 fileSize = */ stream->readUint16BE(); +Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *palette) { + assert(stream); + + uint16 fileSize = stream->readUint16BE(); + + // If we have no file size here, we probably have a PICT from a file + // and not a resource. The other two bytes are the fileSize which we + // don't actually need (and already read if from a resource). + if (!fileSize) + stream->seek(512 + 2); _imageRect.top = stream->readUint16BE(); _imageRect.left = stream->readUint16BE(); @@ -52,11 +64,12 @@ Graphics::Surface *MystPICT::decodeImage(Common::SeekableReadStream *stream) { Graphics::Surface *image = new Graphics::Surface(); image->create(_imageRect.width(), _imageRect.height(), _pixelFormat.bytesPerPixel); + _isPaletted = false; // NOTE: This is only a subset of the full PICT format. // - Only V2 Images Supported - // - JPEG Chunks are Supported - // - DirectBitsRect Chunks are Supported + // - CompressedQuickTime (JPEG) compressed data is supported + // - DirectBitsRect/PackBitsRect compressed data is 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); @@ -82,8 +95,11 @@ Graphics::Surface *MystPICT::decodeImage(Common::SeekableReadStream *stream) { error ("Unknown PICT version"); } else if (opcode == 0x001E) { // DefHilite // Ignore, Contains no Data + } else if (opcode == 0x0098) { // PackBitsRect + decodeDirectBitsRect(stream, image, true); + _isPaletted = true; } else if (opcode == 0x009A) { // DirectBitsRect - decodeDirectBitsRect(stream, image); + decodeDirectBitsRect(stream, image, false); } else if (opcode == 0x00A1) { // LongComment stream->readUint16BE(); uint16 dataSize = stream->readUint16BE(); @@ -106,59 +122,71 @@ Graphics::Surface *MystPICT::decodeImage(Common::SeekableReadStream *stream) { decodeCompressedQuickTime(stream, image); break; } else { - error ("Unknown PICT opcode %04x", opcode); + warning("Unknown PICT opcode %04x", opcode); } } + // If we got a palette throughout this nonsense, go and grab it + if (palette && _isPaletted) + memcpy(palette, _palette, 256 * 4); + return image; } +PictDecoder::PixMap PictDecoder::readPixMap(Common::SeekableReadStream *stream, bool hasBaseAddr) { + PixMap pixMap; + pixMap.baseAddr = hasBaseAddr ? stream->readUint32BE() : 0; + pixMap.rowBytes = stream->readUint16BE() & 0x3fff; + pixMap.bounds.top = stream->readUint16BE(); + pixMap.bounds.left = stream->readUint16BE(); + pixMap.bounds.bottom = stream->readUint16BE(); + pixMap.bounds.right = stream->readUint16BE(); + pixMap.pmVersion = stream->readUint16BE(); + pixMap.packType = stream->readUint16BE(); + pixMap.packSize = stream->readUint32BE(); + pixMap.hRes = stream->readUint32BE(); + pixMap.vRes = stream->readUint32BE(); + pixMap.pixelType = stream->readUint16BE(); + pixMap.pixelSize = stream->readUint16BE(); + pixMap.cmpCount = stream->readUint16BE(); + pixMap.cmpSize = stream->readUint16BE(); + pixMap.planeBytes = stream->readUint32BE(); + pixMap.pmTable = stream->readUint32BE(); + pixMap.pmReserved = stream->readUint32BE(); + return pixMap; +} + 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; + PictDecoder::PixMap 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); +void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, Surface *image, bool hasPalette) { + static const PixelFormat directBitsFormat16 = PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); + + // Clear the palette + memset(_palette, 0, sizeof(_palette)); 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.pixMap = readPixMap(stream, !hasPalette); + + // Read in the palette if there is one present + if (hasPalette) { + // See http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-267.html + stream->readUint32BE(); // seed + stream->readUint16BE(); // flags + uint16 colorCount = stream->readUint16BE() + 1; + + for (uint32 i = 0; i < colorCount; i++) { + stream->readUint16BE(); + _palette[i * 4] = stream->readUint16BE() >> 8; + _palette[i * 4 + 1] = stream->readUint16BE() >> 8; + _palette[i * 4 + 2] = stream->readUint16BE() >> 8; + } + } + directBitsData.srcRect.top = stream->readUint16BE(); directBitsData.srcRect.left = stream->readUint16BE(); directBitsData.srcRect.bottom = stream->readUint16BE(); @@ -169,34 +197,44 @@ void MystPICT::decodeDirectBitsRect(Common::SeekableReadStream *stream, Graphics 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); + if (directBitsData.pixMap.pixelSize != 8 && 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 bytesPerPixel = (directBitsData.pixMap.pixelSize == 32) ? 3 : directBitsData.pixMap.pixelSize / 8; 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 + // NOTE: Compression 0 is "default". The format in SCI games is packed when 0. + // In the future, we may need to have something to set the "default" packing + // format, but this is good for now. + + if (directBitsData.pixMap.packType == 1 || directBitsData.pixMap.rowBytes < 8) { // Unpacked, Pad-Byte (on 24-bit) + // TODO: Finish this. Hasn't been needed (yet). + error("Unpacked DirectBitsRect data (padded)"); + } else if (directBitsData.pixMap.packType == 2) { // Unpacked, No Pad-Byte (on 24-bit) + // TODO: Finish this. Hasn't been needed (yet). + error("Unpacked DirectBitsRect data (not padded)"); + } else if (directBitsData.pixMap.packType == 0 || 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) { + + if (bytesPerPixel == 1) { + // Just copy to the image + memcpy(image->pixels, buffer, image->w * image->h); + } else 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); + if (_pixelFormat.bytesPerPixel == 2) + *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); + else + *((uint32 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); } } } else { @@ -206,7 +244,10 @@ void MystPICT::decodeDirectBitsRect(Common::SeekableReadStream *stream, Graphics 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); + if (_pixelFormat.bytesPerPixel == 2) + *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); + else + *((uint32 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); } } } @@ -214,7 +255,7 @@ void MystPICT::decodeDirectBitsRect(Common::SeekableReadStream *stream, Graphics delete[] buffer; } -void MystPICT::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel) { +void PictDecoder::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel) { uint32 dataDecoded = 0; byte bytesPerDecode = (bytesPerPixel == 2) ? 2 : 1; @@ -256,14 +297,37 @@ void MystPICT::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableRe // 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) { +void PictDecoder::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); + Common::SeekableReadStream *jpegStream = new Common::SeekableSubReadStream(stream, stream->pos() + 156, stream->pos() + dataSize); - image->copyFrom(*jpegImage); + if (!_jpeg->read(jpegStream)) + error("PictDecoder::decodeCompressedQuickTime(): Could not decode JPEG data"); + + Surface *yComponent = _jpeg->getComponent(1); + Surface *uComponent = _jpeg->getComponent(2); + Surface *vComponent = _jpeg->getComponent(3); + + Surface jpegImage; + jpegImage.create(yComponent->w, yComponent->h, _pixelFormat.bytesPerPixel); + + for (uint16 i = 0; i < jpegImage.h; i++) { + for (uint16 j = 0; j < jpegImage.w; j++) { + byte r = 0, g = 0, b = 0; + YUV2RGB(*((byte *)yComponent->getBasePtr(j, i)), *((byte *)uComponent->getBasePtr(j, i)), *((byte *)vComponent->getBasePtr(j, i)), r, g, b); + if (_pixelFormat.bytesPerPixel == 2) + *((uint16 *)jpegImage.getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b); + else + *((uint32 *)jpegImage.getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b); + } + } + + image->copyFrom(jpegImage); + stream->seek(startPos + dataSize); + jpegImage.free(); + delete jpegStream; } -} // End of namespace Mohawk +} // End of namespace Graphics diff --git a/engines/mohawk/myst_pict.h b/graphics/pict.h similarity index 57% rename from engines/mohawk/myst_pict.h rename to graphics/pict.h index 90c06deee09..14fea301259 100644 --- a/engines/mohawk/myst_pict.h +++ b/graphics/pict.h @@ -23,35 +23,61 @@ * */ -#ifndef MYST_PICT_H -#define MYST_PICT_H +#ifndef GRAPHICS_PICT_H +#define GRAPHICS_PICT_H #include "common/rect.h" #include "common/scummsys.h" -#include "common/stream.h" + #include "graphics/pixelformat.h" -#include "graphics/surface.h" -#include "graphics/video/codecs/mjpeg.h" +namespace Common { + class SeekableReadStream; +} -namespace Mohawk { +namespace Graphics { -class MystPICT { +class JPEG; +class Surface; + +class PictDecoder { public: - MystPICT(Graphics::JPEGDecoder *jpegDecoder); - ~MystPICT() {} - Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); + PictDecoder(Graphics::PixelFormat pixelFormat); + ~PictDecoder(); + Surface *decodeImage(Common::SeekableReadStream *stream, byte *palette = 0); + + struct PixMap { + 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; + }; + + static PixMap readPixMap(Common::SeekableReadStream *stream, bool hasBaseAddr = true); private: - Graphics::JPEGDecoder *_jpegDecoder; Common::Rect _imageRect; - Graphics::PixelFormat _pixelFormat; + PixelFormat _pixelFormat; + JPEG *_jpeg; + byte _palette[256 * 4]; + bool _isPaletted; - void decodeDirectBitsRect(Common::SeekableReadStream *stream, Graphics::Surface *image); + void decodeDirectBitsRect(Common::SeekableReadStream *stream, Surface *image, bool hasPalette); void decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel); - void decodeCompressedQuickTime(Common::SeekableReadStream *stream, Graphics::Surface *image); + void decodeCompressedQuickTime(Common::SeekableReadStream *stream, Surface *image); }; -} // End of namespace Mohawk +} // End of namespace Graphics #endif From d49fb8f42db7b9776f1dc426ebe2c6d806ad4720 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 24 May 2010 17:21:11 +0000 Subject: [PATCH 041/249] Add support for showing the icon bar in SCI1.1 Mac. svn-id: r49196 --- engines/sci/engine/kmisc.cpp | 8 ++- engines/sci/engine/selector.cpp | 1 + engines/sci/engine/vm.h | 3 + engines/sci/graphics/maciconbar.cpp | 91 +++++++++++++++++++++++++++++ engines/sci/graphics/maciconbar.h | 55 +++++++++++++++++ engines/sci/graphics/palette.cpp | 7 ++- engines/sci/graphics/screen.cpp | 13 ++++- engines/sci/module.mk | 1 + engines/sci/resource.cpp | 23 +++++--- engines/sci/resource.h | 10 +++- engines/sci/sci.cpp | 5 ++ engines/sci/sci.h | 3 +- 12 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 engines/sci/graphics/maciconbar.cpp create mode 100644 engines/sci/graphics/maciconbar.h diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index aee1d58357a..6fc4b2fc1d8 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -32,6 +32,7 @@ #include "sci/engine/kernel.h" #include "sci/engine/gc.h" #include "sci/graphics/gui.h" +#include "sci/graphics/maciconbar.h" namespace Sci { @@ -297,9 +298,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->_macIconBar->addIcon(argv[i + 3]); + + g_sci->_macIconBar->drawIcons(); + } // Other calls seem to handle selecting/deselecting them diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp index e226c4b574f..aba134818bb 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -158,6 +158,7 @@ void Kernel::mapSelectors() { FIND_SELECTOR(scaleSignal); FIND_SELECTOR(scaleX); FIND_SELECTOR(scaleY); + FIND_SELECTOR(iconIndex); #ifdef ENABLE_SCI32 FIND_SELECTOR(data); diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 97a01051d64..f6151dfc9d2 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -197,6 +197,9 @@ struct SelectorCache { 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() Selector picture; // Used to hold the picture ID for SCI32 pictures diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp new file mode 100644 index 00000000000..b2a0b0677d8 --- /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 MacIconBar::addIcon(reg_t obj) { + _iconBarObjects.push_back(obj); +} + +void MacIconBar::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 = GET_SEL32V(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(surf->w, 320 - lastX), surf->h); + + lastX += surf->w; + surf->free(); + delete surf; + delete stream; + } + + delete pict; + delete[] pal; +} + +void MacIconBar::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/sci/graphics/maciconbar.h b/engines/sci/graphics/maciconbar.h new file mode 100644 index 00000000000..668e033f6ce --- /dev/null +++ b/engines/sci/graphics/maciconbar.h @@ -0,0 +1,55 @@ +/* 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 SCI_GRAPHICS_MACICONBAR_H +#define SCI_GRAPHICS_MACICONBAR_H + +#include "common/array.h" + +#include "sci/engine/vm.h" + +namespace Graphics { + class Surface; +} + +namespace Sci { + +class MacIconBar { +public: + MacIconBar() {} + ~MacIconBar() {} + + void addIcon(reg_t obj); + void drawIcons(); + +private: + Common::Array _iconBarObjects; + + void remapColors(Graphics::Surface *surf, byte *palette); +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index 96bdb420078..841202abced 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 { @@ -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->_macIconBar) + g_sci->_macIconBar->drawIcons(); } bool GfxPalette::kernelSetFromResource(GuiResourceId resourceId, bool force) { diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index 7ca9e335097..0e054d5a760 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 8c4d666ba7e..26ae1c16b1a 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -44,6 +44,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/resource.cpp b/engines/sci/resource.cpp index aa3b8019de0..428e66ebe23 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -445,11 +445,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) { @@ -1476,7 +1475,10 @@ 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 } }; static uint32 resTypeToMacTag(ResourceType type) { @@ -1509,6 +1511,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 +1532,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; diff --git a/engines/sci/resource.h b/engines/sci/resource.h index befda072e08..8e83ed7bf08 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -108,7 +108,13 @@ 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); @@ -127,7 +133,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; } diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index bb5124b88bf..c9f201d1f5e 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" @@ -97,6 +98,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc) DebugMan.addDebugChannel(kDebugLevelOnStartup, "OnStartup", "Enter debugger at start of game"); _gamestate = 0; + _macIconBar = 0; const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -170,6 +172,9 @@ Common::Error SciEngine::run() { else screen = new GfxScreen(_resMan, 320, 200, upscaledHires); + if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1) + _macIconBar = new MacIconBar(); + GfxPalette *palette = new GfxPalette(_resMan, screen); GfxCache *cache = new GfxCache(_resMan, screen, palette); GfxCursor *cursor = new GfxCursor(_resMan, palette, screen); diff --git a/engines/sci/sci.h b/engines/sci/sci.h index fdd10bcd040..b785b256d79 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -65,7 +65,7 @@ class GfxPalette; class GfxPorts; class GfxScreen; class SciGui; - +class MacIconBar; #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 */ + MacIconBar *_macIconBar; // Mac Icon Bar manager #ifdef ENABLE_SCI32 SciGui32 *_gui32; // GUI for SCI32 games From 3fa50583a065dc6c6f9855bdb33918af9a540b43 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Mon, 24 May 2010 17:45:00 +0000 Subject: [PATCH 042/249] SCI: leave console open for pic_visualize/undither commands - also don't use SciGui class for undither anymore svn-id: r49198 --- engines/sci/console.cpp | 18 ++++++++++++++++-- engines/sci/graphics/gui.cpp | 5 ----- engines/sci/graphics/gui.h | 2 -- engines/sci/graphics/paint16.cpp | 2 +- engines/sci/graphics/paint16.h | 2 +- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 6bd7adfdb7c..30791740d0f 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" @@ -1112,7 +1113,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) { @@ -1124,7 +1129,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) { diff --git a/engines/sci/graphics/gui.cpp b/engines/sci/graphics/gui.cpp index 29ab64ddb27..e427edd732d 100644 --- a/engines/sci/graphics/gui.cpp +++ b/engines/sci/graphics/gui.cpp @@ -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 732e1950260..7663036117f 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/paint16.cpp b/engines/sci/graphics/paint16.cpp index d0975f3d3d6..a96189dbf03 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; } diff --git a/engines/sci/graphics/paint16.h b/engines/sci/graphics/paint16.h index b18c8793875..65f9dd0d9c6 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); From f5ec3a3f741fbcfcd8e14661fff0558d45556224 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 24 May 2010 17:55:23 +0000 Subject: [PATCH 043/249] Oops, forgot to delete the icon bar. svn-id: r49199 --- engines/sci/sci.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index c9f201d1f5e..84747a25459 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -126,6 +126,7 @@ SciEngine::~SciEngine() { delete _console; delete _resMan; delete _features; + delete _macIconBar; g_sci = 0; } From 1caf98700b7319719f6db062f7409ea9dc9caa57 Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Mon, 24 May 2010 18:20:16 +0000 Subject: [PATCH 044/249] PSP: to fix the audio, I cleaned up the audio thread and changed the thread priorities. svn-id: r49200 --- backends/platform/psp/audio.cpp | 30 +++++------------------------- backends/platform/psp/audio.h | 6 ++---- backends/platform/psp/osys_psp.cpp | 2 +- backends/platform/psp/thread.h | 8 ++++---- 4 files changed, 12 insertions(+), 34 deletions(-) diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp index 2afc62d4503..bf1fb9ab417 100644 --- a/backends/platform/psp/audio.cpp +++ b/backends/platform/psp/audio.cpp @@ -79,7 +79,6 @@ bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, call _bufferSize = numOfSamples * numOfChannels * sizeof(uint16); // should be the right size to send the app _callback = callback; _userData = userData; - _emptyBuffers = NUM_BUFFERS - 1; // because we'll increase in the beginning _bufferToFill = 0; _bufferToPlay = 0; @@ -122,10 +121,7 @@ int PspAudio::thread(SceSize, void *__this) { }; // The real thread function -void PspAudio::audioThread() { - bool isPlaying = false; - int remainingSamples = 0; - +void PspAudio::audioThread() { assert(_callback); PSP_DEBUG_PRINT_FUNC("audio thread started\n"); @@ -138,29 +134,13 @@ void PspAudio::audioThread() { PSP_DEBUG_PRINT("audio thread unpaused\n"); } - // check if the audio is playing - remainingSamples = sceAudioGetChannelRestLen(_pspChannel); - if (remainingSamples < 0) { - PSP_ERROR("failed to get remaining samples\n"); - return; - } - isPlaying = remainingSamples ? true : false; - PSP_DEBUG_PRINT("remaining samples[%d]\n", remainingSamples); - if (!isPlaying) { - _emptyBuffers++; - } + PSP_DEBUG_PRINT("filling buffer[%d]\n", _bufferToFill); + _callback(_userData, _buffers[_bufferToFill], _bufferSize); // ask mixer to fill in + nextBuffer(_bufferToFill); - while (_emptyBuffers) { // we have some empty buffers - PSP_DEBUG_PRINT("filling buffer[%d]. empty buffers[%d]\n", _bufferToFill, _emptyBuffers); - _callback(_userData, _buffers[_bufferToFill], _bufferSize); // ask mixer to fill in - nextBuffer(_bufferToFill); - _emptyBuffers--; - break; - } - - PSP_DEBUG_PRINT("playing buffer[%d]. empty buffers[%d]\n", _bufferToPlay, _emptyBuffers); + PSP_DEBUG_PRINT("playing buffer[%d].\n", _bufferToPlay); playBuffer(); nextBuffer(_bufferToPlay); } // while _init diff --git a/backends/platform/psp/audio.h b/backends/platform/psp/audio.h index 97e2391319c..603f8f6bfc6 100644 --- a/backends/platform/psp/audio.h +++ b/backends/platform/psp/audio.h @@ -35,8 +35,8 @@ public: typedef void (* callbackFunc)(void *userData, byte *samples, int len); PspAudio() : _pspChannel(0), _numOfChannels(0), _numOfSamples(0), _callback(0), - _bufferToPlay(0), _bufferToFill(0), _emptyBuffers(NUM_BUFFERS), - _init(false), _paused(true), _stoppedPlayingOnceFlag(true) { + _bufferToPlay(0), _bufferToFill(0), + _init(false), _paused(true) { for (int i=0; i Date: Mon, 24 May 2010 20:50:53 +0000 Subject: [PATCH 045/249] Surface is a struct, not a class svn-id: r49201 --- engines/sci/graphics/maciconbar.h | 2 +- graphics/pict.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/sci/graphics/maciconbar.h b/engines/sci/graphics/maciconbar.h index 668e033f6ce..a9f1fe02433 100644 --- a/engines/sci/graphics/maciconbar.h +++ b/engines/sci/graphics/maciconbar.h @@ -31,7 +31,7 @@ #include "sci/engine/vm.h" namespace Graphics { - class Surface; + struct Surface; } namespace Sci { diff --git a/graphics/pict.h b/graphics/pict.h index 14fea301259..12681f61284 100644 --- a/graphics/pict.h +++ b/graphics/pict.h @@ -38,7 +38,7 @@ namespace Common { namespace Graphics { class JPEG; -class Surface; +struct Surface; class PictDecoder { public: From 830d17ed318d62a01aa1ec24ec79a7439586eb5e Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Mon, 24 May 2010 21:47:06 +0000 Subject: [PATCH 046/249] SCI: renaming MacIconBar to GfxMacIconBar svn-id: r49202 --- engines/sci/engine/kmisc.cpp | 4 ++-- engines/sci/graphics/maciconbar.cpp | 6 +++--- engines/sci/graphics/maciconbar.h | 6 +++--- engines/sci/graphics/palette.cpp | 4 ++-- engines/sci/sci.cpp | 4 ++-- engines/sci/sci.h | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 6fc4b2fc1d8..c05a2bc57b7 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -300,9 +300,9 @@ reg_t kIconBar(EngineState *s, int argc, reg_t *argv) { if (argv[0].toUint16() == 4 && argv[1].toUint16() == 0) { for (int i = 0; i < argv[2].toUint16(); i++) - g_sci->_macIconBar->addIcon(argv[i + 3]); + g_sci->_gfxMacIconBar->addIcon(argv[i + 3]); - g_sci->_macIconBar->drawIcons(); + g_sci->_gfxMacIconBar->drawIcons(); } // Other calls seem to handle selecting/deselecting them diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp index b2a0b0677d8..2904bda22b8 100644 --- a/engines/sci/graphics/maciconbar.cpp +++ b/engines/sci/graphics/maciconbar.cpp @@ -36,11 +36,11 @@ namespace Sci { -void MacIconBar::addIcon(reg_t obj) { +void GfxMacIconBar::addIcon(reg_t obj) { _iconBarObjects.push_back(obj); } -void MacIconBar::drawIcons() { +void GfxMacIconBar::drawIcons() { // Draw the icons to the bottom of the screen byte *pal = new byte[256 * 4]; @@ -69,7 +69,7 @@ void MacIconBar::drawIcons() { delete[] pal; } -void MacIconBar::remapColors(Graphics::Surface *surf, byte *palette) { +void GfxMacIconBar::remapColors(Graphics::Surface *surf, byte *palette) { byte *pixels = (byte *)surf->pixels; // Remap to the screen palette diff --git a/engines/sci/graphics/maciconbar.h b/engines/sci/graphics/maciconbar.h index a9f1fe02433..71e65fcb408 100644 --- a/engines/sci/graphics/maciconbar.h +++ b/engines/sci/graphics/maciconbar.h @@ -36,10 +36,10 @@ namespace Graphics { namespace Sci { -class MacIconBar { +class GfxMacIconBar { public: - MacIconBar() {} - ~MacIconBar() {} + GfxMacIconBar() {} + ~GfxMacIconBar() {} void addIcon(reg_t obj); void drawIcons(); diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index 841202abced..ab968566741 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -314,8 +314,8 @@ void GfxPalette::setOnScreen() { _screen->setPalette(&_sysPalette); // Redraw the Mac SCI1.1 Icon bar every palette change - if (g_sci->_macIconBar) - g_sci->_macIconBar->drawIcons(); + if (g_sci->_gfxMacIconBar) + g_sci->_gfxMacIconBar->drawIcons(); } bool GfxPalette::kernelSetFromResource(GuiResourceId resourceId, bool force) { diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 84747a25459..fc70dc7758d 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -98,7 +98,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc) DebugMan.addDebugChannel(kDebugLevelOnStartup, "OnStartup", "Enter debugger at start of game"); _gamestate = 0; - _macIconBar = 0; + _gfxMacIconBar = 0; const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -174,7 +174,7 @@ Common::Error SciEngine::run() { screen = new GfxScreen(_resMan, 320, 200, upscaledHires); if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1) - _macIconBar = new MacIconBar(); + _gfxMacIconBar = new GfxMacIconBar(); GfxPalette *palette = new GfxPalette(_resMan, screen); GfxCache *cache = new GfxCache(_resMan, screen, palette); diff --git a/engines/sci/sci.h b/engines/sci/sci.h index b785b256d79..685f05e6857 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -65,7 +65,7 @@ class GfxPalette; class GfxPorts; class GfxScreen; class SciGui; -class MacIconBar; +class GfxMacIconBar; #ifdef ENABLE_SCI32 class SciGui32; @@ -206,7 +206,7 @@ public: GfxPorts *_gfxPorts; // Port managment for 16-bit gfx GfxScreen *_gfxScreen; SciGui *_gui; /* Currently active Gui */ - MacIconBar *_macIconBar; // Mac Icon Bar manager + GfxMacIconBar *_gfxMacIconBar; // Mac Icon Bar manager #ifdef ENABLE_SCI32 SciGui32 *_gui32; // GUI for SCI32 games From 58a7dbe7214c64ce77920e7e63dd9be445ebd805 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Mon, 24 May 2010 21:51:45 +0000 Subject: [PATCH 047/249] SCI: forgot one rename in r49202 - MSVC, why? svn-id: r49203 --- engines/sci/sci.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index fc70dc7758d..39f117475bd 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -126,7 +126,7 @@ SciEngine::~SciEngine() { delete _console; delete _resMan; delete _features; - delete _macIconBar; + delete _gfxMacIconBar; g_sci = 0; } From ab540af9f815183fb3bb087e0a7dcab9e62cd847 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Tue, 25 May 2010 02:35:50 +0000 Subject: [PATCH 048/249] Fix a regression with rewinding in QuickTime videos (looping works in Riven again) and some minor cleanup. svn-id: r49206 --- graphics/video/qt_decoder.cpp | 11 +++-------- graphics/video/qt_decoder.h | 1 - 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/graphics/video/qt_decoder.cpp b/graphics/video/qt_decoder.cpp index 5e507720242..a2d088758da 100644 --- a/graphics/video/qt_decoder.cpp +++ b/graphics/video/qt_decoder.cpp @@ -146,9 +146,8 @@ PixelFormat QuickTimeDecoder::getPixelFormat() const { } void QuickTimeDecoder::rewind() { - delete _videoCodec; _videoCodec = NULL; - _curFrame = -1; - _startTime = _nextFrameStartTime = 0; + VideoDecoder::reset(); + _nextFrameStartTime = 0; // Restart the audio too stopAudio(); @@ -243,11 +242,7 @@ Surface *QuickTimeDecoder::scaleSurface(Surface *frame) { } bool QuickTimeDecoder::endOfVideo() const { - return (!_audStream || _audStream->endOfData()) && (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1); -} - -bool QuickTimeDecoder::needsUpdate() const { - return !endOfVideo() && getTimeToNextFrame() == 0; + return (!_audStream || _audStream->endOfData()) && (!_videoCodec || VideoDecoder::endOfVideo()); } uint32 QuickTimeDecoder::getElapsedTime() const { diff --git a/graphics/video/qt_decoder.h b/graphics/video/qt_decoder.h index 545866f9e56..6d724642587 100644 --- a/graphics/video/qt_decoder.h +++ b/graphics/video/qt_decoder.h @@ -112,7 +112,6 @@ public: bool isVideoLoaded() const { return _fd != 0; } Surface *decodeNextFrame(); - bool needsUpdate() const; bool endOfVideo() const; uint32 getElapsedTime() const; uint32 getTimeToNextFrame() const; From 4a8841202a25d48df190d9479bda98026f9c14d5 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Tue, 25 May 2010 03:46:28 +0000 Subject: [PATCH 049/249] Implement *scpbtn and *_domecheck. The domes can now be opened/closed (not using the sliders). svn-id: r49208 --- engines/mohawk/riven_external.cpp | 47 +++++++++++++++++++++++-------- engines/mohawk/riven_external.h | 2 ++ engines/mohawk/video.cpp | 26 +++++++++++++++-- engines/mohawk/video.h | 5 ++++ 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 8b1ff45a66e..184761318ff 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -213,16 +213,39 @@ void RivenExternal::runEndGame(uint16 video) { _vm->_gameOver = true; } +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; +} + // ------------------------------------------------------------------------------------ // aspit (Main Menu, Books, Setup) external commands // ------------------------------------------------------------------------------------ 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); } @@ -627,11 +650,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 +746,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 +1001,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 +1281,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 +1480,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 8270a008547..14bb51340cf 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/video.cpp b/engines/mohawk/video.cpp index adca805763e..99fa8b23f02 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -89,7 +89,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 +120,8 @@ void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) { _vm->_system->delayMillis(10); } - _videoStreams[videoHandle]->close(); - _videoStreams.clear(); + delete _videoStreams[videoHandle].video; + memset(&_videoStreams[videoHandle], 0, sizeof(VideoEntry)); } void VideoManager::playBackgroundMovie(Common::String filename, int16 x, int16 y, bool loop) { @@ -374,4 +374,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.h b/engines/mohawk/video.h index 8cfe1527fb5..5620a5412a7 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -92,6 +92,11 @@ public: // Riven-related variables Common::Array _mlstRecords; + // Handle functions + VideoHandle findVideoHandle(uint16 id); + int32 getCurFrame(const VideoHandle &handle); + uint32 getFrameCount(const VideoHandle &handle); + private: MohawkEngine *_vm; From a83aafab545cbfdf47e5f724a856d1cbbb7914d0 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Tue, 25 May 2010 10:46:56 +0000 Subject: [PATCH 050/249] Changed the font system to allow for multiple fonts to be loaded simultaneously svn-id: r49209 --- engines/m4/converse.cpp | 8 +++--- engines/m4/dialogs.cpp | 26 +++++++++--------- engines/m4/font.cpp | 57 ++++++++++++++++++++++++++------------- engines/m4/font.h | 48 ++++++++++++++++++++++++--------- engines/m4/gui.cpp | 30 ++++++++++----------- engines/m4/m4.cpp | 8 +++--- engines/m4/m4.h | 2 +- engines/m4/mads_anim.cpp | 16 +++++------ engines/m4/mads_menus.cpp | 46 +++++++++++++++---------------- engines/m4/mads_scene.cpp | 6 ++--- engines/m4/mads_views.cpp | 15 +++++------ 11 files changed, 151 insertions(+), 111 deletions(-) diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp index 746ced5d112..11bc1658112 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 3af94af262b..a7104537f52 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 f8dec654120..4afa158976f 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 e64f80b70dc..ca47848c615 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 _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/gui.cpp b/engines/m4/gui.cpp index 8f949de9c5a..8665b4e767b 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 897fb468cd3..2024138f67f 100644 --- a/engines/m4/m4.cpp +++ b/engines/m4/m4.cpp @@ -170,7 +170,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); @@ -554,9 +554,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); diff --git a/engines/m4/m4.h b/engines/m4/m4.h index 1f34bd36852..23204f22289 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; diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp index 954916700c4..24a041e04d5 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); } diff --git a/engines/m4/mads_menus.cpp b/engines/m4/mads_menus.cpp index da8ac4230e9..ff12b699645 100644 --- a/engines/m4/mads_menus.cpp +++ b/engines/m4/mads_menus.cpp @@ -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 1b8e44b5815..99c1249fde0 100644 --- a/engines/m4/mads_scene.cpp +++ b/engines/m4/mads_scene.cpp @@ -289,12 +289,12 @@ 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*** diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp index 7a71509041b..19cf9ceb135 100644 --- a/engines/m4/mads_views.cpp +++ b/engines/m4/mads_views.cpp @@ -291,8 +291,7 @@ void MadsTextDisplay::setDirtyAreas2() { void MadsTextDisplay::draw(View *view) { 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].spacing); @@ -1204,13 +1203,13 @@ MadsInterfaceView::~MadsInterfaceView() { void MadsInterfaceView::setFontMode(InterfaceFontMode newMode) { switch (newMode) { case ITEM_NORMAL: - _vm->_font->setColors(4, 4, 0xff); + _vm->_font->current()->setColours(4, 4, 0xff); break; case ITEM_HIGHLIGHTED: - _vm->_font->setColors(5, 5, 0xff); + _vm->_font->current()->setColours(5, 5, 0xff); break; case ITEM_SELECTED: - _vm->_font->setColors(6, 6, 0xff); + _vm->_font->current()->setColours(6, 6, 0xff); break; } } @@ -1300,7 +1299,7 @@ void MadsInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) { // Display the verb const Common::Rect r(_screenObjects[actionIndex]); - _vm->_font->writeString(destSurface, buffer, r.left, r.top, r.width(), 0); + _vm->_font->current()->writeString(destSurface, buffer, r.left, r.top, r.width(), 0); } } @@ -1335,7 +1334,7 @@ void MadsInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) { else setFontMode(ITEM_NORMAL); // Write out it's description - _vm->_font->writeString(destSurface, buffer, r.left, r.top, r.width(), 0); + _vm->_font->current()->writeString(destSurface, buffer, r.left, r.top, r.width(), 0); } // Handle the display of any currently selected object @@ -1365,7 +1364,7 @@ void MadsInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) { // 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); + _vm->_font->current()->writeString(destSurface, buffer, r.left, r.top, r.width(), 0); } } } From 7bbbaf7d8cc382dd3c6dfc6dcaacf9c902523525 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 25 May 2010 11:35:16 +0000 Subject: [PATCH 051/249] Patch #3006178: "rjp1: calculate sample length correctly" Fixes bug #3001110: "FOTAQ Amiga: crashes reporting assertion failure" Added a NEWS entry to the patch. svn-id: r49210 --- NEWS | 1 + sound/mods/rjp1.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 5d48d8e4e42..9ab98dc4e51 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ For a more comprehensive changelog for the latest experimental SVN code, see: General: - Switched to the "fast" DOSBox OPL emulator. + - Fixed a crash in the rjp1 player code affecting the FOTAQ Amiga version. 1.1.2 (????-??-??) Broken Sword 2 diff --git a/sound/mods/rjp1.cpp b/sound/mods/rjp1.cpp index fc1b49e9e93..be376d61a46 100644 --- a/sound/mods/rjp1.cpp +++ b/sound/mods/rjp1.cpp @@ -422,7 +422,7 @@ void Rjp1::setupNote(Rjp1Channel *channel, int16 period) { channel->envelopeMode = 4; channel->data = channel->waveData; channel->pos = READ_BE_UINT16(note + 16); - channel->len = READ_BE_UINT16(note + 18); + channel->len = channel->pos + READ_BE_UINT16(note + 18); channel->setupNewNote = true; } } From 961a64a9f834a833e9ec7c060e8f81dddd91a3a3 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Tue, 25 May 2010 11:54:18 +0000 Subject: [PATCH 052/249] Bugfix to allow timed text to display in the correct colours svn-id: r49211 --- engines/m4/mads_logic.cpp | 8 +++++--- engines/m4/mads_scene.cpp | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/engines/m4/mads_logic.cpp b/engines/m4/mads_logic.cpp index ee65d3be5ca..4a361d92d2b 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() { @@ -169,7 +169,9 @@ void MadsSceneLogic::setupScene() { // sub_1e754(animName, 3); - getSceneSpriteSet(); + if ((_sceneNumber >= 101) && (_sceneNumber <= 112)) + getSceneSpriteSet(); + getAnimName(); } diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp index 99c1249fde0..60e480e6fb0 100644 --- a/engines/m4/mads_scene.cpp +++ b/engines/m4/mads_scene.cpp @@ -78,7 +78,7 @@ 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); From 5317b8195d252942f084e3120809ab496411e963 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Tue, 25 May 2010 12:04:32 +0000 Subject: [PATCH 053/249] SCI: sci1.1 changed priority to 15, when adding to picture - fixes title in island of dr. brain intro svn-id: r49212 --- engines/sci/graphics/picture.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index 74f651a88ac..e08547c4d9b 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -69,6 +69,8 @@ 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 + if (_addToFlag) + _priority = 15; drawSci11Vga(); break; #ifdef ENABLE_SCI32 @@ -108,9 +110,8 @@ void GfxPicture::drawSci11Vga() { _palette->set(&palette, true); // display Cel-data - if (has_cel) { + if (has_cel) drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, false); - } // process vector data drawVectorData(inbuffer + vector_dataPos, vector_size); From 2502038e73e19dd5cf819834369fffa6e86caa7d Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Tue, 25 May 2010 12:53:35 +0000 Subject: [PATCH 054/249] SCI: sci1.1 uses hardcoded white for picture cel data instead of the value specified in header - fixes pixel glitches in island of dr. brain title, sq4 title and qfg3 room during intro svn-id: r49213 --- engines/sci/graphics/picture.cpp | 19 ++++++++++++------- engines/sci/graphics/picture.h | 8 +++++++- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index e08547c4d9b..f186e095453 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -111,7 +111,7 @@ void GfxPicture::drawSci11Vga() { // display Cel-data if (has_cel) - drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, false); + drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, SCI_PICTURE_CELTYPE_SCI11); // process vector data drawVectorData(inbuffer + vector_dataPos, vector_size); @@ -156,14 +156,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, SCI_PICTURE_CELTYPE_SCI32); 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, int celType) { byte *celBitmap = NULL; byte *ptr = NULL; byte *headerPtr = inbuffer + headerPos; @@ -180,11 +180,16 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos int pixelNr, pixelCount; #ifdef ENABLE_SCI32 - if (!hasSci32Header) { + if (celType != SCI_PICTURE_CELTYPE_SCI32) { #endif displaceX = (signed char)headerPtr[4]; displaceY = (unsigned char)headerPtr[5]; - clearColor = headerPtr[6]; + if (celType == SCI_PICTURE_CELTYPE_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?!? @@ -586,7 +591,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, SCI_PICTURE_CELTYPE_REGULAR); curPos += size; break; case PIC_OPX_EGA_SET_PRIORITY_TABLE: @@ -628,7 +633,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, SCI_PICTURE_CELTYPE_REGULAR); 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 3374c33b52d..ba6052b059c 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_CELTYPE_REGULAR = 0, + SCI_PICTURE_CELTYPE_SCI11 = 1, + SCI_PICTURE_CELTYPE_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, int celType); void drawVectorData(byte *data, int size); bool vectorIsNonOpcode(byte pixel); void vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y); From 849cfe4f0e5793caf648cb8fb030698c88c622f5 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Tue, 25 May 2010 15:38:30 +0000 Subject: [PATCH 055/249] SCI: dont lock mutex in pauseAll(), isn't needed anyway - fixes deadlock in sq4 svn-id: r49214 --- engines/sci/sound/music.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 86c7669df9e..a623c0b4d23 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -115,8 +115,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); From 5f3952e5787079d8acd3476d3b7f0d67116b5d94 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Tue, 25 May 2010 18:11:14 +0000 Subject: [PATCH 056/249] Fix a Myst regression: not a good idea to use memset on a Common::String :) svn-id: r49215 --- engines/mohawk/video.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 99fa8b23f02..3a86e0323bc 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -121,7 +121,9 @@ void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) { } delete _videoStreams[videoHandle].video; - memset(&_videoStreams[videoHandle], 0, sizeof(VideoEntry)); + _videoStreams[videoHandle].video = 0; + _videoStreams[videoHandle].id = 0; + _videoStreams[videoHandle].filename = ""; } void VideoManager::playBackgroundMovie(Common::String filename, int16 x, int16 y, bool loop) { @@ -152,8 +154,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 = ""; continue; } } From aa8c6377a5cb8c51717f6bcf1ffc950c6c837021 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Tue, 25 May 2010 18:45:25 +0000 Subject: [PATCH 057/249] SCI: error out on pattern opcodes inside vector data when drawing pictures in sci1.1+, also adding workaround for garbage data inside picture 381 in sq4 svn-id: r49216 --- engines/sci/graphics/picture.cpp | 32 +++++++++++++++++++++++++------- engines/sci/graphics/picture.h | 9 +++++---- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index f186e095453..73eb9200ec9 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -69,17 +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); } } @@ -111,7 +114,7 @@ void GfxPicture::drawSci11Vga() { // display Cel-data if (has_cel) - drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, SCI_PICTURE_CELTYPE_SCI11); + drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0); // process vector data drawVectorData(inbuffer + vector_dataPos, vector_size); @@ -156,14 +159,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, SCI_PICTURE_CELTYPE_SCI32); + 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, int celType) { +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; @@ -180,11 +183,11 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos int pixelNr, pixelCount; #ifdef ENABLE_SCI32 - if (celType != SCI_PICTURE_CELTYPE_SCI32) { + if (_resourceType != SCI_PICTURE_TYPE_SCI32) { #endif displaceX = (signed char)headerPtr[4]; displaceY = (unsigned char)headerPtr[5]; - if (celType == SCI_PICTURE_CELTYPE_SCI11) { + if (_resourceType == SCI_PICTURE_TYPE_SCI11) { // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise clearColor = _screen->getColorWhite(); } else { @@ -525,9 +528,20 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { break; case PIC_OP_SET_PATTERN: + if (_resourceType >= SCI_PICTURE_TYPE_SCI11) { + if (strcmp(g_sci->getGameID(), "sq4") == 0) { + // WORKAROUND: For SQ4 / picture 381 handle this like a terminator + // This picture includes garbage data, first a set pattern w/o parameter and then short pattern + if (_resourceId == 381) + return; + } + 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); @@ -538,6 +552,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); @@ -548,6 +564,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); @@ -591,7 +609,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, SCI_PICTURE_CELTYPE_REGULAR); + drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y); curPos += size; break; case PIC_OPX_EGA_SET_PRIORITY_TABLE: @@ -633,7 +651,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, SCI_PICTURE_CELTYPE_REGULAR); + 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 ba6052b059c..5a86539b373 100644 --- a/engines/sci/graphics/picture.h +++ b/engines/sci/graphics/picture.h @@ -33,9 +33,9 @@ namespace Sci { #define SCI_PATTERN_CODE_PENSIZE 0x07 enum { - SCI_PICTURE_CELTYPE_REGULAR = 0, - SCI_PICTURE_CELTYPE_SCI11 = 1, - SCI_PICTURE_CELTYPE_SCI32 = 2 + SCI_PICTURE_TYPE_REGULAR = 0, + SCI_PICTURE_TYPE_SCI11 = 1, + SCI_PICTURE_TYPE_SCI32 = 2 }; class GfxPorts; @@ -63,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, int celType); + 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); @@ -86,6 +86,7 @@ private: int16 _resourceId; Resource *_resource; + int _resourceType; int16 _animationNr; bool _mirroredFlag; From 71436c5a8643710a1dac3a489af03e5ca2729261 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Tue, 25 May 2010 18:48:50 +0000 Subject: [PATCH 058/249] SCI: adding comment about error() on pattern opcodes sci1.1+ svn-id: r49217 --- engines/sci/graphics/picture.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index 73eb9200ec9..fad738aa3a1 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -527,6 +527,8 @@ 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) { From b8df22646b6be2a3d0c10e1df2a6122f9a0d0e26 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Tue, 25 May 2010 20:47:48 +0000 Subject: [PATCH 059/249] Patch #2959341: Minor update to SCUMM debugger command 'passcode' svn-id: r49221 --- engines/scumm/debugger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp index a0975839d6d..ea29e25a1f3 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 '\n"); + DebugPrintf("Current Passcode is %d \nUse 'passcode '\n",_vm->_scummVars[411]); return true; } return false; From cd5e90f298098fa44299bcf054fffeada9da2996 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 26 May 2010 03:43:21 +0000 Subject: [PATCH 060/249] Implement QuickTime playback for SCI1.1 Mac. The 'Halfdome' and 'KQ6Movie' videos now play. However, they require multiple edit list support to look completely correct. svn-id: r49224 --- engines/sci/engine/kgraphics.cpp | 39 ++++++++++++++++++++++++-------- graphics/video/qt_decoder.cpp | 2 +- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index abc7efd7438..aaf361d85ca 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" @@ -1080,11 +1082,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 +1097,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 +1123,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 +1155,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 +1177,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/graphics/video/qt_decoder.cpp b/graphics/video/qt_decoder.cpp index a2d088758da..1628e0f308d 100644 --- a/graphics/video/qt_decoder.cpp +++ b/graphics/video/qt_decoder.cpp @@ -427,7 +427,7 @@ int QuickTimeDecoder::readDefault(MOVatom atom) { // Some QuickTime videos with resource forks have mdat chunks // that are of size 0. Adjust it so it's the correct size. - if (a.size == 0) + if (a.type == MKID_BE('mdat') && a.size == 0) a.size = _fd->size(); } From 2c6ea824ec6fcccc1bef48fac479ce0d47569520 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 06:44:07 +0000 Subject: [PATCH 061/249] Reverted commit #49107 - it is pointless to keep silencing this warning (which is, in fact, correct) svn-id: r49225 --- tools/create_msvc/create_msvc.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/create_msvc/create_msvc.cpp b/tools/create_msvc/create_msvc.cpp index a2636dab21a..f4189712394 100644 --- a/tools/create_msvc/create_msvc.cpp +++ b/tools/create_msvc/create_msvc.cpp @@ -511,8 +511,6 @@ int main(int argc, char *argv[]) { // 4103 (alignment changed after including header, may be due to missing #pragma pack(pop)) // used by pack-start / pack-end // - // 4121 (alignment of a member was sensitive to packing) - // // 4127 (conditional expression is constant) // used in a lot of engines // @@ -566,7 +564,6 @@ int main(int argc, char *argv[]) { projectWarnings["lure"] = "4189;4355"; projectWarnings["kyra"] = "4355"; projectWarnings["m4"] = "4355"; - projectWarnings["mohawk"] = "4121"; ProjectProvider *provider = NULL; From ad9772fac6dcd3d462053bb80ebe54a012990a24 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 06:45:57 +0000 Subject: [PATCH 062/249] Properly fixed MSVC warning C4121 (alignment of a member was sensitive to packing) svn-id: r49226 --- graphics/video/qt_decoder.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/graphics/video/qt_decoder.h b/graphics/video/qt_decoder.h index 6d724642587..659ad855e47 100644 --- a/graphics/video/qt_decoder.h +++ b/graphics/video/qt_decoder.h @@ -136,10 +136,14 @@ protected: uint32 size; }; +#include "common/pack-start.h" // START STRUCT PACKING + struct ParseTable { uint32 type; int (QuickTimeDecoder::*func)(MOVatom atom); - }; + } PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING struct MOVstts { int count; From 60dd3106885b9784af15cb96122d28a5f0bf33f1 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 06:53:08 +0000 Subject: [PATCH 063/249] Cleanup svn-id: r49227 --- engines/sci/engine/savegame.cpp | 17 ++++++----------- engines/sci/resource.cpp | 11 +++++------ 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 8dc06dab018..ff51f4015ca 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -849,24 +849,19 @@ void SegManager::reconstructScripts(EngineState *s) { 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; + it->_value._baseMethod = (uint16 *)(scr->_buf + READ_LE_UINT16( data + 6 )); + it->_value._baseVars = (uint16 *)(scr->_buf + READ_LE_UINT16( data + 4 )); } else { int funct_area = READ_LE_UINT16(data + SCRIPT_FUNCTAREAPTR_OFFSET); - Object *_baseObj; + Object *baseObj = s->_segMan->getObject(it->_value.getSpeciesSelector()); - _baseObj = s->_segMan->getObject(it->_value.getSpeciesSelector()); - - if (!_baseObj) { + 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; + it->_value.setVarCount(baseObj->getVarCount()); + it->_value._baseObj = baseObj->_baseObj; it->_value._baseMethod = (uint16 *)(data + funct_area); it->_value._baseVars = (uint16 *)(data + it->_value.getVarCount() * 2 + SCRIPT_SELECTOR_OFFSET); diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 428e66ebe23..57a4fbc751b 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -2343,6 +2343,7 @@ Common::String ResourceManager::findSierraGameId() { // In SCI0-SCI1, the heap is embedded in the script. In SCI1.1+, it's separated Resource *heap = 0; byte *seeker = 0; + Common::String sierraId; // Seek to the name selector of the first export if (getSciVersion() < SCI_VERSION_1_1) { @@ -2357,14 +2358,12 @@ Common::String ResourceManager::findSierraGameId() { seeker = heap->data + READ_UINT16(heap->data + READ_UINT16(exportPtr) + nameSelector * 2); } - char sierraId[20]; - int i = 0; - byte curChar = 0; + char c = 0; do { - curChar = *(seeker + i); - sierraId[i++] = curChar; - } while (curChar != 0); + c = *(seeker++); + sierraId += c; + } while (c); return sierraId; } From 1c0bbb10cbb20b8dd0bdc1cb748bb5ec9e538b42 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 08:27:24 +0000 Subject: [PATCH 064/249] More work on controlling access to members of the Object class: - Moved the code for initializing the object class, species and base object inside the Object class - Made propertyOffsetToId() a method of the Object class - Made relocateObject() a method of the Object class - The Object getVariable() method now returns a reference to the requested variable Only SegManager::reconstructScripts() is left needing direct access to the members of the Object class svn-id: r49228 --- engines/sci/engine/script.cpp | 17 +---- engines/sci/engine/scriptdebug.cpp | 40 ++--------- engines/sci/engine/segment.cpp | 104 +++++++++++++++++++++++++++-- engines/sci/engine/segment.h | 36 ++++------ engines/sci/engine/vm.cpp | 5 +- 5 files changed, 120 insertions(+), 82 deletions(-) diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index e9b1ce3f28f..aa3fbc995a1 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -318,8 +318,6 @@ int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int s 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) { int objType; uint32 objLength = 0; @@ -429,21 +427,10 @@ 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 diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 4b60626b2e0..608260ec509 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); @@ -224,10 +193,11 @@ 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 ((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)); + Object *obj = s->_segMan->getObject(scriptState.xs->objp); + if (!obj) + warning("Attempted to reference on non-object at %04x:%04x", PRINT_REG(scriptState.xs->objp)); + else + printf(" (%s)", selector_name(s, obj->propertyOffsetToId(s->_segMan, scr[pos.offset + 1]))); } } diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index ab1a68d1655..0c468a3cc25 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -247,10 +247,6 @@ int Script::relocateLocal(SegmentId segment, int location) { return 0; // No hands, no cookies } -int Script::relocateObject(Object &obj, SegmentId segment, int location) { - return relocateBlock(obj._variables, obj.getPos().offset, segment, location); -} - void Script::scriptAddCodeBlock(reg_t location) { CodeBlock cb; cb.pos = location; @@ -276,7 +272,7 @@ void Script::scriptRelocate(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; } @@ -321,7 +317,7 @@ 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; } @@ -673,6 +669,27 @@ void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback //-------------------- object ---------------------------- +void Object::init(byte *buf, reg_t obj_pos) { + byte *data = (byte *)(buf + obj_pos.offset); + _baseObj = data; + _pos = obj_pos; + + 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); + } + + for (uint i = 0; i < _variables.size(); i++) + _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2))); +} + Object *Object::getClass(SegManager *segMan) { return isClass() ? this : segMan->getObject(getSuperClassSelector()); } @@ -698,6 +715,81 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) { return -1; // Failed } +bool Object::relocate(SegmentId segment, int location, size_t scriptSize) { + int rel = location - getPos().offset; + + if (rel < 0) + return false; + + uint idx = rel >> 1; + + if (idx >= _variables.size()) + return false; + + if (rel & 1) { + warning("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, getPos().offset); + return false; + } + _variables[idx].segment = segment; // Perform relocation + if (getSciVersion() >= SCI_VERSION_1_1) + _variables[idx].offset += scriptSize; + + return true; +} + +int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) { + 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) { + byte *selectoroffset = ((byte *)(_baseObj)) + SCRIPT_SELECTOR_OFFSET + selectors * 2; + return READ_SCI11ENDIAN_UINT16(selectoroffset + propertyOffset); + } else { + Object *obj = this; + if (!(getInfoSelector().offset & SCRIPT_INFO_CLASS)) + obj = segMan->getObject(getSuperClassSelector()); + + return READ_SCI11ENDIAN_UINT16((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) { + Object *baseObj = segMan->getObject(getSpeciesSelector()); + + if (baseObj) { + setVarCount(baseObj->getVarCount()); + // Copy base from species class, as we need its selector IDs + _baseObj = baseObj->_baseObj; + initSuperClass(segMan, addr); + return true; + } + + return false; +} + //-------------------- dynamic memory -------------------- reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) { diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 1089ada4755..876a081295a 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -270,28 +270,9 @@ public: void setVarCount(uint size) { _variables.resize(size); } uint getVarCount() { return _variables.size(); } - void init(byte *buf, reg_t obj_pos) { - byte *data = (byte *)(buf + obj_pos.offset); - _baseObj = data; - _pos = obj_pos; + void init(byte *buf, reg_t obj_pos); - 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); - } - - for (uint i = 0; i < _variables.size(); i++) - _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2))); - } - - reg_t getVariable(uint var) { return _variables[var]; } + reg_t &getVariable(uint var) { return _variables[var]; } uint16 getMethodCount() { return _methodCount; } reg_t getPos() { return _pos; } @@ -304,13 +285,23 @@ public: _baseVars = obj ? obj->_baseVars : NULL; } + bool relocate(SegmentId segment, int location, size_t scriptSize); + + int propertyOffsetToId(SegManager *segMan, int propertyOffset); + + void initSpecies(SegManager *segMan, reg_t addr); + void initSuperClass(SegManager *segMan, reg_t addr); + bool initBaseObject(SegManager *segMan, reg_t addr); + // TODO: make private - Common::Array _variables; + // Only SegManager::reconstructScripts() is left needing direct access to these +public: 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 */ private: + Common::Array _variables; uint16 _methodCount; int _flags; uint16 _offset; @@ -414,7 +405,6 @@ public: private: int relocateLocal(SegmentId segment, int location); int relocateBlock(Common::Array &block, int block_location, SegmentId segment, int location); - int relocateObject(Object &obj, SegmentId segment, int location); public: // script lock operations diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 7b6763f8f23..d37628da200 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -120,7 +120,7 @@ static reg_t &validate_property(Object *obj, int index) { return dummyReg; } - return obj->_variables[index]; + return obj->getVariable(index); } static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) { @@ -1758,8 +1758,7 @@ void quit_vm() { reg_t* ObjVarRef::getPointer(SegManager *segMan) const { Object *o = segMan->getObject(obj); - if (!o) return 0; - return &(o->_variables[varindex]); + return o ? &o->getVariable(varindex) : 0; } reg_t* ExecStack::getVarPointer(SegManager *segMan) const { From eca8c35cfc6b183800abb1d34c06e787c1b18477 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Wed, 26 May 2010 08:32:32 +0000 Subject: [PATCH 065/249] Gave proper names to each flag in the message flag set svn-id: r49229 --- engines/m4/mads_logic.cpp | 6 ++-- engines/m4/mads_views.cpp | 61 ++++++++++++++++++++------------------- engines/m4/mads_views.h | 16 +++++----- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/engines/m4/mads_logic.cpp b/engines/m4/mads_logic.cpp index 4a361d92d2b..00ed1463996 100644 --- a/engines/m4/mads_logic.cpp +++ b/engines/m4/mads_logic.cpp @@ -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) { diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp index 19cf9ceb135..9e16e2a76ed 100644 --- a/engines/m4/mads_views.cpp +++ b/engines/m4/mads_views.cpp @@ -340,13 +340,13 @@ 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"); @@ -361,28 +361,28 @@ 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 numTicks, 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].numTicks = numTicks; _entries[msgIndex].frameTimer2 = _madsVm->_currentTimer; @@ -391,7 +391,7 @@ void MadsKernelMessageList::unk1(int msgIndex, int numTicks, int v2) { _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,7 +399,7 @@ void MadsKernelMessageList::unk1(int msgIndex, int numTicks, 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; } } @@ -408,9 +408,9 @@ void MadsKernelMessageList::remove(int 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) @@ -441,26 +441,26 @@ void MadsKernelMessageList::processText(int msgIndex) { uint32 currentTimer = _madsVm->_currentTimer; bool flag = false; - if ((msg.flags & KMSG_40) != 0) { + if ((msg.flags & KMSG_EXPIRE) != 0) { _owner._textDisplay.expire(msg.textDisplayIndex); msg.flags &= !KMSG_ACTIVE; return; } - if ((msg.flags & KMSG_8) == 0) { + if ((msg.flags & KMSG_SCROLL) == 0) { msg.timeout -= 3; } - if (msg.flags & KMSG_4) { + 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_40; - if (msg.field_1C != 0) { - _owner._abortTimers = msg.field_1C; + msg.flags |= KMSG_EXPIRE; + if (msg.abortTimers != 0) { + _owner._abortTimers = msg.abortTimers; _owner._abortTimersMode = msg.abortMode; if (_owner._abortTimersMode != ABORTMODE_1) { @@ -473,9 +473,9 @@ void MadsKernelMessageList::processText(int msgIndex) { msg.frameTimer = currentTimer + 3; int x1 = 0, y1 = 0; - if (msg.flags & KMSG_4) { + if (msg.flags & KMSG_SEQ_ENTRY) { MadsSequenceEntry &seqEntry = _owner._sequenceList[msg.sequenceIndex]; - if (seqEntry.field_12) { + if (!seqEntry.nonFixed) { SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(seqEntry.spriteListIndex); M4Sprite *frame = spriteSet.getFrame(seqEntry.frameIndex - 1); x1 = frame->bounds().left; @@ -486,7 +486,7 @@ void MadsKernelMessageList::processText(int msgIndex) { } } - if (msg.flags & KMSG_2) { + if (msg.flags & KMSG_OWNER_TIMEOUT) { if (word_8469E != 0) { // TODO: Figure out various flags } else { @@ -498,7 +498,7 @@ void MadsKernelMessageList::processText(int msgIndex) { x1 += msg.position.x; y1 += msg.position.y; - if ((msg.flags & KMSG_8) && (msg.frameTimer >= currentTimer)) { + if ((msg.flags & KMSG_SCROLL) && (msg.frameTimer >= currentTimer)) { msg.msg[msg.msgOffset] = msg.asciiChar; char *msgP = &msg.msg[++msg.msgOffset]; *msgP = msg.asciiChar2; @@ -507,9 +507,10 @@ void MadsKernelMessageList::processText(int msgIndex) { msg.asciiChar2 = *(msgP + 1); if (!msg.asciiChar) { + // End of message *msgP = '\0'; - msg.flags &= ~KMSG_8; - } else if (msg.flags & KMSG_1) { + msg.flags &= ~KMSG_SCROLL; + } else if (msg.flags & KMSG_QUOTED) { *msgP = '"'; *(msgP + 1) = '\0'; } @@ -520,8 +521,8 @@ void MadsKernelMessageList::processText(int msgIndex) { int strWidth = _talkFont->getWidth(msg.msg, _owner._textSpacing); - if (msg.flags & KMSG_30) { - x1 -= (msg.flags & KMSG_20) ? strWidth / 2 : strWidth; + 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 @@ -854,7 +855,7 @@ 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 msgX, int msgY, 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 @@ -882,7 +883,7 @@ int MadsSequenceList::add(int spriteListIndex, int v0, int frameIndex, int trigg _entries[timerIndex].frameInc = frameInc; _entries[timerIndex].depth = depth; _entries[timerIndex].scale = scale; - _entries[timerIndex].field_12 = field_12; + _entries[timerIndex].nonFixed = nonFixed; _entries[timerIndex].msgPos.x = msgX; _entries[timerIndex].msgPos.y = msgY; _entries[timerIndex].numTicks = numTicks; @@ -924,7 +925,7 @@ void MadsSequenceList::setSpriteSlot(int timerIndex, MadsSpriteSlot &spriteSlot) spriteSlot.depth = timerEntry.depth; spriteSlot.scale = timerEntry.scale; - if (timerEntry.field_12 == 0) { + if (!timerEntry.nonFixed) { spriteSlot.xp = timerEntry.msgPos.x; spriteSlot.yp = timerEntry.msgPos.y; } else { diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h index 52388a99e07..ba7504f3434 100644 --- a/engines/m4/mads_views.h +++ b/engines/m4/mads_views.h @@ -139,8 +139,8 @@ public: #define TIMED_TEXT_SIZE 10 #define TEXT_4A_SIZE 30 -enum KernelMessageFlags {KMSG_1 = 1, KMSG_2 = 2, KMSG_4 = 4, KMSG_8 = 8, KMSG_20 = 0x20, KMSG_30 = 0x30, - 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 MadsKernelMessageEntry { public: @@ -157,7 +157,7 @@ public: uint32 frameTimer2; uint32 frameTimer; uint32 timeout; - bool field_1C; + int abortTimers; AbortTimerMode abortMode; uint16 actionNouns[3]; char msg[100]; @@ -174,9 +174,9 @@ 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(); @@ -313,7 +313,7 @@ struct MadsSequenceEntry { int scale; int dynamicHotspotIndex; - int field_12; + bool nonFixed; int field_13; Common::Point msgPos; @@ -341,7 +341,7 @@ 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 msgX, int msgY, 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); From 1818fa137f491ba8898d83afde86f2d98c857415 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 09:33:33 +0000 Subject: [PATCH 066/249] Silence a warning inside send_selector(): argc > 0 means "write selector". Added code do make sure that argc is always either 0 or 1 when referencing variable selectors (this isn't strictly necessary, but better safe than sorry...). Some cleanup svn-id: r49230 --- engines/sci/engine/vm.cpp | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index d37628da200..1795b86c853 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -341,7 +341,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 +370,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; @@ -397,24 +397,24 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt printf("Varselector: Read\n"); #endif // VM_DEBUG_SEND + // Make sure that argc is either 0 (read) or 1 (write) here. + // This isn't strictly necessary, but better safe than sorry + argc = MIN(argc, 1); + // 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); - { CallsStruct call; call.address.var = varp; // register the call @@ -438,9 +438,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; } { @@ -477,9 +477,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, reg_t objp, int argc, StackPtr argp, Selector selector, const ObjVarRef& address, int origin) { From 9a66bfb575ff536d1a110a43c238b944fe2ea9c7 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 09:59:40 +0000 Subject: [PATCH 067/249] After running some tests, it appears that modifying argc inside send_selector() was a bad idea. Reverting the relevant code, and putting the warning back, with some extra comments svn-id: r49231 --- engines/sci/engine/vm.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 1795b86c853..28e74840987 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -397,10 +397,6 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt printf("Varselector: Read\n"); #endif // VM_DEBUG_SEND - // Make sure that argc is either 0 (read) or 1 (write) here. - // This isn't strictly necessary, but better safe than sorry - argc = MIN(argc, 1); - // argc == 0: read selector // argc != 0: write selector if (printSendActions && !argc) { // read selector @@ -415,6 +411,13 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt printSendActions = false; } + 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? + warning("send_selector(): more than 1 parameter (%d) while modifying a variable selector", argc); + { CallsStruct call; call.address.var = varp; // register the call From 1bee6daff006970b0f1e7186d43c05540a2bb316 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 10:35:54 +0000 Subject: [PATCH 068/249] Added more info to the warning thrown when argc > 1 while modifying a variable selector in send_selector() svn-id: r49232 --- engines/sci/engine/vm.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 28e74840987..8ee60874ea0 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -411,12 +411,21 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt printSendActions = false; } - if (argc > 1) + 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? - warning("send_selector(): more than 1 parameter (%d) while modifying a variable selector", argc); + // 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; From 65fa2f5af836b10554485555959adebc15bde240 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 10:37:54 +0000 Subject: [PATCH 069/249] Formatting svn-id: r49233 --- engines/sci/engine/vm.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 8ee60874ea0..44279af1c15 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -414,11 +414,11 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt 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) + // 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 " From 3187149cca9ab48a391e09c7af6430c2187cd4c6 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 11:02:50 +0000 Subject: [PATCH 070/249] Avoid adding a null char in the sierraId Common::String svn-id: r49234 --- engines/sci/resource.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 57a4fbc751b..af0f08b17a6 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -2358,12 +2358,9 @@ Common::String ResourceManager::findSierraGameId() { seeker = heap->data + READ_UINT16(heap->data + READ_UINT16(exportPtr) + nameSelector * 2); } - char c = 0; - do { - c = *(seeker++); - sierraId += c; - } while (c); + sierraId += *(seeker++); + } while (*seeker); return sierraId; } From 14fae8db03e5a314ec19277ef497fbaae03d6177 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 11:56:58 +0000 Subject: [PATCH 071/249] Proper fix for the MSVC warning concerning packing: reordered the members of the ParseTable struct and removed the struct packing pragmas svn-id: r49235 --- graphics/video/qt_decoder.cpp | 50 +++++++++++++++++------------------ graphics/video/qt_decoder.h | 8 ++---- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/graphics/video/qt_decoder.cpp b/graphics/video/qt_decoder.cpp index 1628e0f308d..244ed14a533 100644 --- a/graphics/video/qt_decoder.cpp +++ b/graphics/video/qt_decoder.cpp @@ -379,31 +379,31 @@ void QuickTimeDecoder::init() { void QuickTimeDecoder::initParseTable() { static const ParseTable p[] = { - { MKID_BE('dinf'), &QuickTimeDecoder::readDefault }, - { MKID_BE('dref'), &QuickTimeDecoder::readLeaf }, - { MKID_BE('edts'), &QuickTimeDecoder::readDefault }, - { MKID_BE('elst'), &QuickTimeDecoder::readELST }, - { MKID_BE('hdlr'), &QuickTimeDecoder::readHDLR }, - { MKID_BE('mdat'), &QuickTimeDecoder::readMDAT }, - { MKID_BE('mdhd'), &QuickTimeDecoder::readMDHD }, - { MKID_BE('mdia'), &QuickTimeDecoder::readDefault }, - { MKID_BE('minf'), &QuickTimeDecoder::readDefault }, - { MKID_BE('moov'), &QuickTimeDecoder::readMOOV }, - { MKID_BE('mvhd'), &QuickTimeDecoder::readMVHD }, - { MKID_BE('smhd'), &QuickTimeDecoder::readLeaf }, - { MKID_BE('stbl'), &QuickTimeDecoder::readDefault }, - { MKID_BE('stco'), &QuickTimeDecoder::readSTCO }, - { MKID_BE('stsc'), &QuickTimeDecoder::readSTSC }, - { MKID_BE('stsd'), &QuickTimeDecoder::readSTSD }, - { MKID_BE('stss'), &QuickTimeDecoder::readSTSS }, - { MKID_BE('stsz'), &QuickTimeDecoder::readSTSZ }, - { MKID_BE('stts'), &QuickTimeDecoder::readSTTS }, - { MKID_BE('tkhd'), &QuickTimeDecoder::readTKHD }, - { MKID_BE('trak'), &QuickTimeDecoder::readTRAK }, - { MKID_BE('udta'), &QuickTimeDecoder::readLeaf }, - { MKID_BE('vmhd'), &QuickTimeDecoder::readLeaf }, - { MKID_BE('cmov'), &QuickTimeDecoder::readCMOV }, - { MKID_BE('wave'), &QuickTimeDecoder::readWAVE }, + { &QuickTimeDecoder::readDefault, MKID_BE('dinf') }, + { &QuickTimeDecoder::readLeaf, MKID_BE('dref') }, + { &QuickTimeDecoder::readDefault, MKID_BE('edts') }, + { &QuickTimeDecoder::readELST, MKID_BE('elst') }, + { &QuickTimeDecoder::readHDLR, MKID_BE('hdlr') }, + { &QuickTimeDecoder::readMDAT, MKID_BE('mdat') }, + { &QuickTimeDecoder::readMDHD, MKID_BE('mdhd') }, + { &QuickTimeDecoder::readDefault, MKID_BE('mdia') }, + { &QuickTimeDecoder::readDefault, MKID_BE('minf') }, + { &QuickTimeDecoder::readMOOV, MKID_BE('moov') }, + { &QuickTimeDecoder::readMVHD, MKID_BE('mvhd') }, + { &QuickTimeDecoder::readLeaf, MKID_BE('smhd') }, + { &QuickTimeDecoder::readDefault, MKID_BE('stbl') }, + { &QuickTimeDecoder::readSTCO, MKID_BE('stco') }, + { &QuickTimeDecoder::readSTSC, MKID_BE('stsc') }, + { &QuickTimeDecoder::readSTSD, MKID_BE('stsd') }, + { &QuickTimeDecoder::readSTSS, MKID_BE('stss') }, + { &QuickTimeDecoder::readSTSZ, MKID_BE('stsz') }, + { &QuickTimeDecoder::readSTTS, MKID_BE('stts') }, + { &QuickTimeDecoder::readTKHD, MKID_BE('tkhd') }, + { &QuickTimeDecoder::readTRAK, MKID_BE('trak') }, + { &QuickTimeDecoder::readLeaf, MKID_BE('udta') }, + { &QuickTimeDecoder::readLeaf, MKID_BE('vmhd') }, + { &QuickTimeDecoder::readCMOV, MKID_BE('cmov') }, + { &QuickTimeDecoder::readWAVE, MKID_BE('wave') }, { 0, 0 } }; diff --git a/graphics/video/qt_decoder.h b/graphics/video/qt_decoder.h index 659ad855e47..db4ff8180b5 100644 --- a/graphics/video/qt_decoder.h +++ b/graphics/video/qt_decoder.h @@ -136,14 +136,10 @@ protected: uint32 size; }; -#include "common/pack-start.h" // START STRUCT PACKING - struct ParseTable { - uint32 type; int (QuickTimeDecoder::*func)(MOVatom atom); - } PACKED_STRUCT; - -#include "common/pack-end.h" // END STRUCT PACKING + uint32 type; + }; struct MOVstts { int count; From f2dda51943c0a34315babb8241c1f12fe3f5d658 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 26 May 2010 12:15:14 +0000 Subject: [PATCH 072/249] Have makeADPCMStream use the entire stream if the size is 0 (as it says in the doxygen comment). svn-id: r49236 --- sound/decoders/adpcm.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/decoders/adpcm.cpp b/sound/decoders/adpcm.cpp index 7a85bc24d52..c8a907d13e0 100644 --- a/sound/decoders/adpcm.cpp +++ b/sound/decoders/adpcm.cpp @@ -724,6 +724,10 @@ int16 Ima_ADPCMStream::decodeIMA(byte code, int channel) { } RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, typesADPCM type, int rate, int channels, uint32 blockAlign) { + // If size is 0, report the entire size of the stream + if (!size) + size = stream->size(); + switch (type) { case kADPCMOki: return new Oki_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign); From 163847b24572ff5425f5ab4256ab1349c9840a74 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 26 May 2010 13:11:04 +0000 Subject: [PATCH 073/249] Fix the 'boiling water' videos in the boiler puzzle. svn-id: r49237 --- engines/mohawk/riven_external.cpp | 7 ++++--- engines/mohawk/riven_scripts.cpp | 3 +-- engines/mohawk/video.cpp | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 184761318ff..fd70de517f4 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -537,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(); diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp index fa6f3365421..b175b3af528 100644 --- a/engines/mohawk/riven_scripts.cpp +++ b/engines/mohawk/riven_scripts.cpp @@ -547,9 +547,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.cpp b/engines/mohawk/video.cpp index 3a86e0323bc..beef3128760 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -277,8 +277,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; } } From 1a01caece762dd06886460830c4cdaf7de42c8d8 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Wed, 26 May 2010 13:24:32 +0000 Subject: [PATCH 074/249] SCI: adding another hack to sci32 picture drawing, fixes crash in sci32 games introduced by r49216 svn-id: r49238 --- engines/sci/graphics/picture.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index fad738aa3a1..3edb8ab18e6 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -143,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 From 2f4f70f3b02f49dc65ec2ba74adf29fbbcbd7323 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Wed, 26 May 2010 13:26:52 +0000 Subject: [PATCH 075/249] Patch #2951677: Text boxes should init with the caret at the beginning svn-id: r49239 --- gui/editable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/editable.cpp b/gui/editable.cpp index 723384ed442..058f08e2332 100644 --- a/gui/editable.cpp +++ b/gui/editable.cpp @@ -65,7 +65,7 @@ void EditableWidget::setEditString(const String &str) { // TODO: We probably should filter the input string here, // e.g. using tryInsertChar. _editString = str; - _caretPos = _editString.size(); + _caretPos = 0; } bool EditableWidget::tryInsertChar(byte c, int pos) { From d502bdf982410dfc0e5731fa9a83f543f08bd744 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Wed, 26 May 2010 13:27:11 +0000 Subject: [PATCH 076/249] Add safeguards when no engines with engine-data are included. Inspired by patch #2986300 svn-id: r49240 --- ports.mk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ports.mk b/ports.mk index 4d819f54f9a..8f51ebb0057 100644 --- a/ports.mk +++ b/ports.mk @@ -44,7 +44,9 @@ bundle: scummvm-static cp $(srcdir)/icons/scummvm.icns $(bundle_name)/Contents/Resources/ cp $(DIST_FILES_DOCS) $(bundle_name)/ cp $(DIST_FILES_THEMES) $(bundle_name)/Contents/Resources/ +ifdef DIST_FILES_ENGINEDATA cp $(DIST_FILES_ENGINEDATA) $(bundle_name)/Contents/Resources/ +endif $(srcdir)/tools/credits.pl --rtf > $(bundle_name)/Contents/Resources/Credits.rtf chmod 644 $(bundle_name)/Contents/Resources/* cp scummvm-static $(bundle_name)/Contents/MacOS/scummvm @@ -56,7 +58,9 @@ iphonebundle: iphone cp $(srcdir)/dists/iphone/Info.plist $(bundle_name)/ cp $(DIST_FILES_DOCS) $(bundle_name)/ cp $(DIST_FILES_THEMES) $(bundle_name)/ +ifdef DIST_FILES_ENGINEDATA cp $(DIST_FILES_ENGINEDATA) $(bundle_name)/ +endif $(STRIP) scummvm ldid -S scummvm chmod 755 scummvm @@ -151,7 +155,9 @@ win32dist: $(EXECUTABLE) mkdir -p $(WIN32PATH) $(STRIP) $(EXECUTABLE) -o $(WIN32PATH)/$(EXECUTABLE) cp $(DIST_FILES_THEMES) $(WIN32PATH) +ifdef DIST_FILES_ENGINEDATA cp $(DIST_FILES_ENGINEDATA) $(WIN32PATH) +endif cp $(srcdir)/AUTHORS $(WIN32PATH)/AUTHORS.txt cp $(srcdir)/COPYING $(WIN32PATH)/COPYING.txt cp $(srcdir)/COPYING.LGPL $(WIN32PATH)/COPYING.LGPL.txt @@ -172,7 +178,9 @@ aos4dist: $(EXECUTABLE) $(STRIP) $(EXECUTABLE) -o $(AOS4PATH)/$(EXECUTABLE) cp icons/scummvm.info $(AOS4PATH)/$(EXECUTABLE).info cp $(DIST_FILES_THEMES) $(AOS4PATH)/themes/ +ifdef DIST_FILES_ENGINEDATA cp $(DIST_FILES_ENGINEDATA) $(AOS4PATH)/extras/ +endif cp $(srcdir)/AUTHORS $(AOS4PATH)/AUTHORS.txt cp $(srcdir)/COPYING $(AOS4PATH)/COPYING.txt cp $(srcdir)/COPYING.LGPL $(AOS4PATH)/COPYING.LGPL.txt From bfaba64c6a3aee6875bf135147c2f29a621c876b Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 14:25:51 +0000 Subject: [PATCH 077/249] Made find_unique_script_block() a member of the Script class svn-id: r49241 --- engines/sci/engine/savegame.cpp | 24 ++---------------------- engines/sci/engine/segment.cpp | 24 ++++++++++++++++++++++++ engines/sci/engine/segment.h | 5 +++++ 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index ff51f4015ca..8f341895c6c 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -748,26 +748,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); @@ -821,8 +801,8 @@ void SegManager::reconstructScripts(EngineState *s) { 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 = (uint16 *) scr->findBlock(SCI_OBJ_EXPORTS); + scr->_synonyms = scr->findBlock(SCI_OBJ_SYNONYMS); scr->_exportTable += 3; } scr->_codeBlocks.clear(); diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 0c468a3cc25..b26ac4f78eb 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -395,6 +395,30 @@ int Script::getSynonymsNr() const { return _numSynonyms; } +byte *Script::findBlock(int type) { + byte *buf = _buf; + bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); + + if (oldScriptHeader) + buf += 2; + + do { + int seekerType = READ_LE_UINT16(buf); + + if (seekerType == 0) + break; + if (seekerType == type) + return buf; + + 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) { diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 876a081295a..764d235e541 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -498,6 +498,11 @@ public: */ int16 getHeap(uint16 offset) const; + /** + * Finds the pointer where a block of a specific type starts from + */ + byte *Script::findBlock(int type); + private: void setScriptSize(int script_nr, ResourceManager *resMan); }; From af8a82aa13f2a316f6a9b4fd857230cbf87c6b1c Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 14:31:51 +0000 Subject: [PATCH 078/249] Fixed compilation svn-id: r49242 --- engines/sci/engine/segment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 764d235e541..2912567ff76 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -501,7 +501,7 @@ public: /** * Finds the pointer where a block of a specific type starts from */ - byte *Script::findBlock(int type); + byte *findBlock(int type); private: void setScriptSize(int script_nr, ResourceManager *resMan); From 8b54efd8a62a68a0544dfc5438c4efe42c0f79f1 Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Wed, 26 May 2010 14:43:25 +0000 Subject: [PATCH 079/249] PSP: implemented basic file cache. Turns out the PSP reads 1 byte as fast as it reads 1 KB. svn-id: r49243 --- backends/fs/psp/psp-stream.cpp | 251 +++++++++++++++++++++++---------- backends/fs/psp/psp-stream.h | 31 ++-- 2 files changed, 197 insertions(+), 85 deletions(-) diff --git a/backends/fs/psp/psp-stream.cpp b/backends/fs/psp/psp-stream.cpp index 8cb7dfea173..d3d6311836c 100644 --- a/backends/fs/psp/psp-stream.cpp +++ b/backends/fs/psp/psp-stream.cpp @@ -32,28 +32,26 @@ #include +#define MIN2(a,b) ((a < b) ? a : b) +#define MIN3(a,b,c) ( (a < b) ? (a < c ? a : c) : (b < c ? b : c) ) + //#define __PSP_PRINT_TO_FILE__ //#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ //#define __PSP_DEBUG_PRINT__ /* For debug printouts */ #include "backends/platform/psp/trace.h" PSPIoStream::PSPIoStream(const Common::String &path, bool writeMode) - : StdioStream((void *)1), _path(path), _writeMode(writeMode) { + : StdioStream((void *)1), _path(path), _writeMode(writeMode), + _ferror(false), _pos(0), + _physicalPos(0), _fileSize(0), _inCache(false), + _cacheStartOffset(-1), _cache(0), + _errorSuspend(0), _errorSource(0), + _errorPos(0), _errorHandle(0), _suspendCount(0) { DEBUG_ENTER_FUNC(); - assert(!path.empty()); + // assert(!path.empty()); // do we need this? _handle = (void *)0; // Need to do this since base class asserts not 0. - _ferror = false; - _feof = false; - _pos = 0; - - /* for error checking */ - _errorSuspend = 0; - _errorSource = 0; - _errorPos = 0; - _errorHandle = 0; - _suspendCount = 0; } PSPIoStream::~PSPIoStream() { @@ -63,9 +61,12 @@ PSPIoStream::~PSPIoStream() { PSP_DEBUG_PRINT_FUNC("Suspended\n"); PowerMan.unregisterSuspend(this); // Unregister with powermanager to be suspended - // Must do this before fclose() or resume() will reopen. + // Must do this before fclose() or resume() will reopen. - fclose((FILE *)_handle); // We don't need a critical section(?). Worst case, the handle gets closed on its own + fclose((FILE *)_handle); // We don't need a critical section. Worst case, the handle gets closed on its own + + if (_cache) + free(_cache); PowerMan.endCriticalSection(); } @@ -82,6 +83,16 @@ void *PSPIoStream::open() { _handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb"); // open + if (_handle) { + // Get the file size + fseek((FILE *)_handle, 0, SEEK_END); // go to the end + _fileSize = ftell((FILE *)_handle); + fseek((FILE *)_handle, 0, SEEK_SET); // back to the beginning + + // Allocate the cache + _cache = (char *)memalign(64, CACHE_SIZE); + } + PowerMan.registerSuspend(this); // Register with the powermanager to be suspended PowerMan.endCriticalSection(); @@ -91,100 +102,177 @@ void *PSPIoStream::open() { bool PSPIoStream::err() const { DEBUG_ENTER_FUNC(); - if (_ferror) - PSP_ERROR("mem_ferror[%d], source[%d], suspend error[%d], pos[%d], _errorPos[%d], _errorHandle[%p], suspendCount[%d]\n", - _ferror, _errorSource, _errorSuspend, _pos, _errorPos, _errorHandle, _suspendCount); + if (_ferror) // We dump since no printing to screen with suspend + PSP_ERROR("mem_ferror[%d], source[%d], suspend error[%d], pos[%d], \ + _errorPos[%d], _errorHandle[%p], suspendCount[%d]\n", + _ferror, _errorSource, _errorSuspend, _pos, + _errorPos, _errorHandle, _suspendCount); return _ferror; } void PSPIoStream::clearErr() { - _ferror = false; // Remove regular error bit + _ferror = false; } bool PSPIoStream::eos() const { - return _feof; + return (_pos >= _fileSize); } int32 PSPIoStream::pos() const { return _pos; } - int32 PSPIoStream::size() const { - DEBUG_ENTER_FUNC(); - if (PowerMan.beginCriticalSection() == PowerManager::Blocked) - PSP_DEBUG_PRINT_FUNC("Suspended\n"); - - fseek((FILE *)_handle, 0, SEEK_END); - int32 length = ftell((FILE *)_handle); - fseek((FILE *)_handle, _pos, SEEK_SET); - - if (_pos < 0 || length < 0) { // Check for errors - _errorSource = 2; - PSP_ERROR("pos[%d] or length[%d] < 0!\n", _pos, length); - _ferror = true; - length = -1; // If our oldPos is bad, we want length to be bad too to signal - clearerr((FILE *)_handle); - } - - PowerMan.endCriticalSection(); - - return length; + return _fileSize; } bool PSPIoStream::seek(int32 offs, int whence) { DEBUG_ENTER_FUNC(); - - // Check if we can access the file - if (PowerMan.beginCriticalSection() == PowerManager::Blocked) - PSP_DEBUG_PRINT_FUNC("Suspended\n"); - - int ret = fseek((FILE *)_handle, offs, whence); - - if (ret != 0) { - _ferror = true; - PSP_ERROR("fseek returned with [%d], non-zero\n", ret); - clearerr((FILE *)_handle); - _feof = feof((FILE *)_handle); - _errorSource = 3; - } else { // everything ok - _feof = false; // Reset eof flag since we know it was ok + PSP_DEBUG_PRINT_FUNC("offset[%d], whence[%d], _pos[%d], _physPos[%d]\n", offs, whence, _pos, _physicalPos); + bool success = true; + + int32 posToSearchFor = 0; + switch (whence) { + case SEEK_CUR: + posToSearchFor = _pos; + break; + case SEEK_END: + posToSearchFor = _fileSize; // unsure. Does it take us here or to EOS - 1? + break; } - - _pos = ftell((FILE *)_handle); // update pos - - PowerMan.endCriticalSection(); - - return (ret == 0); + posToSearchFor += offs; + + // Check for bad values + if (posToSearchFor < 0 || posToSearchFor > _fileSize) { + _ferror = true; + return false; + } + + // See if we can find it in cache + if (isOffsetInCache(posToSearchFor)) { + PSP_DEBUG_PRINT("seek offset[%d] found in cache. Cache starts[%d]\n", posToSearchFor, _cacheStartOffset); + _inCache = true; + } else { // not in cache + _inCache = false; + } + _pos = posToSearchFor; + return success; } +// for debugging +/* +void printBuffer(byte *ptr, uint32 len) { + for (int i = 0; i < len; i++) { + PSP_INFO_PRINT("%x ", *ptr); + ptr++; + } + PSP_INFO_PRINT("\n"); +}*/ + uint32 PSPIoStream::read(void *ptr, uint32 len) { DEBUG_ENTER_FUNC(); - // Check if we can access the file + PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d], ptr[%p]\n", _path.c_str(), len, ptr); + + byte *destPtr = (byte *)ptr; + uint32 lenFromFile = len; // how much we read from the actual file + uint32 lenFromCache = 0; // how much we read from cache + uint32 lenRemainingInFile = _fileSize - _pos; + + if (lenFromFile > lenRemainingInFile) + lenFromFile = lenRemainingInFile; + + // Are we in cache? + if (_inCache && isCacheValid()) { + uint32 offsetInCache = _pos - _cacheStartOffset; + // We can read at most what's in the cache or the remaining size of the file + lenFromCache = MIN2(lenFromFile, CACHE_SIZE - offsetInCache); // unsure + + PSP_DEBUG_PRINT("reading %d bytes from cache to %p. pos[%d] physPos[%d] cacheStart[%d]\n", lenFromCache, destPtr, _pos, _physicalPos, _cacheStartOffset); + + memcpy(destPtr, &_cache[offsetInCache], lenFromCache); + _pos += lenFromCache; + + if (lenFromCache < lenFromFile) { // there's more to copy from the file + lenFromFile -= lenFromCache; + lenRemainingInFile -= lenFromCache; // since we moved pos + destPtr += lenFromCache; + } else { // we're done + // debug + //if (len < 10) printBuffer((byte *)ptr, len); + return lenFromCache; // how much we actually read + } + } + if (PowerMan.beginCriticalSection() == PowerManager::Blocked) PSP_DEBUG_PRINT_FUNC("Suspended\n"); - - PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d]\n", _path.c_str(), len); - - size_t ret = fread((byte *)ptr, 1, len, (FILE *)_handle); - - _pos += ret; // Update pos - - if (ret != len) { // Check for eof - _feof = feof((FILE *)_handle); - if (!_feof) { // It wasn't an eof. Must be an error + + + synchronizePhysicalPos(); // we need to update our physical position + + if (lenFromFile <= MIN_READ_SIZE) { // We load the cache in case the read is small enough + // This optimization is based on the principle that reading 1 byte is as expensive as 1000 bytes + uint32 lenToCopyToCache = MIN2((uint32)MIN_READ_SIZE, lenRemainingInFile); // at most remaining file size + + PSP_DEBUG_PRINT("filling cache with %d bytes from physicalPos[%d]. cacheStart[%d], pos[%d], fileSize[%d]\n", lenToCopyToCache, _physicalPos, _cacheStartOffset, _pos, _fileSize); + + size_t ret = fread(_cache, 1, lenToCopyToCache, (FILE *)_handle); + if (ret != lenToCopyToCache) { + PSP_ERROR("in filling cache, failed to get %d bytes. Only got %d\n", lenToCopyToCache, ret); _ferror = true; clearerr((FILE *)_handle); - _pos = ftell((FILE *)_handle); // Update our position - _errorSource = 4; - PSP_ERROR("fread returned ret[%d] instead of len[%d]\n", ret, len); } + _cacheStartOffset = _physicalPos; + _inCache = true; + + _physicalPos += ret; + + PSP_DEBUG_PRINT("copying %d bytes from cache to %p\n", lenFromFile, destPtr); + + // Copy to the destination buffer from cache + memcpy(destPtr, _cache, lenFromFile); + _pos += lenFromFile; + + } else { // Too big for cache. No caching + PSP_DEBUG_PRINT("reading %d bytes from file to %p. Pos[%d], physPos[%d]\n", lenFromFile, destPtr, _pos, _physicalPos); + size_t ret = fread(destPtr, 1, lenFromFile, (FILE *)_handle); + + _physicalPos += ret; // Update pos + _pos = _physicalPos; + + if (ret != lenFromFile) { // error + PSP_ERROR("fread returned [%d] instead of len[%d]\n", ret, lenFromFile); + _ferror = true; + clearerr((FILE *)_handle); + _errorSource = 4; + } + _inCache = false; } PowerMan.endCriticalSection(); - return ret; + // debug + //if (len < 10) printBuffer((byte *)ptr, len); + return lenFromCache + lenFromFile; // total of what was copied +} + +// TODO: Test if seeking backwards/forwards has any effect on performance +inline bool PSPIoStream::synchronizePhysicalPos() { + if (_pos != _physicalPos) { + if (fseek((FILE *)_handle, _pos - _physicalPos, SEEK_CUR) != 0) + return false; + _physicalPos = _pos; + } + + return true; +} + +inline bool PSPIoStream::isOffsetInCache(uint32 offset) { + if (_cacheStartOffset != -1 && + offset >= (uint32)_cacheStartOffset && + offset < (uint32)(_cacheStartOffset + CACHE_SIZE)) + return true; + return false; } uint32 PSPIoStream::write(const void *ptr, uint32 len) { @@ -195,9 +283,17 @@ uint32 PSPIoStream::write(const void *ptr, uint32 len) { PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d]\n", _path.c_str(), len); + synchronizePhysicalPos(); + size_t ret = fwrite(ptr, 1, len, (FILE *)_handle); - _pos += ret; + // If we're making the file bigger, adjust the size + if (_physicalPos + (int)ret > _fileSize) + _fileSize = _physicalPos + ret; + _physicalPos += ret; + _pos = _physicalPos; + _inCache = false; + _cacheStartOffset = -1; // invalidate cache if (ret != len) { // Set error _ferror = true; @@ -286,6 +382,9 @@ int PSPIoStream::resume() { // Resume our previous position if (_handle > 0 && _pos > 0) { ret = fseek((FILE *)_handle, _pos, SEEK_SET); + + _physicalPos = _pos; + _inCache = false; if (ret != 0) { // Check for problem _errorSuspend = ResumeError; diff --git a/backends/fs/psp/psp-stream.h b/backends/fs/psp/psp-stream.h index 673630b685e..10d5016852a 100644 --- a/backends/fs/psp/psp-stream.h +++ b/backends/fs/psp/psp-stream.h @@ -35,25 +35,38 @@ */ class PSPIoStream : public StdioStream, public Suspendable { protected: - Common::String _path; /* Need to maintain for reopening after suspend */ - bool _writeMode; /* "" */ - int _pos; /* "" */ - mutable int _ferror; /* Save file ferror */ - mutable bool _feof; /* and eof */ - + Common::String _path; + int _fileSize; + bool _writeMode; // for resuming in the right mode + int _physicalPos; // position in the real file + int _pos; // position. Sometimes virtual + bool _inCache; // whether we're in cache (virtual) mode + enum { SuspendError = 2, ResumeError = 3 }; - int _errorSuspend; + enum { + CACHE_SIZE = 1024, + MIN_READ_SIZE = 1024 // reading less than 1024 takes exactly the same time as 1024 + }; + + // For caching + char *_cache; + int _cacheStartOffset; // starting offset of the cache. -1 when cache is invalid + + mutable int _ferror; // file error state + int _errorSuspend; // for debugging mutable int _errorSource; - - // Error checking int _errorPos; void * _errorHandle; int _suspendCount; + bool synchronizePhysicalPos(); // synchronize the physical and virtual positions + bool isOffsetInCache(uint32 pos); // check if an offset is found in cache + bool isCacheValid() { return _cacheStartOffset != -1; } + public: /** From 7b8837cda7b3c44d5e283ef8bb9ebe6e943ebb27 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 26 May 2010 15:41:50 +0000 Subject: [PATCH 080/249] SCI: Simplify appending string 'seeker' to sierraId svn-id: r49244 --- engines/sci/resource.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index af0f08b17a6..3535e36f772 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -2358,9 +2358,7 @@ Common::String ResourceManager::findSierraGameId() { seeker = heap->data + READ_UINT16(heap->data + READ_UINT16(exportPtr) + nameSelector * 2); } - do { - sierraId += *(seeker++); - } while (*seeker); + sierraId += (const char *)seeker; return sierraId; } From 017507ffa6a774ea1df4d74b8431155540f76244 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 26 May 2010 15:42:26 +0000 Subject: [PATCH 081/249] Take any 'moov' resource from a resource fork, not just 0x80; minor cleanup. svn-id: r49245 --- graphics/video/qt_decoder.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/graphics/video/qt_decoder.cpp b/graphics/video/qt_decoder.cpp index 244ed14a533..49d2b0aed95 100644 --- a/graphics/video/qt_decoder.cpp +++ b/graphics/video/qt_decoder.cpp @@ -279,7 +279,12 @@ bool QuickTimeDecoder::loadFile(const Common::String &filename) { MOVatom atom = { 0, 0, 0xffffffff }; if (_resFork->hasResFork()) { - _fd = _resFork->getResource(MKID_BE('moov'), 0x80); + // Search for a 'moov' resource + Common::MacResIDArray idArray = _resFork->getResIDArray(MKID_BE('moov')); + + if (!idArray.empty()) + _fd = _resFork->getResource(MKID_BE('moov'), idArray[0]); + if (_fd) { atom.size = _fd->size(); if (readDefault(atom) < 0 || !_foundMOOV) @@ -417,7 +422,7 @@ int QuickTimeDecoder::readDefault(MOVatom atom) { a.offset = atom.offset; - while(((total_size + 8) < atom.size) && !_fd->eos() && !err) { + while(((total_size + 8) < atom.size) && !_fd->eos() && _fd->pos() < _fd->size() && !err) { a.size = atom.size; a.type = 0; @@ -1153,6 +1158,7 @@ void QuickTimeDecoder::close() { delete _streams[i]; delete _fd; + _fd = 0; if (_scaledSurface) { _scaledSurface->free(); From 0197e9f6a19738054a4b847e3217cd3794ef3ce3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 26 May 2010 16:30:10 +0000 Subject: [PATCH 082/249] SCI: Making various object and script related things const svn-id: r49246 --- engines/sci/console.cpp | 14 ++--- engines/sci/engine/features.cpp | 4 +- engines/sci/engine/kparse.cpp | 2 +- engines/sci/engine/kscripts.cpp | 2 +- engines/sci/engine/savegame.cpp | 2 +- engines/sci/engine/scriptdebug.cpp | 2 +- engines/sci/engine/seg_manager.cpp | 8 +-- engines/sci/engine/segment.cpp | 73 ++++++++++++++------------ engines/sci/engine/segment.h | 84 +++++++++++++++--------------- engines/sci/engine/selector.cpp | 2 +- engines/sci/engine/vm.cpp | 8 +-- 11 files changed, 104 insertions(+), 97 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 30791740d0f..8dbf297f554 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -1265,7 +1265,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()), @@ -1312,7 +1312,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()), @@ -2226,7 +2226,7 @@ bool Console::cmdDisassemble(int argc, const char **argv) { return true; } - Object *obj = _engine->_gamestate->_segMan->getObject(objAddr); + const Object *obj = _engine->_gamestate->_segMan->getObject(objAddr); int selector_id = _engine->getKernel()->findSelector(argv[2]); reg_t addr; @@ -2327,7 +2327,7 @@ bool Console::cmdSend(int argc, const char **argv) { 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; @@ -3018,8 +3018,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) { @@ -3048,7 +3048,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)); diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index e51867332aa..0e521d3c73c 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -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++) { @@ -343,7 +343,7 @@ SciVersion GameFeatures::detectGfxFunctionsType() { // No overlay selector found, check if any method of the Rm object // is calling kDrawPic, as the overlay selector might be missing in demos - Object *obj = _segMan->getObject(_segMan->findObjectByName("Rm")); + const Object *obj = _segMan->getObject(_segMan->findObjectByName("Rm")); for (uint m = 0; m < obj->getMethodCount(); m++) { found = autoDetectGfxFunctionsType(m); if (found) diff --git a/engines/sci/engine/kparse.cpp b/engines/sci/engine/kparse.cpp index 0254d21642d..51ad6bb5c65 100644 --- a/engines/sci/engine/kparse.cpp +++ b/engines/sci/engine/kparse.cpp @@ -177,7 +177,7 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) { 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", diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index ba29f649662..eeaa0ceec0c 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* diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 8f341895c6c..c967dddf7dc 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -833,7 +833,7 @@ void SegManager::reconstructScripts(EngineState *s) { it->_value._baseVars = (uint16 *)(scr->_buf + READ_LE_UINT16( data + 4 )); } else { int funct_area = READ_LE_UINT16(data + SCRIPT_FUNCTAREAPTR_OFFSET); - Object *baseObj = s->_segMan->getObject(it->_value.getSpeciesSelector()); + const Object *baseObj = s->_segMan->getObject(it->_value.getSpeciesSelector()); if (!baseObj) { warning("Object without a base class: Script %d, index %d (reg address %04x:%04x", diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 608260ec509..da8e4ee211f 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -193,7 +193,7 @@ 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 ((opcode == op_pTos) || (opcode == op_sTop) || (opcode == op_pToa) || (opcode == op_aTop) || (opcode == op_dpToa) || (opcode == op_ipToa) || (opcode == op_dpTos) || (opcode == op_ipTos)) { - Object *obj = s->_segMan->getObject(scriptState.xs->objp); + const Object *obj = s->_segMan->getObject(scriptState.xs->objp); if (!obj) warning("Attempted to reference on non-object at %04x:%04x", PRINT_REG(scriptState.xs->objp)); else diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index b18d76e1a7a..e0b6e75d702 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -156,7 +156,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); @@ -234,7 +234,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 ""; @@ -275,7 +275,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; @@ -485,7 +485,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); diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index b26ac4f78eb..c43c195e6b8 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -194,6 +194,13 @@ Object *Script::getObject(uint16 offset) { return 0; } +const Object *Script::getObject(uint16 offset) const { + if (_objects.contains(offset)) + return &_objects[offset]; + else + return 0; +} + Object *Script::scriptObjInit(reg_t obj_pos) { Object *obj; @@ -355,8 +362,8 @@ void Script::setLockers(int lockers) { void Script::setExportTableOffset(int offset) { if (offset) { - _exportTable = (uint16 *)(_buf + offset + 2); - _numExports = READ_SCI11ENDIAN_UINT16((byte *)(_exportTable - 1)); + _exportTable = (const uint16 *)(_buf + offset + 2); + _numExports = READ_SCI11ENDIAN_UINT16((const byte *)(_exportTable - 1)); } else { _exportTable = NULL; _numExports = 0; @@ -373,7 +380,7 @@ uint16 Script::validateExportFunc(int pubfunct) { if (exportsAreWide) pubfunct *= 2; - uint16 offset = READ_SCI11ENDIAN_UINT16((byte *)(_exportTable + pubfunct)); + uint16 offset = READ_SCI11ENDIAN_UINT16((const byte *)(_exportTable + pubfunct)); VERIFY(offset < _bufSize, "invalid export function pointer"); return offset; @@ -383,7 +390,7 @@ void Script::setSynonymsOffset(int offset) { _synonyms = _buf + offset; } -byte *Script::getSynonyms() const { +const byte *Script::getSynonyms() const { return _synonyms; } @@ -547,13 +554,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) @@ -573,16 +580,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++) @@ -626,7 +631,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++) @@ -640,7 +645,7 @@ reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) { 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]); @@ -653,13 +658,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); @@ -673,12 +678,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 @@ -694,19 +699,19 @@ void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback //-------------------- object ---------------------------- void Object::init(byte *buf, reg_t obj_pos) { - byte *data = (byte *)(buf + obj_pos.offset); + byte *data = buf + obj_pos.offset; _baseObj = data; _pos = obj_pos; 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)); + _baseVars = (const uint16 *)(_baseObj + _variables.size() * 2); + _baseMethod = (const 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)); + _baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4)); + _baseMethod = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 6)); _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod); } @@ -714,12 +719,12 @@ void Object::init(byte *buf, reg_t obj_pos) { _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2))); } -Object *Object::getClass(SegManager *segMan) { +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) { @@ -727,7 +732,7 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) { int selector_name_offset = varnum * 2 + SCRIPT_SELECTOR_OFFSET; buf = _baseObj + selector_name_offset; } else { - Object *obj = getClass(segMan); + const Object *obj = getClass(segMan); varnum = obj->getVariable(1).toUint16(); buf = (byte *)obj->_baseVars; } @@ -761,7 +766,7 @@ bool Object::relocate(SegmentId segment, int location, size_t scriptSize) { return true; } -int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) { +int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const { int selectors = getVarCount(); if (propertyOffset < 0 || (propertyOffset >> 1) >= selectors) { @@ -771,14 +776,14 @@ int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) { } if (getSciVersion() < SCI_VERSION_1_1) { - byte *selectoroffset = ((byte *)(_baseObj)) + SCRIPT_SELECTOR_OFFSET + selectors * 2; + const byte *selectoroffset = ((const byte *)(_baseObj)) + SCRIPT_SELECTOR_OFFSET + selectors * 2; return READ_SCI11ENDIAN_UINT16(selectoroffset + propertyOffset); } else { - Object *obj = this; + const Object *obj = this; if (!(getInfoSelector().offset & SCRIPT_INFO_CLASS)) obj = segMan->getObject(getSuperClassSelector()); - return READ_SCI11ENDIAN_UINT16((byte *)obj->_baseVars + propertyOffset); + return READ_SCI11ENDIAN_UINT16((const byte *)obj->_baseVars + propertyOffset); } } @@ -801,7 +806,7 @@ void Object::initSuperClass(SegManager *segMan, reg_t addr) { } bool Object::initBaseObject(SegManager *segMan, reg_t addr) { - Object *baseObj = segMan->getObject(getSpeciesSelector()); + const Object *baseObj = segMan->getObject(getSpeciesSelector()); if (baseObj) { setVarCount(baseObj->getVarCount()); @@ -821,7 +826,7 @@ reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) { 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)); } @@ -840,13 +845,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 *array = &(_table[addr.offset]); + const SciArray *array = &(_table[addr.offset]); for (uint32 i = 0; i < array->getSize(); i++) { reg_t value = array->getValue(i); diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 2912567ff76..b3ea80f6657 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -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 {} }; @@ -195,7 +195,7 @@ 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 void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const; virtual void saveLoadWithSerializer(Common::Serializer &ser); }; @@ -214,29 +214,29 @@ 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]; } + reg_t getInfoSelector() const { return _variables[_offset + 2]; } void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; } - reg_t getNameSelector() { return _variables[_offset + 3]; } + 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 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))); } - 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)); } @@ -247,7 +247,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,30 +256,31 @@ 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); + int locateVarSelector(SegManager *segMan, Selector slc) const; - bool isClass() { return (getInfoSelector().offset & SCRIPT_INFO_CLASS); } - Object *getClass(SegManager *segMan); + bool isClass() const { return (getInfoSelector().offset & SCRIPT_INFO_CLASS); } + const Object *getClass(SegManager *segMan) const; void markAsFreed() { _flags |= OBJECT_FLAG_FREED; } - bool isFreed() { return _flags & OBJECT_FLAG_FREED; } + bool isFreed() const { return _flags & OBJECT_FLAG_FREED; } void setVarCount(uint size) { _variables.resize(size); } - uint getVarCount() { return _variables.size(); } + uint getVarCount() const { return _variables.size(); } void init(byte *buf, reg_t obj_pos); - 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; @@ -287,7 +288,7 @@ public: bool relocate(SegmentId segment, int location, size_t scriptSize); - int propertyOffsetToId(SegManager *segMan, int propertyOffset); + int propertyOffsetToId(SegManager *segMan, int propertyOffset) const; void initSpecies(SegManager *segMan, reg_t addr); void initSuperClass(SegManager *segMan, reg_t addr); @@ -296,9 +297,9 @@ public: // TODO: make private // Only SegManager::reconstructScripts() is left needing direct access to these public: - 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 */ + const byte *_baseObj; /**< base + object offset within base */ + const uint16 *_baseVars; /**< Pointer to the varselector area for this object */ + const uint16 *_baseMethod; /**< Pointer to the method selector area for this object */ private: Common::Array _variables; @@ -325,7 +326,7 @@ public: byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */ - uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */ + const 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*/ @@ -360,13 +361,14 @@ public: virtual SegmentRef dereference(reg_t pointer); virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr); 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 @@ -428,7 +430,7 @@ public: * 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; /** * Retrieves the number of synonyms associated with this script. @@ -525,7 +527,7 @@ 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 void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const; virtual void saveLoadWithSerializer(Common::Serializer &ser); }; @@ -613,7 +615,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)); @@ -626,7 +628,7 @@ struct CloneTable : public Table { CloneTable() : Table(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); }; @@ -637,7 +639,7 @@ struct NodeTable : public Table { NodeTable() : Table(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); }; @@ -648,7 +650,7 @@ struct ListTable : public Table { ListTable() : Table(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); }; @@ -684,7 +686,7 @@ 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 void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const; virtual void saveLoadWithSerializer(Common::Serializer &ser); }; @@ -777,7 +779,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); @@ -791,8 +793,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: @@ -817,7 +819,7 @@ struct ArrayTable : public Table > { ArrayTable() : Table >(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 aba134818bb..cdbce5a6e47 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -260,7 +260,7 @@ int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvoc } SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector selector_id, ObjVarRef *varp, reg_t *fptr) { - Object *obj = segMan->getObject(obj_location); + const Object *obj = segMan->getObject(obj_location); int index; bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 44279af1c15..903c4a9a784 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -120,7 +120,7 @@ static reg_t &validate_property(Object *obj, int index) { return dummyReg; } - return obj->getVariable(index); + return obj->getVariableRef(index); } static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) { @@ -1766,12 +1766,12 @@ void quit_vm() { g_debugState.runningStep = 0; } -reg_t* ObjVarRef::getPointer(SegManager *segMan) const { +reg_t *ObjVarRef::getPointer(SegManager *segMan) const { Object *o = segMan->getObject(obj); - return o ? &o->getVariable(varindex) : 0; + 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); } From 2fa8ac0575e45ddfee96e3cd1eba2f2d9c3d2db3 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Wed, 26 May 2010 17:15:49 +0000 Subject: [PATCH 083/249] SCI: adding another workaround for picture 376 in sq4/cd (same issue like originally found in r49216) svn-id: r49247 --- engines/sci/graphics/picture.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index 3edb8ab18e6..a59153f116e 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -533,10 +533,16 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { case PIC_OP_SET_PATTERN: if (_resourceType >= SCI_PICTURE_TYPE_SCI11) { if (strcmp(g_sci->getGameID(), "sq4") == 0) { - // WORKAROUND: For SQ4 / picture 381 handle this like a terminator + // 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 - if (_resourceId == 381) + // 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"); } From db475d1501452490ab4e95ecbd181380b0bec414 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 26 May 2010 18:11:17 +0000 Subject: [PATCH 084/249] SCI: More const related changes; remove unnecessary casts which hide const issues svn-id: r49248 --- engines/sci/engine/script.cpp | 8 ++++---- engines/sci/engine/segment.cpp | 18 +++++++++--------- engines/sci/engine/segment.h | 32 ++++++++++++++++---------------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index aa3fbc995a1..9bbb7738e93 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -193,7 +193,7 @@ void SegManager::scriptInitialiseLocals(reg_t location) { 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)); @@ -206,10 +206,10 @@ void SegManager::scriptRelocateExportsSci11(SegmentId seg) { /* 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)); + uint16 location = READ_SCI11ENDIAN_UINT16(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); + WRITE_SCI11ENDIAN_UINT16(scr->_exportTable + i, location + scr->_heapStart - scr->_buf); } else { // Otherwise it's probably a function export, // and we don't need to do anything. @@ -219,7 +219,7 @@ void SegManager::scriptRelocateExportsSci11(SegmentId seg) { 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) { diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index c43c195e6b8..02d3a8987b7 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -362,8 +362,8 @@ void Script::setLockers(int lockers) { void Script::setExportTableOffset(int offset) { if (offset) { - _exportTable = (const uint16 *)(_buf + offset + 2); - _numExports = READ_SCI11ENDIAN_UINT16((const byte *)(_exportTable - 1)); + _exportTable = (uint16 *)(_buf + offset + 2); + _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1); } else { _exportTable = NULL; _numExports = 0; @@ -380,7 +380,7 @@ uint16 Script::validateExportFunc(int pubfunct) { if (exportsAreWide) pubfunct *= 2; - uint16 offset = READ_SCI11ENDIAN_UINT16((const byte *)(_exportTable + pubfunct)); + uint16 offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct); VERIFY(offset < _bufSize, "invalid export function pointer"); return offset; @@ -538,7 +538,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; } @@ -622,7 +622,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); @@ -640,7 +640,7 @@ 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; } @@ -821,7 +821,7 @@ bool Object::initBaseObject(SegManager *segMan, reg_t addr) { //-------------------- 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; } @@ -860,7 +860,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"); @@ -871,7 +871,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 b3ea80f6657..cbaf2d09d41 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. @@ -194,7 +194,7 @@ public: 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 listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const; virtual void saveLoadWithSerializer(Common::Serializer &ser); @@ -217,14 +217,14 @@ public: reg_t getSpeciesSelector() const { return _variables[_offset]; } void setSpeciesSelector(reg_t value) { _variables[_offset] = value; } - reg_t getSuperClassSelector() const { return _variables[_offset + 1]; } + reg_t getSuperClassSelector() const { return _variables[_offset + 1]; } void setSuperClassSelector(reg_t value) { _variables[_offset + 1] = value; } reg_t getInfoSelector() const { return _variables[_offset + 2]; } - void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; } + void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; } reg_t getNameSelector() const { return _variables[_offset + 3]; } - void setNameSelector(reg_t value) { _variables[_offset + 3] = value; } + void setNameSelector(reg_t value) { _variables[_offset + 3] = value; } reg_t getClassScriptSelector() const { return _variables[4]; } void setClassScriptSelector(reg_t value) { _variables[4] = value; } @@ -233,12 +233,12 @@ public: 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) 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); } /** @@ -261,11 +261,11 @@ public: */ int locateVarSelector(SegManager *segMan, Selector slc) const; - bool isClass() const { return (getInfoSelector().offset & SCRIPT_INFO_CLASS); } + bool isClass() const { return (getInfoSelector().offset & SCRIPT_INFO_CLASS); } const Object *getClass(SegManager *segMan) const; void markAsFreed() { _flags |= OBJECT_FLAG_FREED; } - bool isFreed() const { return _flags & OBJECT_FLAG_FREED; } + bool isFreed() const { return _flags & OBJECT_FLAG_FREED; } void setVarCount(uint size) { _variables.resize(size); } uint getVarCount() const { return _variables.size(); } @@ -326,10 +326,10 @@ public: byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */ - const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */ + 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*/ + const byte *_synonyms; /**< Synonyms block or 0 if not present*/ int _numSynonyms; /**< Number of entries in the synonyms block */ protected: @@ -359,7 +359,7 @@ public: 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) const; virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const; @@ -526,7 +526,7 @@ public: 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 listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const; virtual void saveLoadWithSerializer(Common::Serializer &ser); @@ -685,7 +685,7 @@ public: 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 listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const; virtual void saveLoadWithSerializer(Common::Serializer &ser); @@ -811,8 +811,8 @@ public: // We overload destroy to ensure the string type is 3 after destroying void destroy() { SciArray::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 > { From 947edd08c3b60ec873fcc6c922ef4ebb34ba2305 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 26 May 2010 19:54:50 +0000 Subject: [PATCH 085/249] Replace SCUMM F5 dialog by GMM & add help button to GMM The new "Help" button in the GMM is currently only used by SCUMM. To use it, an engine currently needs to subclass MainMenuDialog. svn-id: r49249 --- engines/dialogs.cpp | 45 +- engines/dialogs.h | 43 +- engines/scumm/dialogs.cpp | 213 +- engines/scumm/dialogs.h | 24 +- engines/scumm/input.cpp | 2 +- engines/scumm/scumm.cpp | 18 +- engines/scumm/scumm.h | 2 - gui/themes/default.inc | 2235 ++++++++--------- gui/themes/scummclassic.zip | Bin 54108 -> 52230 bytes gui/themes/scummclassic/classic_layout.stx | 35 +- .../scummclassic/classic_layout_lowres.stx | 42 +- gui/themes/scummmodern.zip | Bin 159866 -> 158221 bytes gui/themes/scummmodern/scummmodern_layout.stx | 35 +- .../scummmodern/scummmodern_layout_lowres.stx | 35 +- 14 files changed, 1177 insertions(+), 1552 deletions(-) diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp index 73ba591b4b8..954bc814708 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 6bee7c5fb18..6e5338b3171 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; @@ -38,6 +37,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/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 1f153094c1e..d9c24ddca24 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,220 +245,28 @@ 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' -}; +#ifndef DISABLE_HELP 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 + : 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); + MainMenuDialog::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(); - } -} - -#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 { diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h index 7889027dcf1..41a8ec83c13 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/input.cpp b/engines/scumm/input.cpp index 8a9570f5342..dc3a5d26b38 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.cpp b/engines/scumm/scumm.cpp index 2359d4a04fc..bb50ce7bb2e 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 885ab790deb..42322ba5a22 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/gui/themes/default.inc b/gui/themes/default.inc index 75c4fb73deb..edf116b79ca 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -1,4 +1,1089 @@ "" +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " " " " " " " @@ -536,6 +1621,10 @@ "width='120' " "height='12' " "/> " +" " " " " " " " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " +" " " " " " " " " " " " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip index 9733c7a97eb886d8b2bfc100c4133de300434fa6..cd397e64eda906fd6873b2cbb319ba7c814f4148 100644 GIT binary patch delta 1477 zcmd6n?Mob26vk)Voqcn6W_KNBO|m*h)AgllqE-m5I!aK2WL=cBP+d())!o&oi53(> zti{+Gx<&h#m`bgdHAaIeHkY=v6dM!rp(!OB`=Nx|;3rE7B|<4BX%ag#?u+&>=pC5* z%sJ1!%suzVS({T0UsjpiH7Yev$>WQelrdAiiD?KplTK{hRcBC?n!JDgHpDtoZf57M-`-F>}X8{=EG&BZ&m^@cYxcq{z00#c!N0vFFTU zJw+|nlb>GwJ+>h_8a@TrcnFV}Y;-gRu&&{V!P84))sp};l`8WEEsv*7m5QFy*@&-s z4}&A=7CdheU}jBWoeCGrMfC@)C9GLY4X|JjvlwjghhsTW-^Uyq)oYwFx+dUH!yj2z zl$aBd%4^Z!t3h*{5ua4@_||+2KVIF36W(cbm#NV`Cwo&#mG1zJ(PPO>K<@cB z;}o%e>ODplC@ zo<#!hT%yeeK`#wK9=-kDEu|2zza%+X_=lWuxHx$7UdE9Hv%b_(akAIf)#iidf6s714()N$;M?rvXa+s?EW(-Q_b^NT_DS~QBqf&2M9`n?Ar4C}GrjmKKP z9=&TlWWljY&U*!k^6DbVwScroI`J--3fBYPml$lD`2S`vLo*`KZ? z?XOHmb$Ri;q&diEiRFtz<)!MLLMJ zJd%S5SKmq=1T8e0GZSxI8IxUBGCRl1*I~sE^IPyP94ErHW)&*~+Hra7k*AKLJawOU zZpQc|` zB&>PUcQS=4pTust2G4@=n6++TB{2~L!Q2R9QfZelvp17G=C820xtK=2N>4ESuQ9>$ zaP&xI=%Dex$TX4Kf^nmKtr#6YirNAVsVV=GmM(V^$81JRHWibrTIhA zhNg-QY-MQ>nhap`oKY?cgtxSq>NVn2bs=ur8FH@5sg2-)2f;J=XD*kVcU93lN^T`; z_cMhT36n#ZIWnQEwJqBl2WJSFuj^w*w)&Y*VEhQu8A$!-To-bs`T3J n*X-cC8Te~e5OyO-QOUbZC;RZ(s-0&va#SrnPo(+pyYkn+&pi}s delta 2808 zcmd^BTTGNk6yATYEXxm4)`b;hhYDE~*(;zR5YQkhg>q56l)5a-vb$y33;QpwwGmAt zSnH*FV(UYdm{tu^Tj(_2Xa%gbX>8JJnwT`!>WfX&*z}<-1)f|uwj!F3BEr&qVkOqA|!{tGxcEF*T-v*txq9~+#FjEWd$t!)~^E8zaB;_n&IA&Y;4?rDqc*i z-`$o08!PWa+2uT3v*v3CuAE4L+I3g)l@sga87LMJ7fM7wZhOF4qF)*2IKNMiXc)#) z1m$%t#LM1OD@c2{PD|Q5r=E_Pgmv{=F^Yw;dbK>@@wxP~VB6^mVlh&myp*>fYd-FU zx}n~b#i4-R;iOJ~uV2tS7lUn{R+p1QK6?j={MmLP>VI@HnOSlW4XbEQao?F_h6G6y zx$BGymT#~@!e_}acs7V1^~c3AN;teJ3A)Q<7@e1iVX#Mr{TE9aWdps4)pm~$#zJXO zcHRi112Wi_Hy@6-X!Mm{e~aB4G6?xJZ1l8pZau$ErQ7Loxj9sV^yWOc)3QKp(L z0|^fGT+NO|Qpq7oq1`cWt|rtIV}VhJVXhX`N!G9Kk0iDehB8`Ygbn@39~ATfH`n9n1;7r`<7vpxa9hW zQq2Tgy+vp$^`q1BeT1g=HR8U^?GUOjZLRlsmV6)8WJ zRG_|#8hkKs2RRq&2x>fRjrcWGf za8EygbX>S0UPy8}l%9PKMjOxZnM;S}fh|PZ4=dk6q|Od+%8shx+neKrl%_-W@l^Qo z{TlN3l>jwcynt*m_~F)e@#Lw=aKOGo%-`0;3u+i~gm@-C)T*Pa8LuTv|AvZL&_`0> zK}(`Ie}ZOJ{8Vftk>^kp(NUPmC)}7dfk@Xly#b&QRTF4UF>57hUD(4Bojf4``Qv1S z)7tJT2x>p3hIk*)`YNwWAxXI8TSUXIYtq24S5#}LDD%>RPP9S?@=4CP9KC@mXJnORHerTR_?$>I X!O_u7)K + - - - - - - - - - - - - - - - - + diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx index c8ecb1abaf4..cd406ca987c 100644 --- a/gui/themes/scummclassic/classic_layout_lowres.stx +++ b/gui/themes/scummclassic/classic_layout_lowres.stx @@ -588,6 +588,10 @@ width = '120' height = '12' /> + - - - - - - - - - - - - - - - - + rYfy5WjQx#V-4V-DN@0g{nXVst6Pi5TT0r){4=UMi7wFx{m->5kX1QT8q|| ziHtQuF(GZbK?1$4S7BQTZH$R+qpeM>exZ%_Ltom~HmzUixtE75@gL|(PVSwV-^`sm z=Qn2_k7-Zb(i%3cRVb~Tv_9^cd&;mynX|x^E2LaWQSgCJ1k3IWg{&E@a_JS<7Wjk_ z{buC^#%77K^MUN6IlDm2*~M=$>ZT$EvIW=ZSh0acT=sSR-=Ax9IZi9&B>t=jo3C@G zI_H;G3*Rov&9dtHhVr~IcaPpF<2Y&CSsFB`1G`wQhMP~&^otJ8)5&lUFxRt)yn0aM zUmg<$^!xko)vDp(t76Vi;AxG>pz#70>ZzP4AAOV;7ta#9C6?d56PZj-cgD4!h ztfGD!=xBKom}p=PD8oxC-8Dt~8XLWy#1KqTh&1VuXlHIuiR89}B}AWr6$gwVnu!Q# zKA;a#XM}IwSJ(Ko1j6WA5=2wse6Zoz;Rw1P1r6wbSA`>&OrqBTEr1p6O5Auh14laa z=xH`$VXubPXTvr;d|8FxHJ9L~78Cs&1G{itFn$tg5QB5zA?J# z$b|a}rgl97B`$6m7fDxfCH$)W`CO`izgSuF_4j8b_`DE zZ0gQ~W3u9(uJS2topcfjOgm5X6+pOBwx{;iF}sO=EP&_H>`xL~i=ja}PKT&l1<5=X z1|q4o1fsF$0|)h$Krt=e!OAh-r=jdpSkD-!>IhgUuLO2dS}AKU=Bh6CdiK=S;`hN= zI4XS zb-5r+WKkYWsP+$)qw|oO?zx}~UmZ44+D=%7*N3gri z;pR`pFL0c+ zges|dLty~ks+b;PbjHo6JEbwU=e0+zY6ZthTQ7~c$<^Cd#!-)#k6{7miieNoUsquK zZmW6I+9#2u0Q8lck0}~fb6nNF`UY=(+HSXRCWZ~f+>}G7&MZ`NoV3kTUtrJPw&=(y zKN|D$b~&ZYl{XeXuyLHUjUi}v6jey61hOg5$H&IJnaXi{y|v!i-(>cnmycE4TLyI3 z%g>1qnX+usvae3B-nOfUfx0}rGvR5ob_&#JU(3LkG($JX-9^FQ(Pz19E# delta 3106 zcmd^Bd2Ezb5dUWOV%yzzYnN@Q?eg`o73g-iEvVgI0v;$r4+CmZ+NE8)Rd%=TQ4cgg zyl)!~qX|Zu5N}az%u6(Ziixq{g-6sNSQQNjR?!%hfH?2l9=nC8G4U^V^L_8Vx!%m1 z`F?Ni|HyoF#B6O|tkc^S`McsKd%v|+AH3`0n!#aXn?<+jx$t0Vc8fkiT9cFGu(C{T zZPCVMFMAc`WwCcH9MY}zs)1OnH|lk}qn+_!urF8vrfyG>mkj&udWv9K!MzZJY^;crh4_Uq>A z@RH}nqn&t%?)34K_{n@<-Bo*njk(JeMLq?JLIXYM6c^cWw{FFM7%-LFupm7tMvZWW zDx<2N5>-{Tx4JSZDza{a5^;eYZI`?Ydjp2B#f#)F|{`#`g#pn`Tg~Yiuh!>ji9-u}u8uUwiJt2DE%JtOVinC}#2imCYd$7^( zzk`*Qzs)g!dl0fHeGyv8+=7`@(S+#<#s#~>=ooi#5}+hHf7MJ9!+KFMb|^JkT^> z=hUh@pvYjBXGcC>Z*ZVpT(bjyHpqH^i$5LfPRO)f683dn=nMMCD_ycyCM0rr_+uEH zG=@6NnIMfp&KPOaFkG0TGkbEyyqZ)58dpLrCDq5k@W4zgqsDK*M6(XTVy(uF=agyS zu%7Wt^zMQ+z@>iOyHKLzfMm_j6bu<>$S))-9Tz0NgMHNdDFbQ8elGC`OE6tL{T}=w z6UzxV-+bYc{)r^ZTbppL!J%B;c>$PvSP;Y+SO z&7jyh0t+WBxW0id9eeZtfhb~#%Fxm#IBm|PRJ8m8PVv-X$dG3*7i3w0E9k`MP)tkm z7-l*~IiX{$iiOyg%4#Fqd8m%_m!5}LPUUmDrjhjsS9`*UIR6M(I2D37i|d%Ef#Sa3 zU>52bxYMZ6gLXRi805&C%|yqVFpJh5g@qF+l|{Cru!1f-27|2bGGk6EdU~mS7i3Na zPPYdQFpr=GbN&`OlV$%EcqSW2flqk~(qm%mTuv|g&_baf_<*>2D`f*v$8d&Fcp(l|`dY!$~E#0BeNB~bSJjLylWXWR$*}i5|Zx7m} f^1ZBFtjJ|B~W diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx index 2fd14f37aa0..25add374621 100644 --- a/gui/themes/scummmodern/scummmodern_layout.stx +++ b/gui/themes/scummmodern/scummmodern_layout.stx @@ -595,6 +595,10 @@ width = '150' height = 'Globals.Button.Height' /> + - - - - - - - - - - - - - - - - + diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx index e837e41e826..9804e264344 100644 --- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx +++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx @@ -584,6 +584,10 @@ width = '120' height = 'Globals.Button.Height' /> + - - - - - - - - - - - - - - - - + Date: Wed, 26 May 2010 20:48:08 +0000 Subject: [PATCH 086/249] SCI: fixing kReadNumber to behave like in sierra sci (non standard atoi implementation) - fixes big door not unlocking in sq4 svn-id: r49250 --- engines/sci/engine/kstring.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 426c682e119..d7fa23116bb 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -138,10 +138,28 @@ 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) { + result *= 10; + if ((*source < '0') || (*source > '9')) + error("Invalid character in kReadNumber input"); + result += *source - 0x30; + source++; + } + } + + return make_reg(0, result); } From 2c2a1fa1ba9c4da4f955f341a8710b9cb40ede7e Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 26 May 2010 22:05:51 +0000 Subject: [PATCH 087/249] Made _k_new_node() a method of the segment manager, and fixed a bug with the rarely used SCI0 kernel function kSort in the process (_k_new_node was called with key, value instead of value, key inside kSort) svn-id: r49251 --- engines/sci/engine/klists.cpp | 26 ++++---------------------- engines/sci/engine/seg_manager.cpp | 10 ++++++++++ engines/sci/engine/seg_manager.h | 8 ++++++++ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp index c04454ca3db..7fefccd9d76 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)); @@ -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); } diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index e0b6e75d702..a8f46213eca 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -523,6 +523,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 e8bbdbdb3f3..24d3f3fc1cc 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -214,6 +214,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 From 7f678907d7067d3747d69e4564f64e6c1d5adc24 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 27 May 2010 02:15:11 +0000 Subject: [PATCH 088/249] Add some null checking when pausing/resuming videos. svn-id: r49254 --- engines/mohawk/video.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index beef3128760..deeb5daabf3 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -41,12 +41,14 @@ VideoManager::~VideoManager() { 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() { From 99fc5cbfca3403b07ab023c857b7b997cc9389b4 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 27 May 2010 03:15:24 +0000 Subject: [PATCH 089/249] Add the Mac sync resource type and allow for more than 9 Mac SCI1.1+ data files. svn-id: r49255 --- engines/sci/resource.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 3535e36f772..4bffdd30681 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -574,7 +574,7 @@ int ResourceManager::addAppropriateSources() { #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(); @@ -1478,7 +1478,8 @@ struct { { MKID_BE('HEP '), kResourceTypeHeap }, { MKID_BE('IBIN'), kResourceTypeMacIconBarPictN }, { MKID_BE('IBIS'), kResourceTypeMacIconBarPictS }, - { MKID_BE('PICT'), kResourceTypeMacPict } + { MKID_BE('PICT'), kResourceTypeMacPict }, + { MKID_BE('SYN '), kResourceTypeSync } }; static uint32 resTypeToMacTag(ResourceType type) { From f7ba7b4684c86546151928cf5de669af04d237c1 Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Thu, 27 May 2010 06:11:50 +0000 Subject: [PATCH 090/249] PSP: fixed issue with handling of EOS. Caused crashes. svn-id: r49257 --- backends/fs/psp/psp-stream.cpp | 100 ++++++++++++++++++++++----------- backends/fs/psp/psp-stream.h | 1 + 2 files changed, 67 insertions(+), 34 deletions(-) diff --git a/backends/fs/psp/psp-stream.cpp b/backends/fs/psp/psp-stream.cpp index d3d6311836c..9bcbe9d7cf8 100644 --- a/backends/fs/psp/psp-stream.cpp +++ b/backends/fs/psp/psp-stream.cpp @@ -35,15 +35,37 @@ #define MIN2(a,b) ((a < b) ? a : b) #define MIN3(a,b,c) ( (a < b) ? (a < c ? a : c) : (b < c ? b : c) ) -//#define __PSP_PRINT_TO_FILE__ -//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ +//#define __PSP_PRINT_TO_FILE__ /* For debugging suspend stuff, we have no screen output */ +//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ //#define __PSP_DEBUG_PRINT__ /* For debug printouts */ + #include "backends/platform/psp/trace.h" +//#define DEBUG_BUFFERS /* to see the contents of the buffers being read */ + +#ifdef DEBUG_BUFFERS +void printBuffer(byte *ptr, uint32 len) { + uint32 printLen = len <= 10 ? len : 10; + + for (int i = 0; i < printLen; i++) { + PSP_INFO_PRINT("%x ", ptr[i]); + } + + if (len > 10) { + PSP_INFO_PRINT("... "); + for (int i = len - 10; i < len; i++) + PSP_INFO_PRINT("%x ", ptr[i]); + } + + PSP_INFO_PRINT("\n"); +} +#endif + + PSPIoStream::PSPIoStream(const Common::String &path, bool writeMode) : StdioStream((void *)1), _path(path), _writeMode(writeMode), _ferror(false), _pos(0), - _physicalPos(0), _fileSize(0), _inCache(false), + _physicalPos(0), _fileSize(0), _inCache(false), _eos(false), _cacheStartOffset(-1), _cache(0), _errorSuspend(0), _errorSource(0), _errorPos(0), _errorHandle(0), _suspendCount(0) { @@ -102,6 +124,7 @@ void *PSPIoStream::open() { bool PSPIoStream::err() const { DEBUG_ENTER_FUNC(); + if (_ferror) // We dump since no printing to screen with suspend PSP_ERROR("mem_ferror[%d], source[%d], suspend error[%d], pos[%d], \ _errorPos[%d], _errorHandle[%p], suspendCount[%d]\n", @@ -116,7 +139,7 @@ void PSPIoStream::clearErr() { } bool PSPIoStream::eos() const { - return (_pos >= _fileSize); + return _eos; } int32 PSPIoStream::pos() const { @@ -129,8 +152,8 @@ int32 PSPIoStream::size() const { bool PSPIoStream::seek(int32 offs, int whence) { DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT_FUNC("offset[%d], whence[%d], _pos[%d], _physPos[%d]\n", offs, whence, _pos, _physicalPos); - bool success = true; + PSP_DEBUG_PRINT_FUNC("offset[0x%x], whence[%d], _pos[0x%x], _physPos[0x%x]\n", offs, whence, _pos, _physicalPos); + _eos = false; int32 posToSearchFor = 0; switch (whence) { @@ -144,43 +167,44 @@ bool PSPIoStream::seek(int32 offs, int whence) { posToSearchFor += offs; // Check for bad values - if (posToSearchFor < 0 || posToSearchFor > _fileSize) { + if (posToSearchFor < 0) { _ferror = true; return false; } + if (posToSearchFor > _fileSize) { + _ferror = true; + _eos = true; + return false; + } + // See if we can find it in cache if (isOffsetInCache(posToSearchFor)) { - PSP_DEBUG_PRINT("seek offset[%d] found in cache. Cache starts[%d]\n", posToSearchFor, _cacheStartOffset); + PSP_DEBUG_PRINT("seek offset[0x%x] found in cache. Cache starts[0x%x]\n", posToSearchFor, _cacheStartOffset); _inCache = true; } else { // not in cache _inCache = false; } _pos = posToSearchFor; - return success; + return true; } -// for debugging -/* -void printBuffer(byte *ptr, uint32 len) { - for (int i = 0; i < len; i++) { - PSP_INFO_PRINT("%x ", *ptr); - ptr++; - } - PSP_INFO_PRINT("\n"); -}*/ - uint32 PSPIoStream::read(void *ptr, uint32 len) { DEBUG_ENTER_FUNC(); - PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d], ptr[%p]\n", _path.c_str(), len, ptr); + PSP_DEBUG_PRINT_FUNC("filename[%s], len[0x%x], ptr[%p]\n", _path.c_str(), len, ptr); + if (_ferror || _eos) + return 0; + byte *destPtr = (byte *)ptr; uint32 lenFromFile = len; // how much we read from the actual file uint32 lenFromCache = 0; // how much we read from cache uint32 lenRemainingInFile = _fileSize - _pos; - if (lenFromFile > lenRemainingInFile) + if (lenFromFile > lenRemainingInFile) { lenFromFile = lenRemainingInFile; + _eos = true; + } // Are we in cache? if (_inCache && isCacheValid()) { @@ -188,7 +212,7 @@ uint32 PSPIoStream::read(void *ptr, uint32 len) { // We can read at most what's in the cache or the remaining size of the file lenFromCache = MIN2(lenFromFile, CACHE_SIZE - offsetInCache); // unsure - PSP_DEBUG_PRINT("reading %d bytes from cache to %p. pos[%d] physPos[%d] cacheStart[%d]\n", lenFromCache, destPtr, _pos, _physicalPos, _cacheStartOffset); + PSP_DEBUG_PRINT("reading 0x%x bytes from cache to %p. pos[0x%x] physPos[0x%x] cacheStart[0x%x]\n", lenFromCache, destPtr, _pos, _physicalPos, _cacheStartOffset); memcpy(destPtr, &_cache[offsetInCache], lenFromCache); _pos += lenFromCache; @@ -198,8 +222,10 @@ uint32 PSPIoStream::read(void *ptr, uint32 len) { lenRemainingInFile -= lenFromCache; // since we moved pos destPtr += lenFromCache; } else { // we're done - // debug - //if (len < 10) printBuffer((byte *)ptr, len); +#ifdef DEBUG_BUFFERS + printBuffer((byte *)ptr, len); +#endif + return lenFromCache; // how much we actually read } } @@ -214,11 +240,11 @@ uint32 PSPIoStream::read(void *ptr, uint32 len) { // This optimization is based on the principle that reading 1 byte is as expensive as 1000 bytes uint32 lenToCopyToCache = MIN2((uint32)MIN_READ_SIZE, lenRemainingInFile); // at most remaining file size - PSP_DEBUG_PRINT("filling cache with %d bytes from physicalPos[%d]. cacheStart[%d], pos[%d], fileSize[%d]\n", lenToCopyToCache, _physicalPos, _cacheStartOffset, _pos, _fileSize); + PSP_DEBUG_PRINT("filling cache with 0x%x bytes from physicalPos[0x%x]. cacheStart[0x%x], pos[0x%x], fileSize[0x%x]\n", lenToCopyToCache, _physicalPos, _cacheStartOffset, _pos, _fileSize); size_t ret = fread(_cache, 1, lenToCopyToCache, (FILE *)_handle); if (ret != lenToCopyToCache) { - PSP_ERROR("in filling cache, failed to get %d bytes. Only got %d\n", lenToCopyToCache, ret); + PSP_ERROR("in filling cache, failed to get 0x%x bytes. Only got 0x%x\n", lenToCopyToCache, ret); _ferror = true; clearerr((FILE *)_handle); } @@ -227,21 +253,21 @@ uint32 PSPIoStream::read(void *ptr, uint32 len) { _physicalPos += ret; - PSP_DEBUG_PRINT("copying %d bytes from cache to %p\n", lenFromFile, destPtr); + PSP_DEBUG_PRINT("copying 0x%x bytes from cache to %p\n", lenFromFile, destPtr); // Copy to the destination buffer from cache memcpy(destPtr, _cache, lenFromFile); _pos += lenFromFile; } else { // Too big for cache. No caching - PSP_DEBUG_PRINT("reading %d bytes from file to %p. Pos[%d], physPos[%d]\n", lenFromFile, destPtr, _pos, _physicalPos); + PSP_DEBUG_PRINT("reading 0x%x bytes from file to %p. Pos[0x%x], physPos[0x%x]\n", lenFromFile, destPtr, _pos, _physicalPos); size_t ret = fread(destPtr, 1, lenFromFile, (FILE *)_handle); _physicalPos += ret; // Update pos _pos = _physicalPos; if (ret != lenFromFile) { // error - PSP_ERROR("fread returned [%d] instead of len[%d]\n", ret, lenFromFile); + PSP_ERROR("fread returned [0x%x] instead of len[0x%x]\n", ret, lenFromFile); _ferror = true; clearerr((FILE *)_handle); _errorSource = 4; @@ -251,8 +277,10 @@ uint32 PSPIoStream::read(void *ptr, uint32 len) { PowerMan.endCriticalSection(); - // debug - //if (len < 10) printBuffer((byte *)ptr, len); +#ifdef DEBUG_BUFFERS + printBuffer((byte *)ptr, len); +#endif + return lenFromCache + lenFromFile; // total of what was copied } @@ -281,8 +309,12 @@ uint32 PSPIoStream::write(const void *ptr, uint32 len) { if (PowerMan.beginCriticalSection() == PowerManager::Blocked) PSP_DEBUG_PRINT_FUNC("Suspended\n"); - PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d]\n", _path.c_str(), len); + PSP_DEBUG_PRINT_FUNC("filename[%s], len[0x%x]\n", _path.c_str(), len); + if (_ferror) + return 0; + + _eos = false; // we can't have eos with write synchronizePhysicalPos(); size_t ret = fwrite(ptr, 1, len, (FILE *)_handle); @@ -300,7 +332,7 @@ uint32 PSPIoStream::write(const void *ptr, uint32 len) { clearerr((FILE *)_handle); _pos = ftell((FILE *)_handle); // Update pos _errorSource = 5; - PSP_ERROR("fwrite returned[%d] instead of len[%d]\n", ret, len); + PSP_ERROR("fwrite returned[0x%x] instead of len[0x%x]\n", ret, len); } PowerMan.endCriticalSection(); @@ -320,7 +352,7 @@ bool PSPIoStream::flush() { _ferror = true; clearerr((FILE *)_handle); _errorSource = 6; - PSP_ERROR("fflush returned ret[%u]\n", ret); + PSP_ERROR("fflush returned ret[%d]\n", ret); } PowerMan.endCriticalSection(); diff --git a/backends/fs/psp/psp-stream.h b/backends/fs/psp/psp-stream.h index 10d5016852a..9fd1ad0470f 100644 --- a/backends/fs/psp/psp-stream.h +++ b/backends/fs/psp/psp-stream.h @@ -41,6 +41,7 @@ protected: int _physicalPos; // position in the real file int _pos; // position. Sometimes virtual bool _inCache; // whether we're in cache (virtual) mode + bool _eos; // EOS flag enum { SuspendError = 2, From 5f53683cab48becc1d790132cc46ff29a1a3ae26 Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Thu, 27 May 2010 06:21:37 +0000 Subject: [PATCH 091/249] PSP: fixed a screen shake bug svn-id: r49258 --- backends/platform/psp/display_client.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/backends/platform/psp/display_client.cpp b/backends/platform/psp/display_client.cpp index 90c41e796d6..c5a62501880 100644 --- a/backends/platform/psp/display_client.cpp +++ b/backends/platform/psp/display_client.cpp @@ -686,17 +686,18 @@ void GuRenderer::fillVertices(Vertex *vertices) { uint32 gapX = _useGlobalScaler ? (PSP_SCREEN_WIDTH - outputWidth) >> 1 : 0; uint32 gapY = _useGlobalScaler ? (PSP_SCREEN_HEIGHT - outputHeight) >> 1 : 0; + // Save scaled offset on screen + float scaledOffsetOnScreenX = scaleSourceToOutputX(_offsetOnScreen.x); + float scaledOffsetOnScreenY = scaleSourceToOutputY(_offsetOnScreen.y); + float imageStartX, imageStartY, imageEndX, imageEndY; - imageStartX = gapX + (scaleSourceToOutputX(_maxTextureOffset.x)); - imageStartY = gapY; - - imageStartX += scaleSourceToOutputX(_offsetOnScreen.x); - imageStartY += scaleSourceToOutputY(_offsetOnScreen.y); + imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutputX(_maxTextureOffset.x)); + imageStartY = gapY + scaledOffsetOnScreenY; if (_fullScreen) { // shortcut - imageEndX = PSP_SCREEN_WIDTH - gapX; - imageEndY = PSP_SCREEN_HEIGHT - gapY; + imageEndX = PSP_SCREEN_WIDTH - gapX + scaledOffsetOnScreenX; + imageEndY = PSP_SCREEN_HEIGHT - gapY + scaledOffsetOnScreenY; // needed for screen shake } else { /* !fullScreen */ imageEndX = imageStartX + scaleSourceToOutputX(_drawSize.width); imageEndY = imageStartY + scaleSourceToOutputY(_drawSize.height); From 739f551852b428115f2cd2bca4f7a0a1054b79a8 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 27 May 2010 07:50:23 +0000 Subject: [PATCH 092/249] Slight formatting, and added a note that audio36 and sync36 resource patches were introduced in SCI2, and didn't exist in SCI0-SCI1.1 svn-id: r49259 --- engines/sci/resource.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 4bffdd30681..0b985ea67cb 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1242,9 +1242,9 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, 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; @@ -1254,6 +1254,7 @@ void ResourceManager::readResourcePatches(ResourceSource *source) { for (int i = kResourceTypeView; i <= kResourceTypeRobot; ++i) { // TODO: add support for audio36 and sync36 files + // Such patches were introduced in SCI2, and didn't exist in SCI0-SCI1.1 if (i == kResourceTypeAudio36 || i == kResourceTypeSync36) continue; From e5eaf3ee5578367cc74c3155a68a904e6ce77b9b Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 27 May 2010 08:09:32 +0000 Subject: [PATCH 093/249] Split all of the audio-related functions of the resource manager in a separate file svn-id: r49260 --- engines/sci/module.mk | 1 + engines/sci/resource.cpp | 679 ------------------------------- engines/sci/resource.h | 16 +- engines/sci/resource_audio.cpp | 701 +++++++++++++++++++++++++++++++++ 4 files changed, 716 insertions(+), 681 deletions(-) create mode 100644 engines/sci/resource_audio.cpp diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 26ae1c16b1a..a2cfd38f951 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 \ diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 0b985ea67cb..89b7a5b7e29 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 @@ -270,36 +257,6 @@ 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) { // 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) @@ -341,70 +298,6 @@ bool ResourceManager::loadFromPatchFile(Resource *res) { 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; -} - Common::File *ResourceManager::getVolumeFile(const char *filename) { Common::List::iterator it = _volumeFiles.begin(); Common::File *file; @@ -695,36 +588,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::iterator it = _sources.begin(); it != _sources.end(); ++it) { ResourceSource *source = *it; @@ -1295,49 +1158,6 @@ void ResourceManager::readResourcePatches(ResourceSource *source) { } } -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; Resource *res; @@ -1558,261 +1378,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::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 @@ -2367,248 +1932,4 @@ Common::String ResourceManager::findSierraGameId() { #undef READ_UINT16 -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; - - _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/resource.h b/engines/sci/resource.h index 8e83ed7bf08..dbd99f633d3 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" @@ -121,7 +122,18 @@ 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: diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp new file mode 100644 index 00000000000..5dea36bb07d --- /dev/null +++ b/engines/sci/resource_audio.cpp @@ -0,0 +1,701 @@ +/* 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::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::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; +} + +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::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()); + } + } +} + +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::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; + + 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; + + _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 From cfed70df07781327effb6c5eb3d87b29ef0f34da Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Thu, 27 May 2010 11:26:37 +0000 Subject: [PATCH 094/249] SCI: fixing resuming samples - fixes hang when ship is flying away happening when you entered menu during that sequence svn-id: r49261 --- engines/sci/sound/music.cpp | 7 ++++++- engines/sci/sound/soundcmd.cpp | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index a623c0b4d23..2b203af93e9 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -387,7 +387,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) { diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 40e36373720..45d9302354d 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -828,7 +828,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); From 5f5dcbad47c3f120541c59a141e84bb8aed5184d Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 27 May 2010 12:00:20 +0000 Subject: [PATCH 095/249] Added an explanation for audio36 and sync36 external patches svn-id: r49262 --- engines/sci/resource.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 89b7a5b7e29..cc3a2b0d1ab 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1109,6 +1109,14 @@ void ResourceManager::readResourcePatches(ResourceSource *source) { // this function tries to read patch file with any supported naming scheme, // regardless of s_sciVersion value + // Note that audio36 and sync36 use a different naming scheme, because they cannot be described + // with a single resource number, but are a result of a 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 + Common::String mask, name; Common::ArchiveMemberList files; int number = -1; From 453d13dc2d2bec3a4d7cc4395bf98bd2103c5ff8 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Thu, 27 May 2010 17:41:20 +0000 Subject: [PATCH 096/249] SCI: fixing -propDict- selector on instances to contain -propDict- of the corresponding class - fixes sq4cd/room 381 talk-clicking on robot - thx to waltervn & wjp svn-id: r49263 --- engines/sci/engine/script.cpp | 10 ++++++++++ engines/sci/engine/segment.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 9bbb7738e93..e0bcd632cc9 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -256,6 +256,16 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { 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 diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index cbaf2d09d41..44bf6569b69 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -226,6 +226,9 @@ public: reg_t getNameSelector() const { return _variables[_offset + 3]; } void setNameSelector(reg_t value) { _variables[_offset + 3] = value; } + 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; } From 845c34ee4561b54389437009e449a16b4fb872d4 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Thu, 27 May 2010 17:43:06 +0000 Subject: [PATCH 097/249] SCI: removing tab from vo output (debug console) svn-id: r49264 --- engines/sci/console.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 8dbf297f554..51aa1a59d07 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -3060,7 +3060,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; } From a32b7b38518dd662304a2645bfe4288b18522183 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 27 May 2010 17:47:32 +0000 Subject: [PATCH 098/249] Fix starting GK1. svn-id: r49265 --- engines/sci/engine/kernel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 49266f3a184..55279399503 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -336,7 +336,7 @@ SciKernelFunction kfunct_mappers[] = { 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, ".*"), From a03b5a3434a274447deaa9963ca6df87ee213059 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 27 May 2010 19:34:12 +0000 Subject: [PATCH 099/249] GUI: Reduce code duplication in about dialog svn-id: r49266 --- gui/about.cpp | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/gui/about.cpp b/gui/about.cpp index 74851caf941..6f0f0f8d4aa 100644 --- a/gui/about.cpp +++ b/gui/about.cpp @@ -83,29 +83,6 @@ AboutDialog::AboutDialog() int i; - const int screenW = g_system->getOverlayWidth(); - const int screenH = g_system->getOverlayHeight(); - - _xOff = g_gui.xmlEval()->getVar("Globals.About.XOffset", 5); - _yOff = g_gui.xmlEval()->getVar("Globals.About.YOffset", 5); - int outerBorder = g_gui.xmlEval()->getVar("Globals.About.OuterBorder"); - - _w = screenW - 2 * outerBorder; - _h = screenH - 2 * outerBorder; - - _lineHeight = g_gui.getFontHeight() + 3; - - // Heuristic to compute 'optimal' dialog width - int maxW = _w - 2*_xOff; - _w = 0; - for (i = 0; i < ARRAYSIZE(credits); i++) { - int tmp = g_gui.getStringWidth(credits[i] + 5); - if (_w < tmp && tmp <= maxW) { - _w = tmp; - } - } - _w += 2*_xOff; - for (i = 0; i < 1; i++) _lines.push_back(""); @@ -151,10 +128,6 @@ AboutDialog::AboutDialog() for (i = 0; i < ARRAYSIZE(credits); i++) addLine(credits[i]); - - // Center the dialog - _x = (screenW - _w) / 2; - _y = (screenH - _h) / 2; } void AboutDialog::addLine(const char *str) { @@ -294,6 +267,7 @@ void AboutDialog::handleKeyUp(Common::KeyState state) { void AboutDialog::reflowLayout() { Dialog::reflowLayout(); + int i; const int screenW = g_system->getOverlayWidth(); const int screenH = g_system->getOverlayHeight(); @@ -309,7 +283,7 @@ void AboutDialog::reflowLayout() { // Heuristic to compute 'optimal' dialog width int maxW = _w - 2*_xOff; _w = 0; - for (int i = 0; i < ARRAYSIZE(credits); i++) { + for (i = 0; i < ARRAYSIZE(credits); i++) { int tmp = g_gui.getStringWidth(credits[i] + 5); if (_w < tmp && tmp <= maxW) { _w = tmp; @@ -317,8 +291,7 @@ void AboutDialog::reflowLayout() { } _w += 2*_xOff; - _lineHeight = g_gui.getFontHeight() + 3; - + // Center the dialog _x = (screenW - _w) / 2; _y = (screenH - _h) / 2; } From b99d65e561d1940c5644b6c9d4e27af1c0a56923 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 27 May 2010 19:34:41 +0000 Subject: [PATCH 100/249] Fix for bug #3007656: "GMM: Crash in 320x200" svn-id: r49267 --- gui/themes/default.inc | 2 +- gui/themes/scummclassic.zip | Bin 52230 -> 52242 bytes .../scummclassic/classic_layout_lowres.stx | 2 +- gui/themes/scummmodern.zip | Bin 158221 -> 158233 bytes .../scummmodern/scummmodern_layout_lowres.stx | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gui/themes/default.inc b/gui/themes/default.inc index edf116b79ca..93897a7d880 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -1598,7 +1598,7 @@ " " " " " " -" " +" " "3C-ptjzZT?y-TVw_?Fl277s(5e9Vx*&BG&y&hIHy8!L1J=dUb^k% d3#%n2?>oe{dHyyrQB*CH51qDSV?NCQ1OSvxAHx6u delta 83 zcmbO3CA+9yMY;tD&e;pgdzyQLM43i(8mfk$8;=Ju-xy@{o^S6mk4#-!W beBcPz=H1)aM0rs(Og?woj_vy?1|R?cs=p#2 diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx index cd406ca987c..8a0180db3cd 100644 --- a/gui/themes/scummclassic/classic_layout_lowres.stx +++ b/gui/themes/scummclassic/classic_layout_lowres.stx @@ -565,7 +565,7 @@ - + `5+hkq;BIqB?zyQLs3=Gp3W-`fb_Y`2_wBuGNE=Wwy m%uBabH`*TP$D}XKi=ttAZzfX=K)(! delta 121 zcmbPvg|qhxXG06)7A6S+VXig1Y;GxCeB~U>zyQLs3=GrPW-`fb_Y`2_w3{Bl$HX>0 zKc0zyx&S*9&-QvhCSGY?6g|^tW-`U7^dvJe6sIN@C1>a* - + Date: Thu, 27 May 2010 20:29:39 +0000 Subject: [PATCH 101/249] GUI: Fix about dialog regression from my previous commit svn-id: r49268 --- gui/about.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gui/about.cpp b/gui/about.cpp index 6f0f0f8d4aa..8b2f470bf64 100644 --- a/gui/about.cpp +++ b/gui/about.cpp @@ -81,6 +81,8 @@ AboutDialog::AboutDialog() : Dialog(10, 20, 300, 174), _scrollPos(0), _scrollTime(0), _willClose(false) { + reflowLayout(); + int i; for (i = 0; i < 1; i++) From d2513c9cc25c29a2e32882e0617dfc5d5854a6c2 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Thu, 27 May 2010 20:53:37 +0000 Subject: [PATCH 102/249] SCI: enabling fading again, issues in pharkas and gk1demo are actually "normal" - maybe we should add some hack workaround, but the delay in ssci was just slow resource loading svn-id: r49269 --- engines/sci/sound/music.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 2b203af93e9..d8a79852883 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) { @@ -537,12 +534,6 @@ void MusicEntry::doFade() { // Only process MIDI streams in this thread, not digital sound effects if (pMidiParser) { -#ifdef DISABLE_VOLUME_FADING - // Signal fading to stop... - volume = fadeTo; - fadeStep = 0; - fadeCompleted = true; -#endif pMidiParser->setVolume(volume); } From bbaf98127d95f60740ab9db304be2b9854fda9ec Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 27 May 2010 20:59:15 +0000 Subject: [PATCH 103/249] correct typo svn-id: r49270 --- common/stream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/stream.h b/common/stream.h index b6afcd85a93..11041fa3ce8 100644 --- a/common/stream.h +++ b/common/stream.h @@ -156,7 +156,7 @@ public: class ReadStream : virtual public Stream { public: /** - * Returns true if a read failed because the stream has been reached. + * Returns true if a read failed because the stream end has been reached. * This flag is cleared by clearErr(). * For a SeekableReadStream, it is also cleared by a successful seek. */ From 7029b059bfa4bcff3b4be07af407f5c2cadb410b Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Thu, 27 May 2010 21:20:07 +0000 Subject: [PATCH 104/249] SCI: disabling music fading again, but only for sci32 - drivers seem to have issues when fading in on gk1/sierra logo svn-id: r49271 --- engines/sci/sound/music.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index d8a79852883..bfa2c3b3eef 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -531,6 +531,14 @@ void MusicEntry::doFade() { fadeStep = 0; fadeCompleted = true; } +#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) { From b0366e65e593c2b4fa6b5999a5558508d80883f7 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 27 May 2010 23:57:44 +0000 Subject: [PATCH 105/249] Cleanup AVI a bit, add support for stereo audio svn-id: r49279 --- graphics/video/avi_decoder.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/graphics/video/avi_decoder.cpp b/graphics/video/avi_decoder.cpp index f19ca4aa283..4c3c770c60a 100644 --- a/graphics/video/avi_decoder.cpp +++ b/graphics/video/avi_decoder.cpp @@ -154,10 +154,8 @@ void AviDecoder::handleStreamHeader() { sHeader.bufferSize = _fileStream->readUint32LE(); sHeader.quality = _fileStream->readUint32LE(); sHeader.sampleSize = _fileStream->readUint32LE(); - sHeader.frame.left = _fileStream->readSint16LE(); - sHeader.frame.top = _fileStream->readSint16LE(); - sHeader.frame.right = _fileStream->readSint16LE(); - sHeader.frame.bottom = _fileStream->readSint16LE(); + + _fileStream->skip(sHeader.size - 48); // Skip over the remainder of the chunk (frame) if (_fileStream->readUint32BE() != ID_STRF) error("Could not find STRF tag"); @@ -188,11 +186,14 @@ void AviDecoder::handleStreamHeader() { _palette[i * 3 + 2] = _fileStream->readByte(); _palette[i * 3 + 1] = _fileStream->readByte(); _palette[i * 3] = _fileStream->readByte(); - /*_palette[i * 4 + 3] = */_fileStream->readByte(); + _fileStream->readByte(); } _dirtyPalette = true; } + + if (!_vidsHeader.streamHandler) + _vidsHeader.streamHandler = _bmInfo.compression; } else if (sHeader.streamType == ID_AUDS) { _audsHeader = sHeader; @@ -202,6 +203,11 @@ void AviDecoder::handleStreamHeader() { _wvInfo.avgBytesPerSec = _fileStream->readUint32LE(); _wvInfo.blockAlign = _fileStream->readUint16LE(); _wvInfo.size = _fileStream->readUint16LE(); + + // AVI seems to treat the sampleSize as including the second + // channel as well, so divide for our sake. + if (_wvInfo.channels == 2) + _audsHeader.sampleSize /= 2; } } @@ -325,6 +331,9 @@ Surface *AviDecoder::decodeNextFrame() { else flags |= Audio::FLAG_UNSIGNED; + if (_wvInfo.channels == 2) + flags |= Audio::FLAG_STEREO; + _audStream->queueBuffer(data, chunkSize, DisposeAfterUse::YES, flags); _fileStream->skip(chunkSize & 1); // Alignment } else if (getStreamType(nextTag) == 'dc' || getStreamType(nextTag) == 'id' || @@ -396,7 +405,7 @@ PixelFormat AviDecoder::getPixelFormat() const { Audio::QueuingAudioStream *AviDecoder::createAudioStream() { if (_wvInfo.tag == AVI_WAVE_FORMAT_PCM) - return Audio::makeQueuingAudioStream(AUDIO_RATE, false); + return Audio::makeQueuingAudioStream(AUDIO_RATE, _wvInfo.channels == 2); if (_wvInfo.tag != 0) // No sound warning ("Unsupported AVI audio format %d", _wvInfo.tag); From dad3ad86eac7954f0e5e1932b628c68d22e890a8 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Fri, 28 May 2010 09:29:05 +0000 Subject: [PATCH 106/249] SCI: read out vol selector on initSound/playSound for sci1early (soundversion) as well - fixes lsl1demo svn-id: r49285 --- engines/sci/sound/soundcmd.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 45d9302354d..b191e9f2c05 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -304,7 +304,7 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) { 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) + if (_soundVersion >= SCI_VERSION_1_EARLY) newSound->volume = CLIP(GET_SEL32V(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX); // In SCI1.1 games, sound effects are started from here. If we can find @@ -440,7 +440,7 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) { musicSlot->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop)); musicSlot->priority = GET_SEL32V(_segMan, obj, SELECTOR(priority)); - if (_soundVersion >= SCI_VERSION_1_LATE) + if (_soundVersion >= SCI_VERSION_1_EARLY) musicSlot->volume = GET_SEL32V(_segMan, obj, SELECTOR(vol)); _music->soundPlay(musicSlot); From 145eacd491ce54c8c33d80dda2ec3ec3416a3f87 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 28 May 2010 10:17:16 +0000 Subject: [PATCH 107/249] Implemented needed methods for scrolling surfaces horizontally or vertically svn-id: r49286 --- engines/m4/graphics.cpp | 65 +++++++++++++++++++++++++++++++++++++++++ engines/m4/graphics.h | 3 +- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/engines/m4/graphics.cpp b/engines/m4/graphics.cpp index fa0cd7ccd35..66668142899 100644 --- a/engines/m4/graphics.cpp +++ b/engines/m4/graphics.cpp @@ -738,6 +738,71 @@ void M4Surface::madsloadInterface(int index, RGBList **palData) { delete intStream; } +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 6d0a82ad25d..c140140f976 100644 --- a/engines/m4/graphics.h +++ b/engines/m4/graphics.h @@ -173,7 +173,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); }; From bea6ef4beb9ff55a848a76c2b33e32a9b3d9cdd9 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 28 May 2010 10:20:02 +0000 Subject: [PATCH 108/249] Clarified variable usage for sequence list entry indexes svn-id: r49287 --- engines/m4/mads_menus.cpp | 4 +- engines/m4/mads_views.cpp | 106 +++++++++++++++++++++----------------- engines/m4/mads_views.h | 15 +++--- 3 files changed, 68 insertions(+), 57 deletions(-) diff --git a/engines/m4/mads_menus.cpp b/engines/m4/mads_menus.cpp index ff12b699645..d00272d31ee 100644 --- a/engines/m4/mads_menus.cpp +++ b/engines/m4/mads_menus.cpp @@ -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; diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp index 9e16e2a76ed..3b5ba9e24c2 100644 --- a/engines/m4/mads_views.cpp +++ b/engines/m4/mads_views.cpp @@ -59,7 +59,7 @@ void MadsSpriteSlots::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() { @@ -84,10 +84,10 @@ int MadsSpriteSlots::addSprites(const char *resName) { /* * 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; } } @@ -203,6 +203,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 */ @@ -859,10 +869,10 @@ int MadsSequenceList::add(int spriteListIndex, int v0, int frameIndex, int trigg 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) @@ -873,53 +883,53 @@ 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].nonFixed = nonFixed; - _entries[timerIndex].msgPos.x = msgX; - _entries[timerIndex].msgPos.y = msgY; - _entries[timerIndex].numTicks = numTicks; - _entries[timerIndex].extraTicks = extraTicks; + _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[timerIndex].timeout = _madsVm->_currentTimer + delayTicks; + _entries[seqIndex].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].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]; +void MadsSequenceList::setSpriteSlot(int seqIndex, MadsSpriteSlot &spriteSlot) { + MadsSequenceEntry &timerEntry = _entries[seqIndex]; SpriteAsset &sprite = _owner._spriteSlots.getSprite(timerEntry.spriteListIndex); spriteSlot.spriteType = sprite.getAssetType() == 1 ? BACKGROUND_SPRITE : FOREGROUND_SPRITE; - spriteSlot.timerIndex = timerIndex; + spriteSlot.seqIndex = seqIndex; spriteSlot.spriteListIndex = timerEntry.spriteListIndex; spriteSlot.frameNumber = ((timerEntry.field_2 == 1) ? 0x8000 : 0) | timerEntry.frameIndex; spriteSlot.depth = timerEntry.depth; @@ -934,15 +944,15 @@ void MadsSequenceList::setSpriteSlot(int timerIndex, MadsSpriteSlot &spriteSlot) } } -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; } @@ -951,7 +961,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; @@ -1079,8 +1089,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; diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h index ba7504f3434..1661bac3df9 100644 --- a/engines/m4/mads_views.h +++ b/engines/m4/mads_views.h @@ -46,7 +46,7 @@ enum AbortTimerMode {ABORTMODE_0 = 0, ABORTMODE_1 = 1, ABORTMODE_2 = 2}; class MadsSpriteSlot { public: int spriteType; - int timerIndex; + int seqIndex; int spriteListIndex; int frameNumber; int xp; @@ -60,7 +60,7 @@ public: #define SPRITE_SLOTS_SIZE 50 enum SpriteIdSpecial { - BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, FOREGROUND_SPRITE = 1 + BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, FOREGROUND_SPRITE = 1, EXPIRED_SPRITE = -1 }; typedef Common::Array > SpriteList; @@ -87,11 +87,12 @@ public: int getIndex(); int addSprites(const char *resName); void clear(); - void deleteTimer(int timerIndex); + void deleteTimer(int seqIndex); void drawBackground(); void drawForeground(View *view); void setDirtyAreas(); + void fullRefresh(); void cleanUp(); }; @@ -343,12 +344,12 @@ public: int add(int spriteListIndex, int v0, int v1, int triggerCountdown, int delayTicks, int extraTicks, int numTicks, 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); }; class MadsView { From 967d9ea308342cbfb3c99904b5d6f1a0a3cd7ba0 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Fri, 28 May 2010 10:45:20 +0000 Subject: [PATCH 109/249] Added a stub for kMergePoly, to avoid crashing in QFG1VGA after killing a monster svn-id: r49288 --- engines/sci/engine/kernel.cpp | 1 + engines/sci/engine/kernel.h | 1 + engines/sci/engine/kpathing.cpp | 30 ++++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 55279399503..50d79c432be 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -332,6 +332,7 @@ 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, ".*"), diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index 7717743e195..8f8f34f74ec 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/kpathing.cpp b/engines/sci/engine/kpathing.cpp index 1152addeba1..276d0df1334 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -1694,4 +1694,34 @@ reg_t kIntersections(EngineState *s, int argc, reg_t *argv) { } } +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 + +#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 += GET_SEL32V(s->_segMan, node->value, SELECTOR(size)); + } + + node = s->_segMan->lookupNode(node->succ); + } +#endif + + warning("Stub: kMergePoly"); + + return polygonData; +} + } // End of namespace Sci From e694b66e4f8cb3bc60f8084c94aaccdc5405eab8 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Fri, 28 May 2010 10:52:22 +0000 Subject: [PATCH 110/249] Added comments to kMergePoly() svn-id: r49289 --- engines/sci/engine/kpathing.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index 276d0df1334..c36b7fbd280 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -1694,11 +1694,15 @@ 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]); From d9c0abe0b827a5c1fe15528ba3430fcbf2bdf71b Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Fri, 28 May 2010 10:53:03 +0000 Subject: [PATCH 111/249] Cleanup svn-id: r49290 --- engines/sci/engine/kernel.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 50d79c432be..ae3d30e81d7 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -383,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, ".*"), From b2e4e4b3409b1b8061890f921c80375096dc097e Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Fri, 28 May 2010 12:36:47 +0000 Subject: [PATCH 112/249] Cleaned up detectGfxFunctionsType() slightly, and made it work for Hoyle 1 and 2 properly. svn-id: r49292 --- engines/sci/engine/features.cpp | 66 +++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index 0e521d3c73c..a592805a289 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -332,16 +332,45 @@ 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; - 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 (_kernel->_selectorCache.overlay != -1) { + // The game has an overlay selector, check how it calls kDrawPicto determine + // the graphics functions type used + reg_t objAddr = _segMan->findObjectByName("Rm"); + if (lookup_selector(_segMan, objAddr, _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 (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; const Object *obj = _segMan->getObject(_segMan->findObjectByName("Rm")); for (uint m = 0; m < obj->getMethodCount(); m++) { @@ -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)); From 5b12fda0596b8b05768cc073b681d61c1493cf8e Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Fri, 28 May 2010 12:37:54 +0000 Subject: [PATCH 113/249] Added some more info when severe script errors occur svn-id: r49293 --- engines/sci/engine/vm.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 903c4a9a784..db45a087fad 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -832,12 +832,14 @@ void run_vm(EngineState *s, bool restoring) { #ifndef DISABLE_VALIDATIONS if (scriptState.xs->sp < scriptState.xs->fp) - error("run_vm(): stack underflow"); + error("run_vm(): stack underflow, sp: %04x:%04x, fp: %04x:%04x", + PRINT_REG(*scriptState.xs->sp), PRINT_REG(*scriptState.xs->fp)); scriptState.variables_max[VAR_TEMP] = scriptState.xs->sp - scriptState.xs->fp; if (scriptState.xs->addr.pc.offset >= code_buf_size) - error("run_vm(): program counter gone astray"); + error("run_vm(): program counter gone astray, addr: %d, code buffer size: %d", + scriptState.xs->addr.pc.offset, code_buf_size); #endif // Get opcode From 5d21ff280a30347362701ee177ab54f85e18e712 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Fri, 28 May 2010 16:47:30 +0000 Subject: [PATCH 114/249] Silenced some superfluous warnings in KQ5CD svn-id: r49294 --- engines/sci/engine/kmisc.cpp | 7 ++++++- engines/sci/graphics/paint16.cpp | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index c05a2bc57b7..68dc2fbba45 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -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; } diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp index a96189dbf03..ff4f3bec529 100644 --- a/engines/sci/graphics/paint16.cpp +++ b/engines/sci/graphics/paint16.cpp @@ -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) { From 1c32db1e084698f6594a66e142c217e83cab60d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20Andersson?= Date: Sat, 29 May 2010 08:09:47 +0000 Subject: [PATCH 115/249] Removed some unused variables, found by cppcheck. svn-id: r49306 --- backends/platform/gp2x/graphics.cpp | 5 ----- backends/platform/gp2xwiz/gp2xwiz-graphics.cpp | 5 ----- backends/platform/linuxmoto/linuxmoto-graphics.cpp | 5 ----- backends/platform/sdl/graphics.cpp | 5 ----- 4 files changed, 20 deletions(-) diff --git a/backends/platform/gp2x/graphics.cpp b/backends/platform/gp2x/graphics.cpp index 243c37dcb1b..449e744e8bc 100644 --- a/backends/platform/gp2x/graphics.cpp +++ b/backends/platform/gp2x/graphics.cpp @@ -1502,7 +1502,6 @@ void OSystem_GP2X::drawMouse() { SDL_Rect zoomdst; SDL_Rect dst; int scale; - int width, height; int hotX, hotY; int tmpScreenWidth, tmpScreenHeight; @@ -1523,16 +1522,12 @@ void OSystem_GP2X::drawMouse() { if (!_overlayVisible) { scale = _videoMode.scaleFactor; - width = _videoMode.screenWidth; - height = _videoMode.screenHeight; dst.w = _mouseCurState.vW; dst.h = _mouseCurState.vH; hotX = _mouseCurState.vHotX; hotY = _mouseCurState.vHotY; } else { scale = 1; - width = _videoMode.overlayWidth; - height = _videoMode.overlayHeight; dst.w = _mouseCurState.rW; dst.h = _mouseCurState.rH; hotX = _mouseCurState.rHotX; diff --git a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp index b20087e6d90..28c03db4b02 100644 --- a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp +++ b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp @@ -154,7 +154,6 @@ void OSystem_GP2XWIZ::drawMouse() { SDL_Rect dst; int scale; - int width, height; int hotX, hotY; if (_videoMode.mode == GFX_HALF && !_overlayVisible){ @@ -167,16 +166,12 @@ void OSystem_GP2XWIZ::drawMouse() { if (!_overlayVisible) { scale = _videoMode.scaleFactor; - width = _videoMode.screenWidth; - height = _videoMode.screenHeight; dst.w = _mouseCurState.vW; dst.h = _mouseCurState.vH; hotX = _mouseCurState.vHotX; hotY = _mouseCurState.vHotY; } else { scale = 1; - width = _videoMode.overlayWidth; - height = _videoMode.overlayHeight; dst.w = _mouseCurState.rW; dst.h = _mouseCurState.rH; hotX = _mouseCurState.rHotX; diff --git a/backends/platform/linuxmoto/linuxmoto-graphics.cpp b/backends/platform/linuxmoto/linuxmoto-graphics.cpp index 8f718c82f62..482ed772c7c 100644 --- a/backends/platform/linuxmoto/linuxmoto-graphics.cpp +++ b/backends/platform/linuxmoto/linuxmoto-graphics.cpp @@ -173,7 +173,6 @@ void OSystem_LINUXMOTO::drawMouse() { SDL_Rect dst; int scale; - int width, height; int hotX, hotY; if (_videoMode.mode == GFX_HALF && !_overlayVisible) { @@ -186,16 +185,12 @@ void OSystem_LINUXMOTO::drawMouse() { if (!_overlayVisible) { scale = _videoMode.scaleFactor; - width = _videoMode.screenWidth; - height = _videoMode.screenHeight; dst.w = _mouseCurState.vW; dst.h = _mouseCurState.vH; hotX = _mouseCurState.vHotX; hotY = _mouseCurState.vHotY; } else { scale = 1; - width = _videoMode.overlayWidth; - height = _videoMode.overlayHeight; dst.w = _mouseCurState.rW; dst.h = _mouseCurState.rH; hotX = _mouseCurState.rHotX; diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp index b3ef101e9eb..e0bf7565fbb 100644 --- a/backends/platform/sdl/graphics.cpp +++ b/backends/platform/sdl/graphics.cpp @@ -1771,7 +1771,6 @@ void OSystem_SDL::drawMouse() { SDL_Rect dst; int scale; - int width, height; int hotX, hotY; dst.x = _mouseCurState.x; @@ -1779,16 +1778,12 @@ void OSystem_SDL::drawMouse() { if (!_overlayVisible) { scale = _videoMode.scaleFactor; - width = _videoMode.screenWidth; - height = _videoMode.screenHeight; dst.w = _mouseCurState.vW; dst.h = _mouseCurState.vH; hotX = _mouseCurState.vHotX; hotY = _mouseCurState.vHotY; } else { scale = 1; - width = _videoMode.overlayWidth; - height = _videoMode.overlayHeight; dst.w = _mouseCurState.rW; dst.h = _mouseCurState.rH; hotX = _mouseCurState.rHotX; From 928eafcccf755859a86587e01b676d020baf4d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20Andersson?= Date: Sat, 29 May 2010 08:14:50 +0000 Subject: [PATCH 116/249] Fixed potential memory leak found by cppcheck. Though I'm guessing that if this case happens, we may have bigger problems... svn-id: r49307 --- engines/scumm/he/resource_he.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp index 886ee99e573..c259c3ffd2c 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; From 6f056c6c98e6c32c1e18a731ca6296b9ee4b130a Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 29 May 2010 14:03:08 +0000 Subject: [PATCH 117/249] Added a method to the resource manager, to limit the places where script exports are accessed, since for SCI11 and newer exports can be functions and objects (first step in removing scriptRelocateExportsSci11(), which is a gross hack and it fails in QFG1VGA) svn-id: r49308 --- engines/sci/engine/game.cpp | 4 +--- engines/sci/engine/seg_manager.h | 6 ------ engines/sci/resource.cpp | 33 +++++++++++++++++++++----------- engines/sci/resource.h | 8 ++++++++ 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index d7fdd9be6e0..232e0eca554 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -127,9 +127,7 @@ int game_init(EngineState *s) { 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); + s->_gameObj = g_sci->getResMan()->findGameObject(); #ifdef USE_OLD_MUSIC_FUNCTIONS if (s->sfx_init_flags & SFX_STATE_FLAG_NOSOUND) diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index 24d3f3fc1cc..30d62f50b02 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -111,12 +111,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); diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index cc3a2b0d1ab..d336cbab386 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1913,26 +1913,37 @@ bool ResourceManager::hasSci1Voc900() { #define READ_UINT16(ptr) (!isSci11Mac() ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) -Common::String ResourceManager::findSierraGameId() { +reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) { Resource *script = findResource(ResourceId(kResourceTypeScript, 0), false); + int extraBytes = 0; + if (getSciVersion() == SCI_VERSION_0_EARLY || getSciVersion() >= SCI_VERSION_1_1) + extraBytes = 2; + + int16 offset = READ_UINT16(script->data + extraBytes + 4 + 2); + + // 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; + + return make_reg(1, offset); +} + +Common::String ResourceManager::findSierraGameId() { // In SCI0-SCI1, the heap is embedded in the script. In SCI1.1+, it's separated Resource *heap = 0; - byte *seeker = 0; - Common::String sierraId; + int nameSelector = 3; - // 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); + heap = findResource(ResourceId(kResourceTypeScript, 0), false); } else { - const int nameSelector = 5 + 3; heap = findResource(ResourceId(kResourceTypeHeap, 0), false); - byte *exportPtr = script->data + 4 + 2 + 2; - seeker = heap->data + READ_UINT16(heap->data + READ_UINT16(exportPtr) + nameSelector * 2); + nameSelector += 5; } + // Seek to the name selector of the first export + byte *seeker = heap->data + READ_UINT16(heap->data + findGameObject(false).offset + nameSelector * 2); + Common::String sierraId; sierraId += (const char *)seeker; return sierraId; diff --git a/engines/sci/resource.h b/engines/sci/resource.h index dbd99f633d3..8147763f4f7 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -296,6 +296,14 @@ public: */ 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 From 708b37898c17ca520e8b3ae92a2e458665c7bd81 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 29 May 2010 15:01:33 +0000 Subject: [PATCH 118/249] Fixed regression in SCI2-SCI21 games from commit 49308 svn-id: r49309 --- engines/sci/resource.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index d336cbab386..ab46fa3abd2 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1926,6 +1926,10 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) { if (getSciVersion() >= SCI_VERSION_1_1 && addSci11ScriptOffset) offset += script->size; + // TODO: Investigate why this is needed for SCI2+ games + if (getSciVersion() >= SCI_VERSION_2) + offset += 1; + return make_reg(1, offset); } @@ -1941,8 +1945,14 @@ Common::String ResourceManager::findSierraGameId() { nameSelector += 5; } + int16 gameObjectOffset = findGameObject(false).offset; + + // Compensate for the odd offsets of SCI2+ games + if (getSciVersion() >= SCI_VERSION_2) + gameObjectOffset -= 1; + // Seek to the name selector of the first export - byte *seeker = heap->data + READ_UINT16(heap->data + findGameObject(false).offset + nameSelector * 2); + byte *seeker = heap->data + READ_UINT16(heap->data + gameObjectOffset + nameSelector * 2); Common::String sierraId; sierraId += (const char *)seeker; From 3d09af03773d353e73b61197befa63031e99d096 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 29 May 2010 15:27:27 +0000 Subject: [PATCH 119/249] Removed the hack inside findGameObject(), and replaced it with code from the segment manager, till we find out why the segment is sometimes off by 1 (note that findGameObject() works fine for finding the game ID itself) svn-id: r49310 --- engines/sci/engine/game.cpp | 8 +++++++- engines/sci/resource.cpp | 8 -------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 232e0eca554..241df94316c 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -127,7 +127,13 @@ int game_init(EngineState *s) { srand(g_system->getMillis()); // Initialize random number generator - s->_gameObj = g_sci->getResMan()->findGameObject(); + // TODO: This is sometimes off by 1... find out why + //s->_gameObj = g_sci->getResMan()->findGameObject(); + // Replaced by the code below for now + Script *scr000 = s->_segMan->getScript(1); + s->_gameObj = make_reg(1, scr000->validateExportFunc(0)); + if (getSciVersion() >= SCI_VERSION_1_1) + s->_gameObj.offset += scr000->_scriptSize; #ifdef USE_OLD_MUSIC_FUNCTIONS if (s->sfx_init_flags & SFX_STATE_FLAG_NOSOUND) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index ab46fa3abd2..56ff24389e7 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1926,10 +1926,6 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) { if (getSciVersion() >= SCI_VERSION_1_1 && addSci11ScriptOffset) offset += script->size; - // TODO: Investigate why this is needed for SCI2+ games - if (getSciVersion() >= SCI_VERSION_2) - offset += 1; - return make_reg(1, offset); } @@ -1947,10 +1943,6 @@ Common::String ResourceManager::findSierraGameId() { int16 gameObjectOffset = findGameObject(false).offset; - // Compensate for the odd offsets of SCI2+ games - if (getSciVersion() >= SCI_VERSION_2) - gameObjectOffset -= 1; - // Seek to the name selector of the first export byte *seeker = heap->data + READ_UINT16(heap->data + gameObjectOffset + nameSelector * 2); Common::String sierraId; From a6156a680583bfd3876bcd1c6d5e550763d0a677 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 29 May 2010 15:29:27 +0000 Subject: [PATCH 120/249] Removed the scriptRelocateExportsSci11() hack. The open spell in QFG1VGA works now (thanks to waltervn for all his help on this) svn-id: r49311 --- engines/sci/engine/kscripts.cpp | 8 +++++++- engines/sci/engine/savegame.cpp | 1 - engines/sci/engine/script.cpp | 18 ------------------ 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index eeaa0ceec0c..9b076486475 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -204,7 +204,13 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) { 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->_scriptSize; + + return make_reg(scriptSeg, address); } reg_t kDisposeScript(EngineState *s, int argc, reg_t *argv) { diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index c967dddf7dc..ab8b9eec58e 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -798,7 +798,6 @@ void SegManager::reconstructScripts(EngineState *s) { scr->_synonyms = 0; if (READ_LE_UINT16(scr->_buf + 6) > 0) { scr->setExportTableOffset(6); - s->_segMan->scriptRelocateExportsSci11(i); } } else { scr->_exportTable = (uint16 *) scr->findBlock(SCI_OBJ_EXPORTS); diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index e0bcd632cc9..d1cbfbf5517 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -200,23 +200,6 @@ void SegManager::scriptInitialiseLocals(reg_t location) { } } -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(scr->_exportTable + i); - - if ((location < scr->_heapSize - 1) && (READ_SCI11ENDIAN_UINT16(scr->_heapStart + location) == SCRIPT_OBJECT_MAGIC_NUMBER)) { - WRITE_SCI11ENDIAN_UINT16(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); const byte *seeker = scr->_heapStart + 4 + READ_SCI11ENDIAN_UINT16(scr->_heapStart + 2) * 2; @@ -484,7 +467,6 @@ int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int sc segMan->scriptInitialiseLocals(make_reg(seg_id, _heapStart + 4)); - segMan->scriptRelocateExportsSci11(seg_id); segMan->scriptInitialiseObjectsSci11(seg_id); scr->heapRelocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(heap->data))); From d3bcb10861b7716ed59ecc53efcaabad1f14e246 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 29 May 2010 15:47:28 +0000 Subject: [PATCH 121/249] Cleanup svn-id: r49312 --- engines/sci/engine/seg_manager.h | 1 - 1 file changed, 1 deletion(-) diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index 30d62f50b02..75c9b975651 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -434,7 +434,6 @@ public: */ reg_t findObjectByName(const Common::String &name, int index = -1); - void scriptRelocateExportsSci11(SegmentId seg); void scriptInitialiseObjectsSci11(SegmentId seg); public: // TODO: make private From 989c1fddddbe63075a9d4b9860476a080711164c Mon Sep 17 00:00:00 2001 From: Neil Millstone Date: Sat, 29 May 2010 20:30:54 +0000 Subject: [PATCH 122/249] DS: Various fixes to allow the DS port to compile on DevkitARM r30 and libnds 1.4.3. svn-id: r49313 --- backends/platform/ds/arm7/source/main.cpp | 4 ++-- backends/platform/ds/arm9/makefile | 2 +- backends/platform/ds/arm9/source/dsmain.cpp | 4 ++-- backends/platform/ds/commoninclude/NDS/scummvm_ipc.h | 12 ++++++++++++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/backends/platform/ds/arm7/source/main.cpp b/backends/platform/ds/arm7/source/main.cpp index 7029d96405b..a4cde02ba68 100644 --- a/backends/platform/ds/arm7/source/main.cpp +++ b/backends/platform/ds/arm7/source/main.cpp @@ -38,7 +38,7 @@ #include #include #include -//#include // not needed in current libnds +#include // Needed for SOUND_CR #include ////////////////////////////////////////////////////////////////////// #ifdef USE_DEBUGGER @@ -590,7 +590,7 @@ int main(int argc, char ** argv) { IPC->reset = false; - fifoInit(); + //fifoInit(); for (int r = 0; r < 8; r++) { IPC->adpcm.arm7Buffer[r] = (u8 *) malloc(512); diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile index eca170ef96e..7f03f4c310f 100644 --- a/backends/platform/ds/arm9/makefile +++ b/backends/platform/ds/arm9/makefile @@ -75,7 +75,7 @@ else ifdef DS_BUILD_K else - USE_MAD = 1 + # USE_MAD = 1 endif endif endif diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp index 1e9986e4e9a..4828ae21925 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -701,7 +701,7 @@ void displayMode8Bit() { - consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 2, 0, true); + consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 2, 0, true, true); // Set this again because consoleinit resets it videoSetMode(MODE_5_2D | (consoleEnable? DISPLAY_BG0_ACTIVE: 0) | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_BMP); @@ -939,7 +939,7 @@ void displayMode16Bit() { SUB_BG0_CR = BG_MAP_BASE(4) | BG_TILE_BASE(0); SUB_BG0_Y0 = 0; - consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, false); + consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, false, true); // consoleInitDefault((u16*)SCREEN_BASE_BLOCK_SUB(4), (u16*)CHAR_BASE_BLOCK_SUB(0), 16); for (int r = 0; r < 32 * 32; r++) { diff --git a/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h b/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h index 9344be68f9d..f41548f4008 100644 --- a/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h +++ b/backends/platform/ds/commoninclude/NDS/scummvm_ipc.h @@ -33,6 +33,18 @@ ////////////////////////////////////////////////////////////////////// +typedef struct sTransferSoundData { +//--------------------------------------------------------------------------------- + const void *data; + u32 len; + u32 rate; + u8 vol; + u8 pan; + u8 format; + u8 PADDING; +} TransferSoundData, * pTransferSoundData; + + //--------------------------------------------------------------------------------- From 5143e7fff42de358021c1a150d2bd7495374ba49 Mon Sep 17 00:00:00 2001 From: Neil Millstone Date: Sat, 29 May 2010 20:32:25 +0000 Subject: [PATCH 123/249] Fix typo(?) which prevents streaming code from compiling. svn-id: r49314 --- sound/decoders/voc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/decoders/voc.cpp b/sound/decoders/voc.cpp index 5663861f057..e9af7ece3f0 100644 --- a/sound/decoders/voc.cpp +++ b/sound/decoders/voc.cpp @@ -384,7 +384,7 @@ AudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, uint SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) { #ifdef STREAM_AUDIO_FROM_DISK - return makeVOCDiskStreamNoLoop(*stream, flags, disposeAfterUse); + return makeVOCDiskStreamNoLoop(stream, flags, disposeAfterUse); #else int size, rate; From 42d6ed880b92e19c469c70da92397bd860abb483 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 29 May 2010 21:42:42 +0000 Subject: [PATCH 124/249] SCI: Make Script::_exportTable const (yay :-) svn-id: r49315 --- engines/sci/console.cpp | 2 +- engines/sci/engine/savegame.cpp | 2 +- engines/sci/engine/segment.cpp | 2 +- engines/sci/engine/segment.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 51aa1a59d07..73086de39fb 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -1247,7 +1247,7 @@ bool Console::segmentInfo(int nr) { 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(" Exports: %4d at %d\n", scr->_numExports, (int)(((const byte *)scr->_exportTable) - ((const byte *)scr->_buf))); else DebugPrintf(" Exports: none\n"); diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index ab8b9eec58e..73109934735 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -800,7 +800,7 @@ void SegManager::reconstructScripts(EngineState *s) { scr->setExportTableOffset(6); } } else { - scr->_exportTable = (uint16 *) scr->findBlock(SCI_OBJ_EXPORTS); + scr->_exportTable = (const uint16 *)scr->findBlock(SCI_OBJ_EXPORTS); scr->_synonyms = scr->findBlock(SCI_OBJ_SYNONYMS); scr->_exportTable += 3; } diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 02d3a8987b7..17d0b67cf13 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -362,7 +362,7 @@ void Script::setLockers(int lockers) { void Script::setExportTableOffset(int offset) { if (offset) { - _exportTable = (uint16 *)(_buf + offset + 2); + _exportTable = (const uint16 *)(_buf + offset + 2); _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1); } else { _exportTable = NULL; diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 44bf6569b69..baff120b1c3 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -329,7 +329,7 @@ public: byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */ - uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */ + const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */ int _numExports; /**< Number of entries in the exports table */ const byte *_synonyms; /**< Synonyms block or 0 if not present*/ From 4ecacdad164d95154ac8a645058c2de0e2be73a9 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 29 May 2010 23:09:00 +0000 Subject: [PATCH 125/249] SCI: Merge Script::relocateBlock and Object::relocate The shared code now resides in a new static function named relocateBlock, which is invoked by the two methods. svn-id: r49316 --- engines/sci/engine/segment.cpp | 39 ++++++++++------------------------ engines/sci/engine/segment.h | 3 +-- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 17d0b67cf13..7e7da81125a 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -225,33 +225,34 @@ void Script::scriptObjRemove(reg_t obj_pos) { _objects.erase(obj_pos.toUint16()); } -int Script::relocateBlock(Common::Array &block, int block_location, SegmentId segment, int location) { +// This helper function is used by Script::relocateLocal and Object::relocate +static bool relocateBlock(Common::Array &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 + return false; } void Script::scriptAddCodeBlock(reg_t location) { @@ -745,25 +746,7 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) const { } bool Object::relocate(SegmentId segment, int location, size_t scriptSize) { - int rel = location - getPos().offset; - - if (rel < 0) - return false; - - uint idx = rel >> 1; - - if (idx >= _variables.size()) - return false; - - if (rel & 1) { - warning("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, getPos().offset); - return false; - } - _variables[idx].segment = segment; // Perform relocation - if (getSciVersion() >= SCI_VERSION_1_1) - _variables[idx].offset += scriptSize; - - return true; + return relocateBlock(_variables, getPos().offset, segment, location, scriptSize); } int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const { diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index baff120b1c3..0b4e6bb6657 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -408,8 +408,7 @@ public: void heapRelocate(reg_t block); private: - int relocateLocal(SegmentId segment, int location); - int relocateBlock(Common::Array &block, int block_location, SegmentId segment, int location); + bool relocateLocal(SegmentId segment, int location); public: // script lock operations From 67de5b1bd33d55a21bc2728cedfee25c321b4e36 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 29 May 2010 23:37:15 +0000 Subject: [PATCH 126/249] Mass renaming of selector-related functions, and removed some defines which were just cloaking functions with a different name - GET_SEL32 -> readSelector - GET_SEL32V -> readSelectorValue - PUT_SEL32 -> writeSelector - PUT_SEL32V -> writeSelectorValue Also, changed some selector-related function names and variables to CamelCase svn-id: r49317 --- engines/sci/console.cpp | 22 +-- engines/sci/engine/features.cpp | 6 +- engines/sci/engine/kernel32.cpp | 22 +-- engines/sci/engine/kevent.cpp | 50 +++--- engines/sci/engine/kgraphics.cpp | 66 ++++---- engines/sci/engine/klists.cpp | 26 +-- engines/sci/engine/kmovement.cpp | 138 ++++++++-------- engines/sci/engine/kparse.cpp | 18 +-- engines/sci/engine/kpathing.cpp | 30 ++-- engines/sci/engine/kscripts.cpp | 4 +- engines/sci/engine/kstring.cpp | 2 +- engines/sci/engine/scriptdebug.cpp | 2 +- engines/sci/engine/selector.cpp | 40 ++--- engines/sci/engine/selector.h | 33 ++-- engines/sci/engine/state.cpp | 6 +- engines/sci/engine/vm.cpp | 6 +- engines/sci/engine/vm.h | 4 +- engines/sci/graphics/animate.cpp | 76 ++++----- engines/sci/graphics/compare.cpp | 68 ++++---- engines/sci/graphics/controls.cpp | 18 +-- engines/sci/graphics/coordadjuster.cpp | 16 +- engines/sci/graphics/frameout.cpp | 54 +++---- engines/sci/graphics/maciconbar.cpp | 2 +- engines/sci/graphics/menu.cpp | 8 +- engines/sci/sound/audio.cpp | 8 +- engines/sci/sound/soundcmd.cpp | 214 ++++++++++++------------- 26 files changed, 466 insertions(+), 473 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 73086de39fb..15dcdee8d37 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -1520,12 +1520,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 @@ -2227,7 +2227,7 @@ bool Console::cmdDisassemble(int argc, const char **argv) { } const Object *obj = _engine->_gamestate->_segMan->getObject(objAddr); - int selector_id = _engine->getKernel()->findSelector(argv[2]); + int selectorId = _engine->getKernel()->findSelector(argv[2]); reg_t addr; if (!obj) { @@ -2235,12 +2235,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; } @@ -2320,9 +2320,9 @@ 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; } @@ -2333,7 +2333,7 @@ bool Console::cmdSend(int argc, const char **argv) { 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); @@ -2346,7 +2346,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)) { diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index a592805a289..1539b3d190f 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; } @@ -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. @@ -346,7 +346,7 @@ SciVersion GameFeatures::detectGfxFunctionsType() { // The game has an overlay selector, check how it calls kDrawPicto determine // the graphics functions type used reg_t objAddr = _segMan->findObjectByName("Rm"); - if (lookup_selector(_segMan, objAddr, _kernel->_selectorCache.overlay, NULL, NULL) == kSelectorMethod) { + if (lookupSelector(_segMan, objAddr, _kernel->_selectorCache.overlay, NULL, NULL) == kSelectorMethod) { if (!autoDetectGfxFunctionsType()) { warning("Graphics functions detection failed, taking an educated guess"); diff --git a/engines/sci/engine/kernel32.cpp b/engines/sci/engine/kernel32.cpp index 465e0e92df8..b705bbb7947 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()); } @@ -624,7 +624,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 +689,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 +761,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()); @@ -779,7 +779,7 @@ 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))); + 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 156035b30d1..f0432f0c96d 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -54,11 +54,11 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) { // 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); } @@ -70,8 +70,8 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) { if (s->_voc) s->_voc->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); @@ -81,12 +81,12 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) { 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 +111,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 +165,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 +201,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 +217,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 +236,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/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index aaf361d85ca..17d2cd630ed 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -53,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); @@ -93,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) { @@ -439,7 +439,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); @@ -451,8 +451,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); @@ -528,8 +528,8 @@ 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 (!strcmp(g_sci->getGameID(), "lsl1sci") && s->currentRoomNumber() == 300) { - int top = GET_SEL32V(s->_segMan, object, SELECTOR(brTop)); - PUT_SEL32V(s->_segMan, object, SELECTOR(brTop), top + 2); + int top = readSelectorValue(s->_segMan, object, SELECTOR(brTop)); + writeSelectorValue(s->_segMan, object, SELECTOR(brTop), top + 2); } return s->r_acc; @@ -743,12 +743,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; @@ -764,8 +764,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); @@ -777,32 +777,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 (!strcmp(g_sci->getGameID(), "jones")) - priority = GET_SEL32V(s->_segMan, controlObject, SELECTOR(priority)); + priority = readSelectorValue(s->_segMan, controlObject, SELECTOR(priority)); else priority = -1; } @@ -815,17 +815,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 @@ -876,8 +876,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); @@ -896,7 +896,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: diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp index 7fefccd9d76..f06f3eec778 100644 --- a/engines/sci/engine/klists.cpp +++ b/engines/sci/engine/klists.cpp @@ -397,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; @@ -412,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); @@ -424,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; @@ -515,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); @@ -548,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()) @@ -582,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/kmovement.cpp b/engines/sci/engine/kmovement.cpp index 42e690422c2..499aeabcc68 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,24 +310,24 @@ 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; @@ -335,7 +335,7 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) { 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); } @@ -377,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) { @@ -394,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)); @@ -434,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); } @@ -463,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 51ad6bb5c65..97a75dcb1cd 100644 --- a/engines/sci/engine/kparse.cpp +++ b/engines/sci/engine/kparse.cpp @@ -63,7 +63,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 (s->_voc->parser_event.isNull() || (readSelectorValue(s->_segMan, s->_voc->parser_event, SELECTOR(claimed)))) { return NULL_REG; } @@ -77,7 +77,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, s->_voc->parser_event, SELECTOR(claimed), 1); } else { return NULL_REG; @@ -115,16 +115,16 @@ 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, s->_voc->parser_base, stringpos); /* Issue warning */ debugC(2, kDebugLevelParser, "Tree building failed"); } else { s->_voc->parserIsValid = true; - PUT_SEL32V(segMan, event, SELECTOR(claimed), 0); + writeSelectorValue(segMan, event, SELECTOR(claimed), 0); #ifdef DEBUG_PARSER s->_voc->dumpParseTree(); @@ -134,13 +134,13 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) { } 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); 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, s->_voc->parser_base, stringpos); free(error); return make_reg(0, 1); /* Tell them that it didn't work */ } @@ -163,14 +163,14 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) { s->_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) diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index c36b7fbd280..857ccc2a083 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,7 +1050,7 @@ 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; @@ -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); @@ -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) @@ -1716,7 +1716,7 @@ reg_t kMergePoly(EngineState *s, int argc, reg_t *argv) { polygon = convert_polygon(s, node->value); if (polygon) { - count += GET_SEL32V(s->_segMan, node->value, SELECTOR(size)); + count += readSelectorValue(s->_segMan, node->value, SELECTOR(size)); } node = s->_segMan->lookupNode(node->succ); diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index 9b076486475..aec467bd54a 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -161,7 +161,7 @@ reg_t kDisposeClone(EngineState *s, int argc, reg_t *argv) { } // 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 @@ -250,7 +250,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 d7fa23116bb..13ec1bfc887 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -259,7 +259,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/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index da8e4ee211f..4468d376ea7 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -246,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()) ? "" : 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; diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp index cdbce5a6e47..92fed6e13eb 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -176,32 +176,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; @@ -209,21 +209,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; } @@ -243,7 +243,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]; @@ -253,13 +253,13 @@ 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) { +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); @@ -267,14 +267,14 @@ SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector se // 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 @@ -286,7 +286,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); @@ -301,7 +301,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 70eeb34d93e..f50b9ab1b3c 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_)) /** - * Kludge for use with invoke_selector(). Used for compatibility with compilers + * 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 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 dfc4c39464e..c9398d7ed53 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -227,7 +227,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. @@ -262,7 +262,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); } } @@ -274,7 +274,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/vm.cpp b/engines/sci/engine/vm.cpp index db45a087fad..1973693f1e7 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -212,7 +212,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; } @@ -383,7 +383,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; @@ -468,7 +468,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; diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index f6151dfc9d2..d6bb25c41df 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -95,7 +95,7 @@ class ResourceManager; /** 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, @@ -379,7 +379,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); /** diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp index 8a03c9579b1..c201b2cfb73 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); } @@ -165,21 +165,21 @@ void GfxAnimate::makeSortedList(List *list) { // Get data from current object listEntry->givenOrderNo = listNr; - 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->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; @@ -228,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 @@ -241,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) { @@ -291,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; @@ -348,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; } @@ -396,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); @@ -432,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); @@ -447,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) { @@ -481,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++; } @@ -490,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/compare.cpp b/engines/sci/graphics/compare.cpp index 36dd2d4aed9..3102edc2fa3 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 f744d6e7f1b..26af9741c20 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 40ef655be7f..422df52f275 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 78253bd913f..3cc5ca54473 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/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp index 2904bda22b8..a06e98ccbf1 100644 --- a/engines/sci/graphics/maciconbar.cpp +++ b/engines/sci/graphics/maciconbar.cpp @@ -48,7 +48,7 @@ void GfxMacIconBar::drawIcons() { uint32 lastX = 0; for (uint32 i = 0; i < _iconBarObjects.size(); i++) { - uint32 iconIndex = GET_SEL32V(g_sci->getEngineState()->_segMan, _iconBarObjects[i], SELECTOR(iconIndex)); + 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; diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp index 5e3b419fe3e..880e1aba123 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/sound/audio.cpp b/engines/sci/sound/audio.cpp index 331561eea41..f64760b53e4 100644 --- a/engines/sci/sound/audio.cpp +++ b/engines/sci/sound/audio.cpp @@ -332,11 +332,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 +352,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/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index b191e9f2c05..3d25713ceba 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; + newSound->loop = readSelectorValue(_segMan, obj, SELECTOR(loop)); + newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(pri)) & 0xFF; if (_soundVersion >= SCI_VERSION_1_EARLY) - newSound->volume = CLIP(GET_SEL32V(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX); + newSound->volume = CLIP(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)); + musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop)); + musicSlot->priority = readSelectorValue(_segMan, obj, SELECTOR(priority)); if (_soundVersion >= SCI_VERSION_1_EARLY) - musicSlot->volume = GET_SEL32V(_segMan, obj, SELECTOR(vol)); + 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 } @@ -635,8 +635,8 @@ void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) { ** 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 +651,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 +692,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 +714,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 +724,11 @@ void SoundCommandParser::cmdUpdateSound(reg_t obj, int16 value) { return; } - musicSlot->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop)); - int16 objVol = CLIP(GET_SEL32V(_segMan, obj, SELECTOR(vol)), 0, 255); + musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop)); + int16 objVol = CLIP(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 +755,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 +765,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 +784,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); @@ -841,14 +841,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 +856,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 +874,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 @@ -930,10 +930,10 @@ void SoundCommandParser::cmdStopAllSounds(reg_t obj, int16 value) { 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; @@ -964,7 +964,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 } @@ -991,12 +991,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 @@ -1007,7 +1007,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); } @@ -1032,7 +1032,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 } @@ -1103,11 +1103,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); @@ -1143,7 +1143,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 From 5f2ff0b1e7147a5638e66bbd1362196b5419c330 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 29 May 2010 23:56:37 +0000 Subject: [PATCH 127/249] Limit access to the _classTable array (now it's directly accessible only inside saveLoadWithSerializer() svn-id: r49318 --- engines/sci/console.cpp | 12 ++++----- engines/sci/engine/savegame.cpp | 2 +- engines/sci/engine/script.cpp | 39 +++++++++++++++--------------- engines/sci/engine/seg_manager.cpp | 2 +- engines/sci/engine/seg_manager.h | 8 +++++- engines/sci/engine/vm.h | 2 +- 6 files changed, 35 insertions(+), 30 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 15dcdee8d37..1f61dff12b7 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -277,8 +277,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) { @@ -929,11 +929,11 @@ bool Console::cmdRestartGame(int argc, const char **argv) { 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); } } diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 73109934735..eb52a888fa8 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(s, _segMan->_classtable); + syncArray(s, _segMan->_classTable); #ifdef USE_OLD_MUSIC_FUNCTIONS sync_songlib(s, _sound._songlib); diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index d1cbfbf5517..051cb0d2159 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); @@ -209,14 +209,14 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { 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; } @@ -372,22 +372,21 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr 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(), + species, species, segMan->classTableSize(), script_nr); return 0; } } - segMan->_classtable[species].reg.segment = seg_id; - segMan->_classtable[species].reg.offset = classpos; + segMan->setClassOffset(species, make_reg(seg_id, classpos)); // Set technical class position-- into the block allocated for it } break; @@ -507,7 +506,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()) @@ -541,9 +540,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/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index a8f46213eca..bc64c56e71d 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -77,7 +77,7 @@ void SegManager::resetSegMan() { Hunks_seg_id = 0; // Reinitialize class table - _classtable.clear(); + _classTable.clear(); createClassTable(); } diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index 75c9b975651..c3efd483c26 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -436,9 +436,15 @@ public: 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); } + public: // TODO: make private Common::Array _heap; - Common::Array _classtable; /**< Table of all classes */ + // Only accessible from saveLoadWithSerializer() + Common::Array _classTable; /**< Table of all classes */ #ifdef ENABLE_SCI32 SciArray *allocateArray(reg_t *addr); diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index d6bb25c41df..7ea0b2e5482 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -46,7 +46,7 @@ class ResourceManager; /** 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 +#define SCRIPT_MAX_classTable_SIZE 256 /** Maximum number of cloned objects on the heap */ #define SCRIPT_MAX_CLONES 256 From 6884ffc2918d192c9b091d4836f8c566ef3a7fcb Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Sun, 30 May 2010 09:47:00 +0000 Subject: [PATCH 128/249] PSP: added preliminary support for using ME hardware to play MP3 files. If the decoder fails to load, MAD is used instead. Disable with DISABLE_PSP_MP3. svn-id: r49319 --- backends/platform/psp/Makefile | 6 +- backends/platform/psp/module.mk | 3 +- backends/platform/psp/mp3.cpp | 487 ++++++++++++++++++++++++++++++++ backends/platform/psp/mp3.h | 121 ++++++++ backends/platform/psp/psp.spec | 2 +- sound/decoders/mp3.cpp | 15 +- 6 files changed, 629 insertions(+), 5 deletions(-) create mode 100644 backends/platform/psp/mp3.cpp create mode 100644 backends/platform/psp/mp3.h diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile index 7c33999b4db..7f8bb63b0ac 100644 --- a/backends/platform/psp/Makefile +++ b/backends/platform/psp/Makefile @@ -129,7 +129,8 @@ SDLFLAGS := $(shell $(PSPBIN)/sdl-config --cflags) SDLLIBS := $(shell $(PSPBIN)/sdl-config --libs) # PSP LIBS PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \ - -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspkernel + -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \ + -lpspkernel # Add in PSPSDK includes and libraries. CXXFLAGS += $(SDLFLAGS) @@ -149,7 +150,8 @@ OBJS := powerman.o \ psploader.o \ pspkeyboard.o \ audio.o \ - thread.o + thread.o \ + mp3.o # Include common Scummvm makefile include $(srcdir)/Makefile.common diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk index 4d375bcef09..99170ce7fb6 100644 --- a/backends/platform/psp/module.mk +++ b/backends/platform/psp/module.mk @@ -14,7 +14,8 @@ MODULE_OBJS := powerman.o \ psploader.o \ pspkeyboard.o \ audio.o \ - thread.o + thread.o \ + mp3.o MODULE_DIRS += \ backends/platform/psp/ diff --git a/backends/platform/psp/mp3.cpp b/backends/platform/psp/mp3.cpp new file mode 100644 index 00000000000..972c5a8ba87 --- /dev/null +++ b/backends/platform/psp/mp3.cpp @@ -0,0 +1,487 @@ +/* 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/debug.h" +#include "common/stream.h" +#include "common/util.h" +#include "common/singleton.h" +#include "common/mutex.h" + +#include "sound/audiostream.h" + +#include +#include +#include +#include +#include +#include +#include +#include "backends/platform/psp/mp3.h" + +//#define DISABLE_PSP_MP3 // to make us use the regular MAD decoder instead + +//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */ +//#define __PSP_DEBUG_PRINT__ +#include "backends/platform/psp/trace.h" + +//#define PRINT_BUFFERS /* to debug MP3 buffers */ + +namespace Audio { + +class Mp3PspStream; + +bool Mp3PspStream::_decoderInit = false; // has the decoder been initialized +#ifdef DISABLE_PSP_MP3 +bool Mp3PspStream::_decoderFail = true; // pretend the decoder failed +#else +bool Mp3PspStream::_decoderFail = false; // has the decoder failed to load +#endif + +bool Mp3PspStream::initDecoder() { + DEBUG_ENTER_FUNC(); + + if (_decoderInit) { + PSP_ERROR("Already initialized!"); + return true; + } + + // Based on PSP firmware version, we need to do different things to do Media Engine processing + uint32 firmware = sceKernelDevkitVersion(); + PSP_DEBUG_PRINT("Firmware version 0x%x\n", firmware); + if (firmware == 0x01050001){ + if (!loadStartAudioModule((char *)(void *)"flash0:/kd/me_for_vsh.prx", + PSP_MEMORY_PARTITION_KERNEL)) { + PSP_ERROR("failed to load me_for_vsh.prx. ME cannot start.\n"); + _decoderFail = true; + return false; + } + if (!loadStartAudioModule((char *)(void *)"flash0:/kd/audiocodec.prx", PSP_MEMORY_PARTITION_KERNEL)) { + PSP_ERROR("failed to load audiocodec.prx. ME cannot start.\n"); + _decoderFail = true; + return false; + } + } else { + if (sceUtilityLoadAvModule(PSP_AV_MODULE_AVCODEC) < 0) { + PSP_ERROR("failed to load AVCODEC module.\n"); + _decoderFail = true; + return false; + } + } + + PSP_INFO_PRINT("Using PSP's ME for MP3\n"); // important to know this is happening + + _decoderInit = true; + return true; +} + +bool Mp3PspStream::stopDecoder() { + DEBUG_ENTER_FUNC(); + + if (!_decoderInit) + return true; + + // Based on PSP firmware version, we need to do different things to do Media Engine processing + if (sceKernelDevkitVersion() == 0x01050001){ +/* if (!unloadAudioModule("flash0:/kd/me_for_vsh.prx", PSP_MEMORY_PARTITION_KERNEL) || + !unloadAudioModule("flash0:/kd/audiocodec.prx", PSP_MEMORY_PARTITION_KERNEL) { + PSP_ERROR("failed to unload audio module\n"); + return false; + } +*/ + }else{ + if (sceUtilityUnloadModule(PSP_MODULE_AV_AVCODEC) < 0) { + PSP_ERROR("failed to unload avcodec module\n"); + return false; + } + } + + _decoderInit = false; + return true; +} + +//Load a PSP audio module +bool Mp3PspStream::loadStartAudioModule(const char *modname, int partition){ + DEBUG_ENTER_FUNC(); + + SceKernelLMOption option; + SceUID modid; + + memset(&option, 0, sizeof(option)); + option.size = sizeof(option); + option.mpidtext = partition; + option.mpiddata = partition; + option.position = 0; + option.access = 1; + + modid = sceKernelLoadModule(modname, 0, &option); + if (modid < 0) { + PSP_ERROR("Failed to load module %s. Got error 0x%x\n", modname, modid); + return false; + } + + int ret = sceKernelStartModule(modid, 0, NULL, NULL, NULL); + if (ret < 0) { + PSP_ERROR("Failed to start module %s. Got error 0x%x\n", modname, ret); + return false; + } + return true; +} + +// TODO: make parallel function for unloading the 1.50 modules + +Mp3PspStream::Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) : + _inStream(inStream), + _disposeAfterUse(dispose), + _pcmLength(0), + _posInFrame(0), + _state(MP3_STATE_INIT), + _length(0, 1000), + _sampleRate(0), + _totalTime(mad_timer_zero) { + + DEBUG_ENTER_FUNC(); + + assert(_decoderInit); // must be initialized by now + + // let's leave the buffer guard -- who knows, it may be good? + memset(_buf, 0, sizeof(_buf)); + memset(_codecInBuffer, 0, sizeof(_codecInBuffer)); + + initStream(); // init needed stuff for the stream + + while (_state != MP3_STATE_EOS) + findValidHeader(); // get a first header so we can read basic stuff + + _sampleRate = _header.samplerate; // copy it before it gets destroyed + + _length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate()); + + //initStreamME(); // init the stuff needed for the ME to work + + deinitStream(); + //releaseStreamME(); + + _state = MP3_STATE_INIT; +} + +int Mp3PspStream::initStream() { + DEBUG_ENTER_FUNC(); + + if (_state != MP3_STATE_INIT) + deinitStream(); + + // Init MAD + mad_stream_init(&_stream); + mad_header_init(&_header); + + // Reset the stream data + _inStream->seek(0, SEEK_SET); + _totalTime = mad_timer_zero; + _posInFrame = 0; + + // Update state + _state = MP3_STATE_READY; + + // Read the first few sample bytes into the buffer + readMP3DataIntoBuffer(); + + return true; +} + +bool Mp3PspStream::initStreamME() { + // The following will eventually go into the thread + sceAudiocodecReleaseEDRAM(_codecParams); // do we need this? + + memset(_codecParams, 0, sizeof(_codecParams)); + + // Init the MP3 hardware + int ret = 0; + ret = sceAudiocodecCheckNeedMem(_codecParams, 0x1002); + if (ret < 0) { + PSP_ERROR("failed to init MP3 ME module. sceAudiocodecCheckNeedMem returned 0x%x.\n", ret); + return false; + } + PSP_DEBUG_PRINT("sceAudiocodecCheckNeedMem returned %d\n", ret); + ret = sceAudiocodecGetEDRAM(_codecParams, 0x1002); + if (ret < 0) { + PSP_ERROR("failed to init MP3 ME module. sceAudiocodecGetEDRAM returned 0x%x.\n", ret); + return false; + } + PSP_DEBUG_PRINT("sceAudioCodecGetEDRAM returned %d\n", ret); + + PSP_DEBUG_PRINT("samplerate[%d]\n", _sampleRate); + _codecParams[10] = _sampleRate; + + ret = sceAudiocodecInit(_codecParams, 0x1002); + if (ret < 0) { + PSP_ERROR("failed to init MP3 ME module. sceAudiocodecInit returned 0x%x.\n", ret); + return false; + } + + return true; +} + +Mp3PspStream::~Mp3PspStream() { + DEBUG_ENTER_FUNC(); + + deinitStream(); + releaseStreamME(); // free the memory used for this stream + + if (_disposeAfterUse == DisposeAfterUse::YES) + delete _inStream; +} + +void Mp3PspStream::deinitStream() { + DEBUG_ENTER_FUNC(); + + if (_state == MP3_STATE_INIT) + return; + + // Deinit MAD + mad_header_finish(&_header); + mad_stream_finish(&_stream); + + _state = MP3_STATE_EOS; +} + +void Mp3PspStream::releaseStreamME() { + sceAudiocodecReleaseEDRAM(_codecParams); +} + +void Mp3PspStream::decodeMP3Data() { + DEBUG_ENTER_FUNC(); + + do { + if (_state == MP3_STATE_INIT) { + initStream(); + initStreamME(); + } + + if (_state == MP3_STATE_EOS) + return; + + findValidHeader(); // seach for next valid header + + while (_state == MP3_STATE_READY) { + _stream.error = MAD_ERROR_NONE; + + uint32 frame_size = _stream.next_frame - _stream.this_frame; + uint32 samplesPerFrame = _header.layer == MAD_LAYER_III ? 576 : 1152; // Varies by layer + // calculate frame size -- try + //uint32 calc_frame_size = ((144 * _header.bitrate) / 22050) + (_header.flags & MAD_FLAG_PADDING ? 1 : 0); + + // Get stereo/mono + uint32 multFactor = 1; + if (_header.mode != MAD_MODE_SINGLE_CHANNEL) // mono - x2 for 16bit + multFactor *= 2; // stereo - x4 for 16bit + + PSP_DEBUG_PRINT("MP3 frame size[%d]. Samples[%d]. Multfactor[%d] pad[%d]\n", frame_size, samplesPerFrame, multFactor, _header.flags & MAD_FLAG_PADDING); + memcpy(_codecInBuffer, _stream.this_frame, frame_size); // we need it aligned + + // set up parameters for ME + _codecParams[6] = (unsigned long)_codecInBuffer; + _codecParams[8] = (unsigned long)_pcmSamples; + _codecParams[7] = frame_size; + _codecParams[9] = samplesPerFrame * multFactor; // x2 for stereo + + // debug +#ifdef PRINT_BUFFERS + PSP_DEBUG_PRINT("mp3 frame:\n"); + for (int i=0; i < (int)frame_size; i++) { + PSP_DEBUG_PRINT_SAMELN("%x ", _codecInBuffer[i]); + } + PSP_DEBUG_PRINT("\n"); +#endif + // Decode the next frame + // This function blocks. We'll want to put it in a thread + int ret = sceAudiocodecDecode(_codecParams, 0x1002); + if (ret < 0) { + PSP_ERROR("failed to decode MP3 data in ME. sceAudiocodecDecode returned 0x%x\n", ret); + // handle error here + } + +#ifdef PRINT_BUFFERS + PSP_DEBUG_PRINT("PCM frame:\n"); + for (int i=0; i < (int)_codecParams[9]; i+=2) { // changed from i+=2 + PSP_DEBUG_PRINT_SAMELN("%d ", (int16)_pcmSamples[i]); + } + PSP_DEBUG_PRINT("\n"); +#endif + _pcmLength = samplesPerFrame; + _posInFrame = 0; + break; + } + } while (_state != MP3_STATE_EOS && _stream.error == MAD_ERROR_BUFLEN); + + if (_stream.error != MAD_ERROR_NONE) // catch EOS + _state = MP3_STATE_EOS; +} + +void Mp3PspStream::readMP3DataIntoBuffer() { + DEBUG_ENTER_FUNC(); + + uint32 remaining = 0; + + // Give up immediately if we already used up all data in the stream + if (_inStream->eos()) { + _state = MP3_STATE_EOS; + return; + } + + if (_stream.next_frame) { + // If there is still data in the MAD stream, we need to preserve it. + // Note that we use memmove, as we are reusing the same buffer, + // and hence the data regions we copy from and to may overlap. + remaining = _stream.bufend - _stream.next_frame; + assert(remaining < BUFFER_SIZE); // Paranoia check + memmove(_buf, _stream.next_frame, remaining); // TODO: may want another buffer + } + + // Try to read the next block + uint32 size = _inStream->read(_buf + remaining, BUFFER_SIZE - remaining); + if (size <= 0) { + _state = MP3_STATE_EOS; + return; + } + + // Feed the data we just read into the stream decoder + _stream.error = MAD_ERROR_NONE; + mad_stream_buffer(&_stream, _buf, size + remaining); // just setup the pointers +} + +bool Mp3PspStream::seek(const Timestamp &where) { + DEBUG_ENTER_FUNC(); + + if (where == _length) { + _state = MP3_STATE_EOS; + return true; + } else if (where > _length) { + return false; + } + + const uint32 time = where.msecs(); + + mad_timer_t destination; + mad_timer_set(&destination, time / 1000, time % 1000, 1000); + + // Check if we need to rewind + if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0) { + initStream(); + initStreamME(); + } + + // The ME will need clear data no matter what once we seek? + //if (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS) + // initStreamME(); + + // Skip ahead + while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS) + findValidHeader(); + + return (_state != MP3_STATE_EOS); +} + +// Seek in the stream, finding the next valid header +void Mp3PspStream::findValidHeader() { + DEBUG_ENTER_FUNC(); + + if (_state != MP3_STATE_READY) + return; + + // If necessary, load more data into the stream decoder + if (_stream.error == MAD_ERROR_BUFLEN) + readMP3DataIntoBuffer(); + + while (_state != MP3_STATE_EOS) { + _stream.error = MAD_ERROR_NONE; + + // Decode the next header. + if (mad_header_decode(&_header, &_stream) == -1) { + if (_stream.error == MAD_ERROR_BUFLEN) { + readMP3DataIntoBuffer(); // Read more data + continue; + } else if (MAD_RECOVERABLE(_stream.error)) { + debug(6, "MP3PSPStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); + continue; + } else { + warning("MP3PSPStream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); + break; + } + } + + // Sum up the total playback time so far + mad_timer_add(&_totalTime, _header.duration); + break; + } + + if (_stream.error != MAD_ERROR_NONE) + _state = MP3_STATE_EOS; +} + +int Mp3PspStream::readBuffer(int16 *buffer, const int numSamples) { + DEBUG_ENTER_FUNC(); + + int samples = 0; +#ifdef PRINT_BUFFERS + int16 *debugBuffer = buffer; +#endif + + // Keep going as long as we have input available + while (samples < numSamples && _state != MP3_STATE_EOS) { + const int len = MIN(numSamples, samples + (int)(_pcmLength - _posInFrame) * MAD_NCHANNELS(&_header)); + + while (samples < len) { + *buffer++ = _pcmSamples[_posInFrame << 1]; + samples++; + if (MAD_NCHANNELS(&_header) == 2) { + *buffer++ = _pcmSamples[(_posInFrame << 1) + 1]; + samples++; + } + _posInFrame++; // always skip an extra sample since ME always outputs stereo + } + + //memcpy(buffer, &_pcmSamples[_posInFrame], len << 1); // 16 bits + //_posInFrame += len; // next time we start from the middle + + if (_posInFrame >= _pcmLength) { + // We used up all PCM data in the current frame -- read & decode more + decodeMP3Data(); + } + } + +#ifdef PRINT_BUFFERS + PSP_INFO_PRINT("buffer:\n"); + for (int i = 0; i - +#if defined(__PSP__) + #include "backends/platform/psp/mp3.h" +#endif namespace Audio { @@ -347,7 +349,18 @@ int MP3Stream::readBuffer(int16 *buffer, const int numSamples) { SeekableAudioStream *makeMP3Stream( Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) { + +#if defined(__PSP__) + SeekableAudioStream *s = 0; + + if (Mp3PspStream::isOkToCreateStream()) + s = new Mp3PspStream(stream, disposeAfterUse); + + if (!s) // go to regular MAD mp3 stream if ME fails + s = new MP3Stream(stream, disposeAfterUse); +#else SeekableAudioStream *s = new MP3Stream(stream, disposeAfterUse); +#endif if (s && s->endOfData()) { delete s; return 0; From dbe561c59b61f40459ed2b4602457308e0426269 Mon Sep 17 00:00:00 2001 From: Lars Skovlund Date: Sun, 30 May 2010 10:27:39 +0000 Subject: [PATCH 129/249] Clarify reasoning behind hack in Script::scriptRelocate() svn-id: r49320 --- engines/sci/engine/segment.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 7e7da81125a..8267de76bdc 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -270,8 +270,14 @@ void Script::scriptRelocate(reg_t block) { for (int i = 0; i <= count; i++) { int pos = READ_SCI11ENDIAN_UINT16(_buf + block.offset + 2 + (i * 2)); + // This occurs in SCI01/SCI1 games where every other export + // value is zero. I have no idea what it's supposed to mean. + // + // Yes, there is code in the original to handle this situation, + // but we need an example of it happening in order to determine + // what to do. if (!pos) - continue; // FIXME: A hack pending investigation + continue; // FIXME: Just ignore it for now. if (!relocateLocal(block.segment, pos)) { bool done = false; From d0c79d21e969b0881fb9dfc1d7b204fa74ff2721 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 30 May 2010 12:44:59 +0000 Subject: [PATCH 130/249] Fix file length of zip file members inside ZipArchive (thanks to fuzzie for reporting). svn-id: r49321 --- common/unzip.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/unzip.cpp b/common/unzip.cpp index a83f70d6712..e46106025eb 100644 --- a/common/unzip.cpp +++ b/common/unzip.cpp @@ -1433,11 +1433,11 @@ Common::SeekableReadStream *ZipArchive::createReadStreamForMember(const Common:: unz_file_info fileInfo; unzOpenCurrentFile(_zipFile); unzGetCurrentFileInfo(_zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0); - byte *buffer = (byte *)calloc(fileInfo.uncompressed_size+1, 1); + byte *buffer = (byte *)malloc(fileInfo.uncompressed_size); assert(buffer); unzReadCurrentFile(_zipFile, buffer, fileInfo.uncompressed_size); unzCloseCurrentFile(_zipFile); - return new Common::MemoryReadStream(buffer, fileInfo.uncompressed_size+1, DisposeAfterUse::YES); + return new Common::MemoryReadStream(buffer, fileInfo.uncompressed_size, DisposeAfterUse::YES); // FIXME: instead of reading all into a memory stream, we could // instead create a new ZipStream class. But then we have to be From 0e9156c7c4d481a0f43b232207dd6065779e9765 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 30 May 2010 13:10:23 +0000 Subject: [PATCH 131/249] Add a (currently) failing test for reference logic in Common::String. (Taken from an example by fuzzie) svn-id: r49322 --- test/common/str.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/common/str.h b/test/common/str.h index 16fb0859dbf..2e1651ab59f 100644 --- a/test/common/str.h +++ b/test/common/str.h @@ -118,6 +118,28 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd"); } + void test_refCount5() { + // Test for allocated storage + Common::String foo1("HelloHelloHelloHelloAndHi"); + Common::String foo2(foo1); + + for (Common::String::iterator i = foo2.begin(); i != foo2.end(); ++i) + *i = 'h'; + + TS_ASSERT_EQUALS(foo1, "HelloHelloHelloHelloAndHi"); + TS_ASSERT_EQUALS(foo2, "hhhhhhhhhhhhhhhhhhhhhhhhh"); + + // Test for builtin storage + Common::String foo3("Hello"); + Common::String foo4(foo3); + + for (Common::String::iterator i = foo4.begin(); i != foo4.end(); ++i) + *i = 'h'; + + TS_ASSERT_EQUALS(foo3, "Hello"); + TS_ASSERT_EQUALS(foo4, "hhhhh"); + } + void test_self_asignment() { Common::String foo1("12345678901234567890123456789012"); foo1 = foo1.c_str() + 2; From f02e31f2fca7299695e006f0a0bffbebe115d8e9 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 30 May 2010 13:10:44 +0000 Subject: [PATCH 132/249] Fix non-const version of Common::String::begin. Common::String::begin now assures the storage is a unique one, i.e. there are no other Common::String objects pointing at it. This allows for safe use of the writable iterators (and thus fixes the test case added with my last commit) svn-id: r49323 --- common/str.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/str.h b/common/str.h index 12e2b0d2d3a..74bcb42264a 100644 --- a/common/str.h +++ b/common/str.h @@ -222,6 +222,12 @@ public: typedef const char * const_iterator; iterator begin() { + // Since the user could potentionally + // change the string via the returned + // iterator we have to assure we are + // pointing to an unique storage. + makeUnique(); + return _str; } From 9521f8d0085f7159bf61770ef13e7f949c0a3fd0 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 30 May 2010 13:41:40 +0000 Subject: [PATCH 133/249] Typo fixes. svn-id: r49324 --- common/str.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/str.h b/common/str.h index 74bcb42264a..189c37adb4a 100644 --- a/common/str.h +++ b/common/str.h @@ -222,10 +222,10 @@ public: typedef const char * const_iterator; iterator begin() { - // Since the user could potentionally + // Since the user could potentially // change the string via the returned // iterator we have to assure we are - // pointing to an unique storage. + // pointing to a unique storage. makeUnique(); return _str; From ff3f0f5d65ec72e7a8e189089e59e8b818beddb7 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 30 May 2010 13:42:04 +0000 Subject: [PATCH 134/249] Split test cases for internal and external storage. svn-id: r49325 --- test/common/str.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/common/str.h b/test/common/str.h index 2e1651ab59f..6581c37cdbb 100644 --- a/test/common/str.h +++ b/test/common/str.h @@ -119,7 +119,7 @@ class StringTestSuite : public CxxTest::TestSuite } void test_refCount5() { - // Test for allocated storage + // using external storage Common::String foo1("HelloHelloHelloHelloAndHi"); Common::String foo2(foo1); @@ -128,16 +128,18 @@ class StringTestSuite : public CxxTest::TestSuite TS_ASSERT_EQUALS(foo1, "HelloHelloHelloHelloAndHi"); TS_ASSERT_EQUALS(foo2, "hhhhhhhhhhhhhhhhhhhhhhhhh"); + } - // Test for builtin storage - Common::String foo3("Hello"); - Common::String foo4(foo3); + void test_refCount6() { + // using internal storage + Common::String foo1("Hello"); + Common::String foo2(foo1); - for (Common::String::iterator i = foo4.begin(); i != foo4.end(); ++i) + for (Common::String::iterator i = foo2.begin(); i != foo2.end(); ++i) *i = 'h'; - TS_ASSERT_EQUALS(foo3, "Hello"); - TS_ASSERT_EQUALS(foo4, "hhhhh"); + TS_ASSERT_EQUALS(foo1, "Hello"); + TS_ASSERT_EQUALS(foo2, "hhhhh"); } void test_self_asignment() { From 0276ec835ef3c77a4dbf772ea54cc6d5292452f2 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 15:17:29 +0000 Subject: [PATCH 135/249] Fixed findGameObject() for SCI11 games svn-id: r49326 --- engines/sci/engine/game.cpp | 8 +------- engines/sci/resource.cpp | 6 +++++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 241df94316c..232e0eca554 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -127,13 +127,7 @@ int game_init(EngineState *s) { srand(g_system->getMillis()); // Initialize random number generator - // TODO: This is sometimes off by 1... find out why - //s->_gameObj = g_sci->getResMan()->findGameObject(); - // Replaced by the code below for now - Script *scr000 = s->_segMan->getScript(1); - s->_gameObj = make_reg(1, scr000->validateExportFunc(0)); - if (getSciVersion() >= SCI_VERSION_1_1) - s->_gameObj.offset += scr000->_scriptSize; + s->_gameObj = g_sci->getResMan()->findGameObject(); #ifdef USE_OLD_MUSIC_FUNCTIONS if (s->sfx_init_flags & SFX_STATE_FLAG_NOSOUND) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 56ff24389e7..ba5689dcf0b 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1923,9 +1923,13 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) { // 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) + if (getSciVersion() >= SCI_VERSION_1_1 && addSci11ScriptOffset) { offset += script->size; + if (script->size & 2) + offset++; + } + return make_reg(1, offset); } From c32e88fe0bb61e75ca983072ba28102d4efbf123 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 16:14:31 +0000 Subject: [PATCH 136/249] Limit access to the _bufSize, _scriptSize and _heapSize members of the Script class svn-id: r49327 --- engines/sci/console.cpp | 2 +- engines/sci/engine/features.cpp | 14 +++++++------- engines/sci/engine/kernel.cpp | 2 +- engines/sci/engine/kscripts.cpp | 2 +- engines/sci/engine/savegame.cpp | 8 ++++---- engines/sci/engine/script.cpp | 8 ++++---- engines/sci/engine/scriptdebug.cpp | 4 ++-- engines/sci/engine/seg_manager.cpp | 2 +- engines/sci/engine/segment.h | 13 +++++++++---- engines/sci/engine/vm.cpp | 6 +++--- 10 files changed, 33 insertions(+), 28 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 1f61dff12b7..6965ca0ecec 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -1245,7 +1245,7 @@ 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); + DebugPrintf("script.%03d locked by %d, bufsize=%d (%x)\n", scr->_nr, scr->getLockers(), (uint)scr->getBufSize(), (uint)scr->getBufSize()); if (scr->_exportTable) DebugPrintf(" Exports: %4d at %d\n", scr->_numExports, (int)(((const byte *)scr->_exportTable) - ((const byte *)scr->_buf))); else diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index 1539b3d190f..3ad56306705 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -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 @@ -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) @@ -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) { @@ -412,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) { @@ -465,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/kernel.cpp b/engines/sci/engine/kernel.cpp index ae3d30e81d7..0b7198d1bc0 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -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/kscripts.cpp b/engines/sci/engine/kscripts.cpp index aec467bd54a..d5a0c225d61 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -208,7 +208,7 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) { // Point to the heap for SCI1.1+ games if (getSciVersion() >= SCI_VERSION_1_1) - address += scr->_scriptSize; + address += scr->getScriptSize(); return make_reg(scriptSeg, address); } diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index eb52a888fa8..363dc8a44a6 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -758,22 +758,22 @@ static void reconstruct_stack(EngineState *retval) { } static void load_script(EngineState *s, Script *scr) { - scr->_buf = (byte *)malloc(scr->_bufSize); + scr->_buf = (byte *)malloc(scr->getBufSize()); assert(scr->_buf); Resource *script = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, scr->_nr), 0); assert(script != 0); - assert(scr->_bufSize >= script->size); + assert(scr->getBufSize() >= 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; + scr->_heapStart = scr->_buf + scr->getScriptSize(); - assert(scr->_bufSize - scr->_scriptSize <= heap->size); + assert(scr->getBufSize() - scr->getScriptSize() <= heap->size); memcpy(scr->_heapStart, heap->data, heap->size); } } diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 051cb0d2159..ab0ab690837 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -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,9 +185,9 @@ 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); diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 4468d376ea7..103a0169725 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -85,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"); @@ -303,7 +303,7 @@ void script_debug(EngineState *s) { if (mobj) { Script *scr = (Script *)mobj; byte *code_buf = scr->_buf; - int code_buf_size = scr->_bufSize; + int code_buf_size = scr->getBufSize(); int opcode = scriptState.xs->addr.pc.offset >= code_buf_size ? 0 : code_buf[scriptState.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]; diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index bc64c56e71d..92eb1c47175 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -223,7 +223,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); } diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 0b4e6bb6657..06d53158ced 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -323,10 +323,6 @@ 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 */ const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */ @@ -335,9 +331,18 @@ public: const 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; + public: /** * Table for objects, contains property variables. diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 1973693f1e7..03d67ae4510 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -784,7 +784,7 @@ void run_vm(EngineState *s, bool restoring) { obj = s->_segMan->getObject(scriptState.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); if (!local_script) { @@ -1398,7 +1398,7 @@ void run_vm(EngineState *s, bool restoring) { 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]; @@ -1420,7 +1420,7 @@ void run_vm(EngineState *s, bool restoring) { 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]; From 5cdb13b3e8a160e7eae14c03644ad3be5a38b415 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 16:38:08 +0000 Subject: [PATCH 137/249] Made load_script() a member of the Script class svn-id: r49328 --- engines/sci/engine/savegame.cpp | 23 +---------------------- engines/sci/engine/segment.cpp | 21 +++++++++++++++++++++ engines/sci/engine/segment.h | 1 + 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 363dc8a44a6..2846aa5b9f4 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -757,27 +757,6 @@ 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->getBufSize()); - assert(scr->_buf); - - Resource *script = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, scr->_nr), 0); - assert(script != 0); - - assert(scr->getBufSize() >= 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->getScriptSize(); - - assert(scr->getBufSize() - scr->getScriptSize() <= 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; @@ -791,7 +770,7 @@ void SegManager::reconstructScripts(EngineState *s) { Script *scr = (Script *)mobj; // FIXME: Unify this code with script_instantiate_* ? - load_script(s, scr); + scr->load(g_sci->getResMan()); scr->_localsBlock = (scr->_localsSegment == 0) ? NULL : (LocalVariables *)(_heap[scr->_localsSegment]); if (getSciVersion() >= SCI_VERSION_1_1) { scr->_exportTable = 0; diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 8267de76bdc..30cfe2d0460 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -147,6 +147,27 @@ bool Script::init(int script_nr, ResourceManager *resMan) { return true; } +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); + } +} + 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); diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 06d53158ced..3a4e929abea 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -364,6 +364,7 @@ public: void freeScript(); bool init(int script_nr, ResourceManager *resMan); + void load(ResourceManager *resMan); virtual bool isValidOffset(uint16 offset) const; virtual SegmentRef dereference(reg_t pointer); From 29c2f30558e9c40d5c1a76ab600611b21ee72851 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 17:02:21 +0000 Subject: [PATCH 138/249] Unified the script loading code, and marked an issue with the SCI11 heap addresses svn-id: r49329 --- engines/sci/engine/script.cpp | 60 +++++++++++----------------------- engines/sci/engine/segment.cpp | 16 ++------- 2 files changed, 21 insertions(+), 55 deletions(-) diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index ab0ab690837..d52cdd693b8 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -263,24 +263,9 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { -int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int script_nr, Resource **script, Resource **heap, int *was_new) { +int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int script_nr, 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) { @@ -292,13 +277,10 @@ int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int s } } 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); + scr->load(resMan); // Set heap position (beyond the size word) scr->setLockers(1); @@ -315,26 +297,24 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr 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); + const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &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(seg_id, localsCount); } // Now do a first pass through the script objects to find the @@ -396,7 +376,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; @@ -436,7 +416,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); if (relocation >= 0) scr->scriptRelocate(make_reg(seg_id, relocation)); @@ -445,30 +425,28 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr } 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); + const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &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) + if (READ_SCI11ENDIAN_UINT16(scr->_buf + 6) > 0) scr->setExportTableOffset(6); - segMan->scriptInitialiseLocals(make_reg(seg_id, _heapStart + 4)); + int heapStart = scr->getScriptSize(); + // FIXME: This code was used to ensure that the heap address is word-aligned + // Make sure that this is used in all places where the heap is referenced, + // not just here... + //if (heapStart & 2) + // heapStart++; + + segMan->scriptInitialiseLocals(make_reg(seg_id, heapStart + 4)); segMan->scriptInitialiseObjectsSci11(seg_id); - - scr->heapRelocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(heap->data))); + scr->heapRelocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); return seg_id; } diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 30cfe2d0460..8a9b953289d 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -120,15 +120,6 @@ void Script::freeScript() { 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; - } - _localsOffset = 0; _localsBlock = NULL; @@ -138,11 +129,8 @@ bool Script::init(int script_nr, ResourceManager *resMan) { _markedAsDeleted = false; _nr = script_nr; - - if (getSciVersion() >= SCI_VERSION_1_1) - _heapStart = _buf + _scriptSize; - else - _heapStart = _buf; + _buf = 0; + _heapStart = 0; return true; } From 016862ac3a4928529d9eaedf6edf3e916c89155c Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 18:45:07 +0000 Subject: [PATCH 139/249] Moved setScriptSize() inside Script::init(), and removed a FIXME - the SCI1.1 word-align is done inside Script::init() svn-id: r49330 --- engines/sci/engine/script.cpp | 7 ---- engines/sci/engine/segment.cpp | 60 ++++++++++++---------------------- engines/sci/engine/segment.h | 5 +-- engines/sci/resource.cpp | 1 + 4 files changed, 23 insertions(+), 50 deletions(-) diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index d52cdd693b8..99a567d1e7e 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -437,13 +437,6 @@ int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int sc scr->setExportTableOffset(6); int heapStart = scr->getScriptSize(); - - // FIXME: This code was used to ensure that the heap address is word-aligned - // Make sure that this is used in all places where the heap is referenced, - // not just here... - //if (heapStart & 2) - // heapStart++; - segMan->scriptInitialiseLocals(make_reg(seg_id, heapStart + 4)); segMan->scriptInitialiseObjectsSci11(seg_id); scr->heapRelocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 8a9b953289d..a8c4eb73f60 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -117,8 +117,8 @@ void Script::freeScript() { _codeBlocks.clear(); } -bool Script::init(int script_nr, ResourceManager *resMan) { - setScriptSize(script_nr, resMan); +void Script::init(int script_nr, ResourceManager *resMan) { + Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0); _localsOffset = 0; _localsBlock = NULL; @@ -132,7 +132,25 @@ bool Script::init(int script_nr, ResourceManager *resMan) { _buf = 0; _heapStart = 0; - return true; + _scriptSize = script->size; + _bufSize = script->size; + _heapSize = 0; + + if (getSciVersion() == SCI_VERSION_0_EARLY) { + _bufSize += READ_LE_UINT16(script->data) * 2; + } else if (getSciVersion() >= SCI_VERSION_1_1) { + 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. + if (script->size & 2) { + _bufSize++; + _scriptSize++; + } + + assert(_bufSize <= 65535); + } } void Script::load(ResourceManager *resMan) { @@ -156,42 +174,6 @@ void Script::load(ResourceManager *resMan) { } } -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); - - _scriptSize = script->size; - _heapSize = 0; // Set later - - 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; - _heapSize = heap->size; - - // Ensure that the start of the heap resource can be word-aligned. - if (script->size & 2) { - _bufSize++; - _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; - } - } -} - Object *Script::allocateObject(uint16 offset) { return &_objects[offset]; } diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 3a4e929abea..127ab28b7e8 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -363,7 +363,7 @@ 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; @@ -512,9 +512,6 @@ public: * Finds the pointer where a block of a specific type starts from */ byte *findBlock(int type); - -private: - void setScriptSize(int script_nr, ResourceManager *resMan); }; /** Data stack */ diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index ba5689dcf0b..c36feb57c66 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1926,6 +1926,7 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) { if (getSciVersion() >= SCI_VERSION_1_1 && addSci11ScriptOffset) { offset += script->size; + // Ensure that the start of the heap is word-aligned - same as in Script::init() if (script->size & 2) offset++; } From 9c2da78ba9a99145241025974c42219a673dd2a8 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 20:01:25 +0000 Subject: [PATCH 140/249] kScriptID can be used to load scripts with no exports. Don't throw warnings in this case if no export is requested, as it's perfectly normal behavior svn-id: r49331 --- engines/sci/engine/kscripts.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index d5a0c225d61..b8298874331 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -194,8 +194,14 @@ 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); + // 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; } From dc4d61f7181edf332d426bab9d16e0055e3d0f21 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 20:06:50 +0000 Subject: [PATCH 141/249] - Merged the SCI0 scriptRelocate() and SCI11 heapRelocate() functions inside relocate(). scriptRelocate checked one more relocation entry, which seems wrong, so we're now checking for the correct number of relocations in all SCI versions - Re-added the error when script + heap exceed 64KB (better than an assert) - this should theoretically never happen, and it never has for the games tested - Removed the relocated sanity check - again, it shouldn't occur (else something else is wrong) svn-id: r49332 --- engines/sci/engine/script.cpp | 4 +- engines/sci/engine/segment.cpp | 85 ++++++++++++++-------------------- engines/sci/engine/segment.h | 5 +- 3 files changed, 38 insertions(+), 56 deletions(-) diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 99a567d1e7e..aa975cc1d0f 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -419,7 +419,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr } while (objType != 0 && curOffset < scr->getScriptSize() - 2); if (relocation >= 0) - scr->scriptRelocate(make_reg(seg_id, relocation)); + scr->relocate(make_reg(seg_id, relocation)); return seg_id; // instantiation successful } @@ -439,7 +439,7 @@ int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int sc int heapStart = scr->getScriptSize(); segMan->scriptInitialiseLocals(make_reg(seg_id, heapStart + 4)); segMan->scriptInitialiseObjectsSci11(seg_id); - scr->heapRelocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); + scr->relocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); return seg_id; } diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index a8c4eb73f60..bdd9fbc9661 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -100,7 +100,6 @@ Script::Script() : SegmentObj(SEG_TYPE_SCRIPT) { _localsSegment = 0; _localsBlock = NULL; - _relocated = false; _markedAsDeleted = 0; } @@ -125,7 +124,6 @@ void Script::init(int script_nr, ResourceManager *resMan) { _codeBlocks.clear(); - _relocated = false; _markedAsDeleted = false; _nr = script_nr; @@ -139,6 +137,14 @@ void Script::init(int script_nr, ResourceManager *resMan) { 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; @@ -149,7 +155,11 @@ void Script::init(int script_nr, ResourceManager *resMan) { _scriptSize++; } - assert(_bufSize <= 65535); + // 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"); } } @@ -253,14 +263,24 @@ 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, +void Script::relocate(reg_t block) { + byte *heap = _buf; + uint16 heapSize = (uint16)_bufSize; + uint16 heapOffset = 0; + + if (getSciVersion() >= SCI_VERSION_1_1) { + heap = _heapStart; + heapSize = (uint16)_heapSize; + heapOffset = _scriptSize; + } + + VERIFY(block.offset < (uint16)heapSize && READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset < (uint16)heapSize, "Relocation block outside of script\n"); - int count = READ_SCI11ENDIAN_UINT16(_buf + block.offset); + int count = READ_SCI11ENDIAN_UINT16(heap + block.offset); - for (int i = 0; i <= count; i++) { - int pos = READ_SCI11ENDIAN_UINT16(_buf + block.offset + 2 + (i * 2)); + for (int i = 0; i < count; i++) { + int pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (i * 2)) + heapOffset; // This occurs in SCI01/SCI1 games where every other export // value is zero. I have no idea what it's supposed to mean. // @@ -281,10 +301,13 @@ void Script::scriptRelocate(reg_t block) { 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; + // 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) { @@ -303,44 +326,6 @@ void Script::scriptRelocate(reg_t block) { } } -void Script::heapRelocate(reg_t block) { - VERIFY(block.offset < (uint16)_heapSize && READ_SCI11ENDIAN_UINT16(_heapStart + block.offset) * 2 + block.offset < (uint16)_bufSize, - "Relocation block outside of script\n"); - - if (_relocated) - return; - _relocated = true; - int count = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset); - - for (int i = 0; i < count; i++) { - int pos = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset + 2 + (i * 2)) + _scriptSize; - - 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 (it->_value.relocate(block.segment, pos, _scriptSize)) - 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); - 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()); - error("Breakpoint in %s, line %d", __FILE__, __LINE__); - } - } - } -} - void Script::incrementLockers() { _lockers++; } diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 127ab28b7e8..7b0828ab6b3 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -355,7 +355,6 @@ public: LocalVariables *_localsBlock; Common::Array _codeBlocks; - bool _relocated; bool _markedAsDeleted; public: @@ -409,9 +408,7 @@ 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: bool relocateLocal(SegmentId segment, int location); From 1fd3877ec7778535174cdfaef50810d619630fbb Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 20:18:42 +0000 Subject: [PATCH 142/249] Cleanup svn-id: r49333 --- engines/sci/engine/savegame.cpp | 9 --------- engines/sci/sound/soundcmd.cpp | 1 - 2 files changed, 10 deletions(-) diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 2846aa5b9f4..2d21ce6cbb1 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -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); diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 3d25713ceba..ece4c1430c0 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -630,7 +630,6 @@ 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); From 3b96e4833e0035ce5d54efbdd1badeaca858f5ae Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 20:30:07 +0000 Subject: [PATCH 143/249] Cleanup svn-id: r49334 --- engines/sci/engine/script.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index aa975cc1d0f..fda7d05aa0a 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -205,7 +205,7 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { 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) & SCRIPT_INFO_CLASS) { // -info- selector int classpos = seeker - scr->_buf; int species = READ_SCI11ENDIAN_UINT16(seeker + 10); @@ -226,15 +226,6 @@ 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)); From e13abd77e92a4c363731f4a6775aa26865bb4ad6 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 30 May 2010 21:44:26 +0000 Subject: [PATCH 144/249] Add md5's for Myst ME and Riven DVD French. svn-id: r49335 --- engines/mohawk/detection.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp index a7b1fe7fae8..7f2e0cb312e 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 @@ -431,6 +449,24 @@ static const MohawkGameDescription gameDescriptions[] = { 0, }, + // 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 From a0ee93ece52213cd989a50902281d917fe392ea4 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 21:49:07 +0000 Subject: [PATCH 145/249] SCI: Script exports and synonyms are now initialized when a script is loaded. Removed a sanity check inside script_instantiate_sci0 for a bug which no longer exists svn-id: r49336 --- engines/sci/engine/savegame.cpp | 16 ++----------- engines/sci/engine/savegame.h | 2 +- engines/sci/engine/script.cpp | 26 ++------------------- engines/sci/engine/segment.cpp | 41 ++++++++++++++++++--------------- engines/sci/engine/segment.h | 21 +---------------- 5 files changed, 29 insertions(+), 77 deletions(-) diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 2d21ce6cbb1..ae233f8c097 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -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: @@ -763,18 +763,6 @@ void SegManager::reconstructScripts(EngineState *s) { // FIXME: Unify this code with script_instantiate_* ? 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); - } - } else { - scr->_exportTable = (const uint16 *)scr->findBlock(SCI_OBJ_EXPORTS); - scr->_synonyms = scr->findBlock(SCI_OBJ_SYNONYMS); - scr->_exportTable += 3; - } - scr->_codeBlocks.clear(); ObjMap::iterator it; const ObjMap::iterator end = scr->_objects.end(); diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h index bad79fca275..7be05381da1 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 fda7d05aa0a..793f78e030a 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -275,9 +275,7 @@ int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int s // Set heap position (beyond the size word) scr->setLockers(1); - scr->setExportTableOffset(0); - scr->setSynonymsOffset(0); - scr->setSynonymsNr(0); + *was_new = 0; @@ -309,7 +307,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr } // 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); @@ -317,29 +315,12 @@ 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)); break; - case SCI_OBJ_CLASS: { int classpos = curOffset - SCRIPT_OBJECT_MAGIC_OFFSET; int species = scr->getHeap(curOffset - SCRIPT_OBJECT_MAGIC_OFFSET + SCRIPT_SPECIES_OFFSET); @@ -424,9 +405,6 @@ int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int sc Script *scr = segMan->getScript(seg_id); - if (READ_SCI11ENDIAN_UINT16(scr->_buf + 6) > 0) - scr->setExportTableOffset(6); - int heapStart = scr->getScriptSize(); segMan->scriptInitialiseLocals(make_reg(seg_id, heapStart + 4)); segMan->scriptInitialiseObjectsSci11(seg_id); diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index bdd9fbc9661..3653ff4ae91 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" @@ -182,6 +183,28 @@ void Script::load(ResourceManager *resMan) { 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 + 6) > 0) { + _exportTable = (const uint16 *)(_buf + 6 + 2); + _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1); + } + } else { + _exportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS); + if (_exportTable) { + _exportTable += 3; + _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1); + } + _synonyms = findBlock(SCI_OBJ_SYNONYMS); + _numSynonyms = _synonyms ? READ_SCI11ENDIAN_UINT16(_synonyms - 2) / 4 : 0; + } } Object *Script::allocateObject(uint16 offset) { @@ -343,16 +366,6 @@ void Script::setLockers(int lockers) { _lockers = lockers; } -void Script::setExportTableOffset(int offset) { - if (offset) { - _exportTable = (const uint16 *)(_buf + offset + 2); - _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1); - } else { - _exportTable = NULL; - _numExports = 0; - } -} - uint16 Script::validateExportFunc(int pubfunct) { bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE); @@ -369,18 +382,10 @@ uint16 Script::validateExportFunc(int pubfunct) { return offset; } -void Script::setSynonymsOffset(int offset) { - _synonyms = _buf + offset; -} - const byte *Script::getSynonyms() const { return _synonyms; } -void Script::setSynonymsNr(int n) { - _numSynonyms = n; -} - int Script::getSynonymsNr() const { return _numSynonyms; } diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 7b0828ab6b3..ea85a6e7648 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -342,6 +342,7 @@ private: size_t _scriptSize; size_t _heapSize; size_t _bufSize; + Common::Array _codeBlocks; public: /** @@ -354,7 +355,6 @@ public: SegmentId _localsSegment; /**< The local variable segment */ LocalVariables *_localsBlock; - Common::Array _codeBlocks; bool _markedAsDeleted; public: @@ -443,12 +443,6 @@ public: */ int getSynonymsNr() const; - /** - * Sets the script-relative offset of the exports table. - * @param offset script-relative exports table offset - */ - void setExportTableOffset(int offset); - /** * Validate whether the specified public function is exported by * the script in the specified segment. @@ -458,19 +452,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 From 4e25867a671a8847b167decba1ed1e95cf699e66 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 30 May 2010 23:00:32 +0000 Subject: [PATCH 146/249] SCI: Merge setLockers(1) call into Script::init svn-id: r49337 --- engines/sci/engine/script.cpp | 4 ---- engines/sci/engine/segment.cpp | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 793f78e030a..07fc75596ee 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -273,10 +273,6 @@ int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int s scr->init(script_nr, resMan); scr->load(resMan); - // Set heap position (beyond the size word) - scr->setLockers(1); - - *was_new = 0; return seg_id; diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 3653ff4ae91..3bec74398ca 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -135,6 +135,8 @@ void Script::init(int script_nr, ResourceManager *resMan) { _bufSize = script->size; _heapSize = 0; + _lockers = 1; + if (getSciVersion() == SCI_VERSION_0_EARLY) { _bufSize += READ_LE_UINT16(script->data) * 2; } else if (getSciVersion() >= SCI_VERSION_1_1) { From 50cd1d1da4a934cfcdcf7cb0b05bed6f7d9735c2 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 30 May 2010 23:31:33 +0000 Subject: [PATCH 147/249] Limited access to the script export table and synonyms block svn-id: r49338 --- engines/sci/console.cpp | 6 +++--- engines/sci/engine/kscripts.cpp | 8 ++++---- engines/sci/engine/segment.cpp | 8 -------- engines/sci/engine/segment.h | 29 +++++++++++++++++++++-------- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 6965ca0ecec..98046cfa324 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -1246,12 +1246,12 @@ 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->getBufSize(), (uint)scr->getBufSize()); - if (scr->_exportTable) - DebugPrintf(" Exports: %4d at %d\n", scr->_numExports, (int)(((const byte *)scr->_exportTable) - ((const byte *)scr->_buf))); + 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); diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index b8298874331..2f260bc03ab 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -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,7 +193,7 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) { Script *scr = s->_segMan->getScript(scriptSeg); - if (!scr->_numExports) { + 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 @@ -205,8 +205,8 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) { 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; } diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 3bec74398ca..e1e7fd4ae6c 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -384,14 +384,6 @@ uint16 Script::validateExportFunc(int pubfunct) { return offset; } -const byte *Script::getSynonyms() const { - return _synonyms; -} - -int Script::getSynonymsNr() const { - return _numSynonyms; -} - byte *Script::findBlock(int type) { byte *buf = _buf; bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index ea85a6e7648..dce1eb8445c 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -325,12 +325,6 @@ public: byte *_buf; /**< Static data buffer, or NULL if not used */ byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */ - const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */ - int _numExports; /**< Number of entries in the exports table */ - - const 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; } @@ -342,6 +336,13 @@ 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 _codeBlocks; public: @@ -431,17 +432,29 @@ public: /** Sets the number of locks held on this script. */ 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. */ - const 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; + uint16 getSynonymsNr() const { return _numSynonyms; } /** * Validate whether the specified public function is exported by From 693618d89a56ccc943f9f0608abf8737d5002d32 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 00:04:38 +0000 Subject: [PATCH 148/249] Slight cleanup svn-id: r49339 --- engines/sci/engine/savegame.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index ae233f8c097..07c40b332c9 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -751,14 +751,12 @@ static void reconstruct_stack(EngineState *retval) { // 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; + Script *scr = (Script *)_heap[i]; // FIXME: Unify this code with script_instantiate_* ? scr->load(g_sci->getResMan()); @@ -773,11 +771,10 @@ void SegManager::reconstructScripts(EngineState *s) { } 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; From 2a0f91444f3d42068a7aa6e1b6a6ac57ce0a0574 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 31 May 2010 01:27:57 +0000 Subject: [PATCH 149/249] Ignore v2 compressed audio chunks instead of treating them as Huffman DPCM. Should fix playback of at least the video portion of those videos (found in later Broken Sword releases). svn-id: r49340 --- graphics/video/smk_decoder.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/graphics/video/smk_decoder.cpp b/graphics/video/smk_decoder.cpp index f27a70f78c8..adc96a78206 100644 --- a/graphics/video/smk_decoder.cpp +++ b/graphics/video/smk_decoder.cpp @@ -361,7 +361,7 @@ SmackerDecoder::~SmackerDecoder() { } uint32 SmackerDecoder::getElapsedTime() const { - if (_audioStream) + if (_audioStream && _audioStarted) return _mixer->getSoundElapsedTime(_audioHandle); return VideoDecoder::getElapsedTime(); @@ -438,6 +438,9 @@ bool SmackerDecoder::load(Common::SeekableReadStream &stream) { !(audioInfo & 0x4000000); _header.audioInfo[i].sampleRate = audioInfo & 0xFFFFFF; + if (_header.audioInfo[i].hasV2Compression) + warning("Unhandled Smacker v2 audio compression"); + if (_header.audioInfo[i].hasAudio && i == 0) _audioStream = Audio::makeQueuingAudioStream(_header.audioInfo[0].sampleRate, _header.audioInfo[0].isStereo); } @@ -541,7 +544,11 @@ Surface *SmackerDecoder::decodeNextFrame() { _fileStream->read(soundBuffer, chunkSize); - if (_header.audioInfo[i].isCompressed) { + if (_header.audioInfo[i].hasV2Compression) { + // TODO: Compressed audio (Bink RDFT encoded) + free(soundBuffer); + continue; + } else if (_header.audioInfo[i].isCompressed) { // Compressed audio (Huffman DPCM encoded) queueCompressedBuffer(soundBuffer, chunkSize, dataSizeUnpacked, i); free(soundBuffer); From 05357d0f2aa7695981f5df706787bcd741e32c93 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 07:34:18 +0000 Subject: [PATCH 150/249] Cleanup svn-id: r49342 --- engines/sci/engine/features.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index 3ad56306705..48f7c2d64ff 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -341,12 +341,12 @@ SciVersion GameFeatures::detectGfxFunctionsType() { } else { // SCI0 late // Check if the game is using an overlay 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 - reg_t objAddr = _segMan->findObjectByName("Rm"); - if (lookupSelector(_segMan, objAddr, _kernel->_selectorCache.overlay, NULL, NULL) == kSelectorMethod) { + if (lookupSelector(_segMan, rmObjAddr, _kernel->_selectorCache.overlay, NULL, NULL) == kSelectorMethod) { if (!autoDetectGfxFunctionsType()) { warning("Graphics functions detection failed, taking an educated guess"); @@ -372,7 +372,7 @@ SciVersion GameFeatures::detectGfxFunctionsType() { // as the overlay selector might be missing in demos bool found = false; - const 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) From 66d4bddb30498419cebf0478a83b77ca3abb8131 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 08:11:49 +0000 Subject: [PATCH 151/249] Merged several script instantiation-related functions inside script_instantiate() svn-id: r49343 --- engines/sci/engine/script.cpp | 95 ++++++++++++----------------------- 1 file changed, 33 insertions(+), 62 deletions(-) diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 07fc75596ee..304fd4d6fd3 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -252,46 +252,13 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { } } - - -int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int script_nr, int *was_new) { - *was_new = 1; - - 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); - } - - scr->init(script_nr, resMan); - scr->load(resMan); - - *was_new = 0; - - return seg_id; -} - -int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int script_nr) { +int script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) { int objType; uint32 objLength = 0; int relocation = -1; - int was_new; bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); - const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &was_new); uint16 curOffset = oldScriptHeader ? 2 : 0; - if (was_new) - return seg_id; - - Script *scr = segMan->getScript(seg_id); - if (oldScriptHeader) { // Old script block // There won't be a localvar block in this case @@ -299,7 +266,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr // number of locals we need; these are then allocated and zeroed. int localsCount = READ_LE_UINT16(scr->_buf); if (localsCount) - segMan->scriptInitialiseLocalsZero(seg_id, localsCount); + segMan->scriptInitialiseLocalsZero(segmentId, localsCount); } // Now do a first pass through the script objects to find the @@ -315,7 +282,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr switch (objType) { 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; @@ -327,14 +294,14 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr segMan->resizeClassTable(segMan->classTableSize() + 1); } else { warning("Invalid species %d(0x%x) not in interval " - "[0,%d) while instantiating script %d\n", + "[0,%d) while instantiating script at segment %d\n", species, species, segMan->classTableSize(), - script_nr); + segmentId); return 0; } } - segMan->setClassOffset(species, make_reg(seg_id, classpos)); + segMan->setClassOffset(species, make_reg(segmentId, classpos)); // Set technical class position-- into the block allocated for it } break; @@ -358,7 +325,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: @@ -387,33 +354,37 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr } while (objType != 0 && curOffset < scr->getScriptSize() - 2); if (relocation >= 0) - scr->relocate(make_reg(seg_id, relocation)); + scr->relocate(make_reg(segmentId, relocation)); - return seg_id; // instantiation successful + return segmentId; // instantiation successful } -int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int script_nr) { - int was_new; - const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &was_new); +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); + } - if (was_new) - return seg_id; + scr->init(scriptNum, resMan); + scr->load(resMan); - Script *scr = segMan->getScript(seg_id); - - int heapStart = scr->getScriptSize(); - segMan->scriptInitialiseLocals(make_reg(seg_id, heapStart + 4)); - segMan->scriptInitialiseObjectsSci11(seg_id); - scr->relocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); - - return seg_id; -} - -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); + 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))); + return segmentId; + } else { + return script_instantiate_sci0(scr, segmentId, segMan); + } } void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg) { From 7001d3e6157dc9fe601a5f0e2195a367755a344b Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Mon, 31 May 2010 09:21:15 +0000 Subject: [PATCH 152/249] SCI: when getting invalid chars in kReadNumber don't error() out, but create a warning - we get invalid chars in the intro of lsl5, cause currently unknown svn-id: r49344 --- engines/sci/engine/kstring.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 13ec1bfc887..69090c4335d 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -151,9 +151,13 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) { source++; } while (*source) { + if ((*source < '0') || (*source > '9')) { + // 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; - if ((*source < '0') || (*source > '9')) - error("Invalid character in kReadNumber input"); result += *source - 0x30; source++; } From 9d50dac101b0d545b23397eef83f34b75a382303 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Mon, 31 May 2010 09:31:05 +0000 Subject: [PATCH 153/249] SCI: skip spaces in kReadNumber - this happens in lsl3 intro svn-id: r49345 --- engines/sci/engine/kstring.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 69090c4335d..90096d5c170 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -151,6 +151,10 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) { source++; } while (*source) { + if (*source == ' ') { + source++; // skip spaces - happens in lsl3 intro + continue; + } if ((*source < '0') || (*source > '9')) { // 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 From 3f4302214c334a590b8428fe7ae32c76e64b6ed5 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 11:25:59 +0000 Subject: [PATCH 154/249] The save/load object init code is now unified with the regular object init code svn-id: r49346 --- engines/sci/engine/savegame.cpp | 38 ++++++++------------------------- engines/sci/engine/segment.cpp | 21 ++++++++++-------- engines/sci/engine/segment.h | 10 ++++----- 3 files changed, 26 insertions(+), 43 deletions(-) diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 07c40b332c9..20bcb687d59 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -757,17 +757,11 @@ void SegManager::reconstructScripts(EngineState *s) { continue; Script *scr = (Script *)_heap[i]; - - // FIXME: Unify this code with script_instantiate_* ? scr->load(g_sci->getResMan()); scr->_localsBlock = (scr->_localsSegment == 0) ? NULL : (LocalVariables *)(_heap[scr->_localsSegment]); - 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++) { @@ -776,29 +770,15 @@ void SegManager::reconstructScripts(EngineState *s) { 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; + for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) { + reg_t addr = it->_value.getPos(); + Object *obj = scr->scriptObjInit(addr, false); - if (getSciVersion() >= SCI_VERSION_1_1) { - it->_value._baseMethod = (uint16 *)(scr->_buf + READ_LE_UINT16( data + 6 )); - it->_value._baseVars = (uint16 *)(scr->_buf + READ_LE_UINT16( data + 4 )); - } else { - int funct_area = READ_LE_UINT16(data + SCRIPT_FUNCTAREAPTR_OFFSET); - const Object *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; + 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); } - it->_value.setVarCount(baseObj->getVarCount()); - it->_value._baseObj = baseObj->_baseObj; - - it->_value._baseMethod = (uint16 *)(data + funct_area); - it->_value._baseVars = (uint16 *)(data + it->_value.getVarCount() * 2 + SCRIPT_SELECTOR_OFFSET); } } } diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index e1e7fd4ae6c..07fe6f0a927 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -227,10 +227,10 @@ const Object *Script::getObject(uint16 offset) const { return 0; } -Object *Script::scriptObjInit(reg_t obj_pos) { +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"); @@ -239,7 +239,7 @@ Object *Script::scriptObjInit(reg_t obj_pos) { VERIFY(obj_pos.offset + SCRIPT_FUNCTAREAPTR_OFFSET < (int)_bufSize, "Function area pointer stored beyond end of script\n"); - obj->init(_buf, obj_pos); + obj->init(_buf, obj_pos, fullObjectInit); return obj; } @@ -680,7 +680,7 @@ void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback //-------------------- object ---------------------------- -void Object::init(byte *buf, reg_t obj_pos) { +void Object::init(byte *buf, reg_t obj_pos, bool initVariables) { byte *data = buf + obj_pos.offset; _baseObj = data; _pos = obj_pos; @@ -697,8 +697,10 @@ void Object::init(byte *buf, reg_t obj_pos) { _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod); } - for (uint i = 0; i < _variables.size(); i++) - _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2))); + 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 { @@ -769,14 +771,15 @@ void Object::initSuperClass(SegManager *segMan, reg_t addr) { setSuperClassSelector(segMan->getClassAddress(superClassOffset, SCRIPT_GET_LOCK, addr)); } -bool Object::initBaseObject(SegManager *segMan, reg_t addr) { +bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass) { const Object *baseObj = segMan->getObject(getSpeciesSelector()); if (baseObj) { - setVarCount(baseObj->getVarCount()); + _variables.resize(baseObj->getVarCount()); // Copy base from species class, as we need its selector IDs _baseObj = baseObj->_baseObj; - initSuperClass(segMan, addr); + if (doInitSuperClass) + initSuperClass(segMan, addr); return true; } diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index dce1eb8445c..051354bf7a0 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -270,10 +270,9 @@ public: void markAsFreed() { _flags |= OBJECT_FLAG_FREED; } bool isFreed() const { return _flags & OBJECT_FLAG_FREED; } - void setVarCount(uint size) { _variables.resize(size); } uint getVarCount() const { return _variables.size(); } - void init(byte *buf, reg_t obj_pos); + void init(byte *buf, reg_t obj_pos, bool initVariables = true); reg_t getVariable(uint var) const { return _variables[var]; } reg_t &getVariableRef(uint var) { return _variables[var]; } @@ -295,16 +294,17 @@ public: void initSpecies(SegManager *segMan, reg_t addr); void initSuperClass(SegManager *segMan, reg_t addr); - bool initBaseObject(SegManager *segMan, reg_t addr); + bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true); // TODO: make private // 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 */ -private: Common::Array _variables; uint16 _methodCount; int _flags; @@ -394,7 +394,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 From 088e6456ea4d009b8ab0c91176c84dce34a8ea41 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 31 May 2010 12:10:30 +0000 Subject: [PATCH 155/249] In progress work implementing the animation player svn-id: r49347 --- engines/m4/animation.cpp | 466 ++++++++++++++++++++++++++++---------- engines/m4/animation.h | 103 ++++++--- engines/m4/assets.cpp | 25 +- engines/m4/assets.h | 3 +- engines/m4/console.cpp | 57 ++--- engines/m4/console.h | 3 +- engines/m4/m4.cpp | 4 - engines/m4/m4.h | 1 - engines/m4/mads_views.cpp | 32 ++- engines/m4/mads_views.h | 34 ++- 10 files changed, 536 insertions(+), 192 deletions(-) diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index fe46e121f07..4b6be82fad3 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -31,177 +31,397 @@ namespace M4 { // TODO: this code needs cleanup -Animation::Animation(MadsM4Engine *vm) { - _vm = vm; +MadsAnimation::MadsAnimation(MadsM4Engine *vm, MadsView *view): Animation(vm), _view(view) { _playing = false; + _font = NULL; + _unk1 = 0; + _skipLoad = false; + _unkIndex = -1; + _messageCtr= 0; } -void Animation::loadFullScreen(const char *filename) { - _vm->_palette->deleteAllRanges(); - load(filename); +MadsAnimation::~MadsAnimation() { + delete _font; } -void Animation::load(const char *filename) { - MadsPack anim(filename, _vm); +void MadsAnimation::load(const Common::String &filename) { + 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(); - _spriteSeriesNames = new Common::String[_seriesCount]; - printf("%i sprite series\n", _seriesCount); + animStream->skip(2); + _animMode = animStream->readUint16LE(); + assert(_animMode != 4); + _roomNumber = animStream->readUint16LE(); + _field12 = animStream->readUint16LE() != 0; + animStream->skip(4); + _spriteListIndex = animStream->readUint16LE(); + _scrollX = animStream->readUint16LE(); + _scrollY = animStream->readSint16LE(); + animStream->skip(10); + + animStream->read(buffer, 13); + _field24 = Common::String(buffer, 13); - // 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 - - for (int i = 0; i < _seriesCount; i++) { + for (int i = 0; i < 10; ++i) { animStream->read(buffer, 13); - _spriteSeriesNames[i] = Common::String(buffer); - //printf("%03d: %s\n", i, _spriteSeriesNames[i].c_str()); + _spriteSetNames[i] = Common::String(buffer, 13); + } - 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()); + 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); - // 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); + // TODO: Based on a weird usage of a flags word, a secondary method gets called here. + // Figure out secondary method, and when/if it's called - for (int k = 0; k < _spriteSeries->getCount(); k++) { - M4Sprite *spr = _spriteSeries->getFrame(k); - spr->translate(palData); // sprite pixel translation + // Initialise the reference list + for (int i = 0; i < spriteListCount; ++i) + _spriteListIndexes.push_back(-1); + + delete animStream; + + if (messagesCount > 0) { + // Chunk 2 + // Following is a list of any messages for the animation + + Common::SeekableReadStream *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++); - delete animStream; + for (int i = 0; i < frameEntryCount; i++) { + AnimFrameEntry rec; + rec.frameNumber = animStream->readUint16LE(); + rec.seqIndex = animStream->readByte(); + rec.spriteSlot.frameNumber = animStream->readUint16LE(); + rec.spriteSlot.xp = animStream->readUint16LE(); + rec.spriteSlot.yp = animStream->readUint16LE(); + rec.spriteSlot.depth = animStream->readUint16LE(); + rec.spriteSlot.scale = animStream->readUint16LE(); - // ------------------ + _frameEntries.push_back(rec); + } - // 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 - ); - */ + delete animStream; } - //printf("End pos: %i\n", animStream->pos()); - delete animStream; + if (miscEntriesCount > 0) { + // Chunk 4: Misc Data + animStream = anim.getItemStream(streamIndex); - // Chunk 3: unknown (seems to be sound data?) - // TODO + for (int i = 0; i < miscEntriesCount; ++i) { + AnimMiscEntry rec; + rec.soundNum = animStream->readUint16LE(); + rec.numTicks = animStream->readUint16LE(); + rec.posAdjust.x = animStream->readUint16LE(); + rec.posAdjust.y = animStream->readUint16LE(); + animStream->readUint16LE(); + + _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; + + _font = _vm->_font->getFont(fontName); + } + + // Load all the sprite sets for the animation + for (int i = 0; i < spriteListCount; ++i) { + _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 palette entries - I think it's adjusting sprite sets + // to the palette of the game screen + + // Process the sprite list indexes to remap them to the actual sprite list indexes + } -Animation::~Animation() { - //delete[] _spriteSeriesNames; - //delete[] _spriteSeries; - //delete[] _frameEntries; -} - -void Animation::start() { - _curFrame = 0; - _curFrameEntry = 0; +void MadsAnimation::start() { + _currentFrame = 0; + _oldFrameEntry = 0; //for (int i = 0; i < _seriesCount; i++) { //_spriteSeries[i] = new SpriteSeries((char*)_spriteSeriesNames[i].c_str()); //} _playing = true; - updateAnim(); + update(); } -bool Animation::updateAnim() { +bool MadsAnimation::update() { if (!_playing) return true; - // Get the scene background surface - M4Surface *bg = _vm->_scene->getBackgroundSurface(); + 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; + } - while (_frameEntries[_curFrameEntry].animFrameIndex == _curFrame) { - AnimationFrame *frame = &_frameEntries[_curFrameEntry]; - int seriesFrameIndex = (frame->seriesFrameIndex & 0x7FFF) - 1; - - // Write the sprite onto the screen - M4Sprite *spr = _spriteSeries->getFrame(seriesFrameIndex); - - // FIXME: correct x, y - spr->copyTo(bg, frame->x, frame->y, (int)spr->getTransparentColor()); - - // HACK: wait a bit - g_system->delayMillis(100); - - //printf("_curFrameEntry = %d\n", _curFrameEntry); - _curFrameEntry++; + if (newIndex >= 0) + load1(newIndex); } - //printf("_curFrame = %d\n", _curFrame); + // If it's not time for the next frame, then exit + if (_madsVm->_currentTimer < _nextFrameTimer) + return false; - _curFrame++; - if (_curFrame >= _frameCount) // anim done + // 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) && + (_view->_spriteSlots[slotIndex].seqIndex <= 0xFD)) { + // Flag the frame as animation sprite slot + _view->_spriteSlots[slotIndex].spriteType = EXPIRED_SPRITE; + } + } + + // Validate the current frame + if (_currentFrame > (int)_miscEntries.size()) { + // Is the animation allowed to be repeated? + if (_resetFlag) { + _currentFrame = 0; + _oldFrameEntry = 0; + } else { + _unk1 = true; + return true; + } + } + + // Handle starting any sound for this frame + AnimMiscEntry &misc = _miscEntries[_currentFrame]; + if (misc.soundNum) + _vm->_sound->playSound(misc.soundNum); + + bool screenChanged = false; + + // Handle any scrolling of the screen surface + if ((_scrollX != 0) || (_scrollY != 0)) { + _view->_bgSurface->scrollX(_scrollX); + _view->_bgSurface->scrollY(_scrollY); + + screenChanged = true; + } + + // 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(); + } + + 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; + } + ++index; + continue; + } + + if (spriteSlotIndex == 0) { + int slotIndex = _view->_spriteSlots.getIndex(); + _view->_spriteSlots[slotIndex].copy(_frameEntries[_oldFrameEntry].spriteSlot); + _view->_spriteSlots[slotIndex].seqIndex += 0x80; + + SpriteAsset &spriteSet = _view->_spriteSlots.getSprite( + _view->_spriteSlots[slotIndex].spriteListIndex); + + _view->_spriteSlots[slotIndex].spriteType = (spriteSet.getAssetType() == 0) ? + SPRITE_FOUR : SPRITE_ZERO; + } + 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 stop(); - return _curFrame >= _frameCount; + 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]; + } + } + } + + int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1); + _nextFrameTimer = _madsVm->_currentTimer + _miscEntries[frameNum].numTicks; + + return _currentFrame >= (int)_miscEntries.size(); } -void Animation::stop() { +void MadsAnimation::stop() { _playing = false; +} - for (int i = 0; i < _seriesCount; i++) { - // TODO: cleanup - //delete _spriteSeries[i]; - //_spriteSeries[i] = NULL; +void MadsAnimation::setCurrentFrame(int frameNumber) { + _currentFrame = frameNumber; + _oldFrameEntry = 0; + _unk1 = 0; +} + +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; } } // End of namespace M4 diff --git a/engines/m4/animation.h b/engines/m4/animation.h index c8be7f5cb36..b7e88f0871c 100644 --- a/engines/m4/animation.h +++ b/engines/m4/animation.h @@ -29,39 +29,90 @@ #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 Animation { - public: - Animation(MadsM4Engine *vm); - ~Animation(); +class AnimFrameEntry { +public: + int frameNumber; + int seqIndex; + SpriteSlotSubset spriteSlot; +}; - void load(const char *filename); - void loadFullScreen(const char *filename); - void start(); - bool updateAnim(); - void stop(); +class AnimMiscEntry { +public: + int soundNum; + int numTicks; + Common::Point posAdjust; +}; - private: - bool _playing; - MadsM4Engine *_vm; - int _seriesCount; - int _frameCount; - int _frameEntryCount; - AnimationFrame *_frameEntries; - Common::String *_spriteSeriesNames; - SpriteAsset *_spriteSeries; - int _curFrame, _curFrameEntry; +#define ANIM_SPRITE_SET_SIZE 50 + +enum MadsAnimationFlags {ANIM_CUSTOM_FONT = 0x20}; + +class MadsAnimation: public Animation { +private: + bool _playing; + MadsView *_view; + + int _spriteListCount; + Common::Array _messages; + Common::Array _frameEntries; + Common::Array _miscEntries; + Font *_font; + + uint8 _flags; + int _animMode; + int _roomNumber; + bool _field12; + int _spriteListIndex; + int _scrollX; + int _scrollY; + Common::String _field24; + Common::String _spriteSetNames[10]; + Common::String _lbmFilename; + Common::String _spritesFilename; + Common::String _soundName; + Common::Array _spriteListIndexes; + + int _currentFrame, _oldFrameEntry; + bool _resetFlag; + int _unk1; + bool _skipLoad; + int _unkIndex; + Common::Point _unkList[2]; + uint32 _nextFrameTimer; + int _messageCtr; + int _abortTimers; + AbortTimerMode _abortMode; + uint16 _actionNouns[3]; + + void load1(int frameNumber); + bool MadsAnimation::proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber); +public: + MadsAnimation(MadsM4Engine *vm, MadsView *view); + ~MadsAnimation(); + + virtual void load(const Common::String &filename); + virtual void start(); + virtual bool update(); + virtual void stop(); + virtual void setCurrentFrame(int frameNumber); }; } // End of namespace M4 diff --git a/engines/m4/assets.cpp b/engines/m4/assets.cpp index 14857e6f2b1..91c371dec59 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 diff --git a/engines/m4/assets.h b/engines/m4/assets.h index cd0ae6ba78d..816a8dcff0c 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); diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp index 0c2e80df0ef..d568584d30c 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 \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,34 @@ 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 \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->scene()->_sceneAnimation.loadFullScreen(resourceName); + else + _madsVm->scene()->_sceneAnimation.load(resourceName); + _madsVm->scene()->_sceneAnimation.start(); + + 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 b592f041cfe..53a47dada9b 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/m4.cpp b/engines/m4/m4.cpp index 2024138f67f..da271b10c97 100644 --- a/engines/m4/m4.cpp +++ b/engines/m4/m4.cpp @@ -145,7 +145,6 @@ MadsM4Engine::~MadsM4Engine() { delete _script; delete _ws; delete _random; - delete _animation; delete _palette; } @@ -184,7 +183,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"); @@ -581,8 +579,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 23204f22289..9937107668f 100644 --- a/engines/m4/m4.h +++ b/engines/m4/m4.h @@ -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/mads_views.cpp b/engines/m4/mads_views.cpp index 3b5ba9e24c2..e66b1d8d41f 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" @@ -43,6 +44,22 @@ 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; +} + +//-------------------------------------------------------------------------- + MadsSpriteSlots::MadsSpriteSlots(MadsView &owner): _owner(owner) { for (int i = 0; i < SPRITE_SLOTS_SIZE; ++i) { MadsSpriteSlot rec; @@ -74,6 +91,7 @@ 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)); _vm->res()->toss(resName); @@ -1125,8 +1143,20 @@ void MadsSequenceList::setAnimRange(int seqIndex, int startVal, int endVal) { //-------------------------------------------------------------------------- +Animation::Animation(MadsM4Engine *vm): _vm(vm) { +} + +void Animation::loadFullScreen(const Common::String &filename) { + _vm->_palette->deleteAllRanges(); + load(filename); +} + +//-------------------------------------------------------------------------- + MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceList(*this), - _kernelMessages(*this), _spriteSlots(*this), _dirtyAreas(*this), _textDisplay(*this) { + _kernelMessages(*this), _spriteSlots(*this), _dirtyAreas(*this), _textDisplay(*this), + // FIXME: There's probably a cleaner way to do this, and I don't think the destructor is ever called + _sceneAnimation(*new MadsAnimation(_vm, this)) { _textSpacing = -1; _ticksAmount = 3; _newTimeout = 0; diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h index 1661bac3df9..6d6d5762632 100644 --- a/engines/m4/mads_views.h +++ b/engines/m4/mads_views.h @@ -43,6 +43,16 @@ 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; @@ -55,12 +65,16 @@ 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, EXPIRED_SPRITE = -1 + BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, EXPIRED_SPRITE = -1, SPRITE_ZERO = 0, FOREGROUND_SPRITE = 1, + SPRITE_FOUR = 4 }; typedef Common::Array > SpriteList; @@ -138,7 +152,7 @@ public: }; #define TIMED_TEXT_SIZE 10 -#define TEXT_4A_SIZE 30 +#define INDEFINITE_TIMEOUT 9999999 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}; @@ -352,10 +366,26 @@ public: void setAnimRange(int seqIndex, int startVal, int endVal); }; +class Animation { +protected: + MadsM4Engine *_vm; +public: + Animation(MadsM4Engine *vm); + void loadFullScreen(const Common::String &filename); + + virtual void load(const Common::String &filename) = 0; + virtual void start() = 0; + virtual bool update() = 0; + virtual void stop() = 0; + virtual void setCurrentFrame(int frameNumber) = 0; +}; + + class MadsView { private: View *_view; public: + Animation &_sceneAnimation; MadsSpriteSlots _spriteSlots; MadsTextDisplay _textDisplay; MadsKernelMessageList _kernelMessages; From a963917e89f0f4d404872473c99fd998938984b2 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Mon, 31 May 2010 12:11:42 +0000 Subject: [PATCH 156/249] SCI: added TODO at kReadNumber space code svn-id: r49348 --- engines/sci/engine/kstring.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 90096d5c170..2ed4dfaac29 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -153,6 +153,8 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) { while (*source) { if (*source == ' ') { source++; // skip spaces - happens in lsl3 intro + // TODO: find the cause for those spaces. ssci breaks when encountering spaces, but we even get a leading + // space in lsl3 (" -97 ") which would actually mean we need to return 0 continue; } if ((*source < '0') || (*source > '9')) { From cc025ace18b2bd47e81d4ec1ac46aa9abb566c16 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 12:13:50 +0000 Subject: [PATCH 157/249] The code that loads saved game from the launcher can now load SCI2 saved games. Added an explanation why the injected call is necessary svn-id: r49349 --- engines/sci/engine/vm.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 03d67ae4510..f18a3844ebd 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -593,19 +593,25 @@ 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 + // TODO: SCI2.1 equivalent + if (g_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 - if (saveSlot < 0) - error("Requested to load invalid save slot"); // should never happen, really + // 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 = g_loadFromLauncher; + g_loadFromLauncher = -1; // invalidate slot, so that we don't load again - reg_t restoreArgv[2] = { NULL_REG, make_reg(0, saveSlot) }; // special call (argv[0] is NULL) - kRestoreGame(s, 2, restoreArgv); + 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); From ff40247376606412556e4cc39b4da3361842dd3c Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 12:27:13 +0000 Subject: [PATCH 158/249] Hopefully fixed compilation svn-id: r49350 --- engines/m4/animation.cpp | 2 +- engines/m4/animation.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index 4b6be82fad3..9c31cd35d72 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -106,7 +106,7 @@ void MadsAnimation::load(const Common::String &filename) { // Chunk 2 // Following is a list of any messages for the animation - Common::SeekableReadStream *animStream = anim.getItemStream(streamIndex++); + animStream = anim.getItemStream(streamIndex++); for (int i = 0; i < messagesCount; ++i) { AnimMessage rec; diff --git a/engines/m4/animation.h b/engines/m4/animation.h index b7e88f0871c..41ad40ef9ae 100644 --- a/engines/m4/animation.h +++ b/engines/m4/animation.h @@ -103,10 +103,10 @@ private: uint16 _actionNouns[3]; void load1(int frameNumber); - bool MadsAnimation::proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber); + bool proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber); public: MadsAnimation(MadsM4Engine *vm, MadsView *view); - ~MadsAnimation(); + virtual ~MadsAnimation(); virtual void load(const Common::String &filename); virtual void start(); From ba11596572c32c3282f03c643dc23f6050210a08 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 12:36:42 +0000 Subject: [PATCH 159/249] SCI: Silenced warning when no audio decoder is compiled in svn-id: r49351 --- engines/sci/sound/audio.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp index f64760b53e4..7748c0505ba 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) { From 2bebba8c947ed6862a915d074804fc819ffd1472 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Mon, 31 May 2010 12:38:15 +0000 Subject: [PATCH 160/249] Fix warning, whitespace svn-id: r49352 --- engines/m4/animation.h | 12 ++++++------ engines/m4/compression.h | 4 ++-- engines/m4/m4_views.cpp | 2 +- engines/m4/mads_views.cpp | 3 +++ engines/m4/mads_views.h | 7 ++++--- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/engines/m4/animation.h b/engines/m4/animation.h index 41ad40ef9ae..a5f3ea30856 100644 --- a/engines/m4/animation.h +++ b/engines/m4/animation.h @@ -90,7 +90,7 @@ private: Common::String _soundName; Common::Array _spriteListIndexes; - int _currentFrame, _oldFrameEntry; + int _currentFrame, _oldFrameEntry; bool _resetFlag; int _unk1; bool _skipLoad; @@ -106,12 +106,12 @@ private: bool proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber); public: MadsAnimation(MadsM4Engine *vm, MadsView *view); - virtual ~MadsAnimation(); + virtual ~MadsAnimation(); - virtual void load(const Common::String &filename); - virtual void start(); - virtual bool update(); - virtual void stop(); + virtual void load(const Common::String &filename); + virtual void start(); + virtual bool update(); + virtual void stop(); virtual void setCurrentFrame(int frameNumber); }; diff --git a/engines/m4/compression.h b/engines/m4/compression.h index 74fed357ff9..00e3d1f927e 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/m4_views.cpp b/engines/m4/m4_views.cpp index 3d633cef0d2..f4345787dff 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_views.cpp b/engines/m4/mads_views.cpp index e66b1d8d41f..f4f43c48f12 100644 --- a/engines/m4/mads_views.cpp +++ b/engines/m4/mads_views.cpp @@ -1146,6 +1146,9 @@ void MadsSequenceList::setAnimRange(int seqIndex, int startVal, int endVal) { Animation::Animation(MadsM4Engine *vm): _vm(vm) { } +Animation::~Animation() { +} + void Animation::loadFullScreen(const Common::String &filename) { _vm->_palette->deleteAllRanges(); load(filename); diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h index 6d6d5762632..6f264312d19 100644 --- a/engines/m4/mads_views.h +++ b/engines/m4/mads_views.h @@ -371,12 +371,13 @@ protected: MadsM4Engine *_vm; public: Animation(MadsM4Engine *vm); + virtual ~Animation(); void loadFullScreen(const Common::String &filename); virtual void load(const Common::String &filename) = 0; - virtual void start() = 0; - virtual bool update() = 0; - virtual void stop() = 0; + virtual void start() = 0; + virtual bool update() = 0; + virtual void stop() = 0; virtual void setCurrentFrame(int frameNumber) = 0; }; From b5a2e3c758361e19518f934f99a69056319f5de4 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 12:43:28 +0000 Subject: [PATCH 161/249] Fixed operator precedence warning svn-id: r49353 --- engines/sci/engine/vm.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index f18a3844ebd..3aee20692ad 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -594,10 +594,11 @@ static void callKernelFunc(EngineState *s, int kernelFuncNum, int argc) { //warning("callk %s", kernelFunc.orig_name.c_str()); // TODO: SCI2.1 equivalent - if (g_loadFromLauncher >= 0 && + if (g_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 + (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). From 753fdd6c123e3be04057ad4e4e35a95a3c39a2b7 Mon Sep 17 00:00:00 2001 From: Martin Kiewitz Date: Mon, 31 May 2010 13:52:07 +0000 Subject: [PATCH 162/249] SCI: break on anything, warn on anything but spaces in kReadNumber svn-id: r49355 --- engines/sci/engine/kstring.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 2ed4dfaac29..2681b612e9b 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -151,16 +151,14 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) { source++; } while (*source) { - if (*source == ' ') { - source++; // skip spaces - happens in lsl3 intro - // TODO: find the cause for those spaces. ssci breaks when encountering spaces, but we even get a leading - // space in lsl3 (" -97 ") which would actually mean we need to return 0 - continue; - } if ((*source < '0') || (*source > '9')) { - // 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"); + // 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; From d1da820a75a3a8f921c0b7cd1ae26bf6f7cb6729 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 31 May 2010 15:16:46 +0000 Subject: [PATCH 163/249] Fix for DW2 engine abort with message "Cannot find file hienergy.sc!". Bug introduced by r49086 change which could trim the last character of filenames. svn-id: r49356 --- engines/tinsel/handle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp index de573feee29..b006f718b7e 100644 --- a/engines/tinsel/handle.cpp +++ b/engines/tinsel/handle.cpp @@ -288,7 +288,7 @@ void LoadFile(MEMHANDLE *pH) { } // extract and zero terminate the filename - Common::strlcpy(szFilename, pH->szName, sizeof(pH->szName)); + Common::strlcpy(szFilename, pH->szName, sizeof(pH->szName)+1); if (f.open(szFilename)) { // read the data From 5bb4fadc4c85e14b5881fb3849ea32233dba91ed Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 31 May 2010 18:05:39 +0000 Subject: [PATCH 164/249] Fix change in r49356, Common::strlcpy should only be used on zero terminated source strings. The original code change with r49086 did only aimed at zero terminating the szFilename string (as the comment suggests), so I now changed it to use memcpy and a manual placement of the terminating zero. svn-id: r49357 --- engines/tinsel/handle.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp index b006f718b7e..60eb08a2dd2 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)+1); + memcpy(szFilename, pH->szName, sizeof(pH->szName)); + szFilename[sizeof(pH->szName)] = 0; if (f.open(szFilename)) { // read the data From 6c44df455ecbdd1a5793cbf2c3670491cc18bbd8 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 31 May 2010 18:22:29 +0000 Subject: [PATCH 165/249] Add OS2 specific files to repository svn-id: r49358 --- dists/os2/readme.os2 | 13 +++++++++++++ dists/os2/scummvm.ico | Bin 0 -> 3428 bytes 2 files changed, 13 insertions(+) create mode 100644 dists/os2/readme.os2 create mode 100644 dists/os2/scummvm.ico diff --git a/dists/os2/readme.os2 b/dists/os2/readme.os2 new file mode 100644 index 00000000000..a753323f4a1 --- /dev/null +++ b/dists/os2/readme.os2 @@ -0,0 +1,13 @@ +This is an OS/2 & eComStation build of ScummVM 1.1.1 + +To run, it requires: +* The libc063 runtime dll, available from ftp://ftp.netlabs.org/pub/gcc/libc-0.6.3-csd3.zip +* The gcc444 runtime dll, available from http://download.smedley.info/gcc444.zip +* The SDL dll's available from ftp://ftp.netlabs.org/pub/sdl/sdl-1.2.10-bin-20080804.zip + +All feedback is appreciated! + +Thanks! + +Paul Smedley +5th May, 2010 \ No newline at end of file diff --git a/dists/os2/scummvm.ico b/dists/os2/scummvm.ico new file mode 100644 index 0000000000000000000000000000000000000000..c22ca23608bc9bc44f4d7ce5fa04a81c087ee19b GIT binary patch literal 3428 zcmeH~Elguu5Xa{p?q>^>uLOx{!b?byNb-_RNGf=F=1LrrIwXPwi7OIER*gh7LE46I{)L3=%~qNs z&aar6$+!2Y?cyV zU3^e5kRCoL7)T!<6bxj54+;ii_@H30v$G?6dwa6KzfTR+%*D*8fw{NwK*4;>{1go8 znlW=UpC^4%Fz;6%9~2B^fDZ}=V)&q7aBy%Shlhu9baW)g$H#JVazY)aWIv6U@hNS5 zP%w}VJ}4MS7atT1UH{U(3zSjojYe%H7?a z+~40*%LDy*po#}-d7u`2P%w}VJ}4MS7atT1q=yd*2GYj|1p^u2gMxt=J}4MGK0eCR z(~~?uKg-L@i@d(RQj_lx?~KJu+W4SgART;AFpw@jC>Tf&9~2Cvj}Hn4GQbA~0}7!g z{NZ6Cx37>_fwhI)_+TI%d{8iuEn=q80pQnrRm;B$JjteT2Pq_|Ga=3*6PbLre%n$F~X)1e~ioSVn|tkWSh zL%B>dhBDV>d1Jb|n78y`F?}2Gq5*qnOER<=+%1&-7ezMm*zrxe=}R<~ zIaFye3g{`DO$x3m&polg!F5Anl+j*4FICc{rty&E{m}VokEbd&a8kFJkMjD?=Y;zD zF`elJp)c(FSYbR(!}Xo*Aq6h^33287%wxRq>b!wT?!p)`-dH&A;?#ce2IL%F7sj|n zvGmy{_1_U%;gX@vbH*pnZe0b9%S6<@fIuck&JS>>OKR->_q>TB85TmQxV E0nmDu1^@s6 literal 0 HcmV?d00001 From 443c0d4f935ce908caf79bdc94183ad5214dc7c1 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 31 May 2010 18:28:26 +0000 Subject: [PATCH 166/249] DS: Use gScummVMVersion in dsmain.cpp; merge 1.1.1 changes in readme_ds.txt svn-id: r49359 --- backends/platform/ds/arm9/dist/readme_ds.txt | 6 +++++- backends/platform/ds/arm9/source/dsmain.cpp | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/backends/platform/ds/arm9/dist/readme_ds.txt b/backends/platform/ds/arm9/dist/readme_ds.txt index 191b358f787..c4f1263452a 100644 --- a/backends/platform/ds/arm9/dist/readme_ds.txt +++ b/backends/platform/ds/arm9/dist/readme_ds.txt @@ -41,6 +41,10 @@ Visit the main ScummVM website What's New? ------------------------------------------------------------------------ +ScummVM DS 1.1.1 + + * Bugfix release: no new features + ScummVM DS 1.1.0 * New games are supported in this stable build: Return to Zork, Rodney's @@ -319,7 +323,7 @@ CANNOT DO THIS. ------------------------------------------------------------------------ I'm glad you asked. Here is a list of the compatible games in version -1.1.0. Demo versions of the games listed should work too. +1.1.1. Demo versions of the games listed should work too. Flight of the Amazon Queen, Beneath a Steel Sky, and Lure of the Temptress have generously been released as freeware by the original diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp index 4828ae21925..5a63e5f08fa 100644 --- a/backends/platform/ds/arm9/source/dsmain.cpp +++ b/backends/platform/ds/arm9/source/dsmain.cpp @@ -103,6 +103,7 @@ #include "profiler/cyg-profile.h" #endif #include "backends/fs/ds/ds-fs.h" +#include "base/version.h" #include "engine.h" extern "C" void OurIntrMain(void); @@ -3162,7 +3163,7 @@ int main(void) { consolePrintf("-------------------------------\n"); consolePrintf("ScummVM DS\n"); consolePrintf("Ported by Neil Millstone\n"); - consolePrintf("Version 1.1.0 "); + consolePrintf("Version %s ", gScummVMVersion); #if defined(DS_BUILD_A) consolePrintf("build A\n"); consolePrintf("Lucasarts SCUMM games (SCUMM)\n"); From de2e935b2c6ca2091e37068772931da1ec51ceb3 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 18:31:37 +0000 Subject: [PATCH 167/249] Wrote the initialization code for the exports and synonyms table to make more sense and fixed a bug with the initialization of the synonyms pointer, introduced with rev #49336 svn-id: r49360 --- engines/sci/engine/segment.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 07fe6f0a927..10d73d73255 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -194,18 +194,21 @@ void Script::load(ResourceManager *resMan) { _numSynonyms = 0; if (getSciVersion() >= SCI_VERSION_1_1) { - if (READ_LE_UINT16(_buf + 6) > 0) { - _exportTable = (const uint16 *)(_buf + 6 + 2); + 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) { - _exportTable += 3; - _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1); + _numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1); + _exportTable += 3; // skip header plus 2 bytes (_exportTable is a uint16 pointer) } _synonyms = findBlock(SCI_OBJ_SYNONYMS); - _numSynonyms = _synonyms ? READ_SCI11ENDIAN_UINT16(_synonyms - 2) / 4 : 0; + if (_synonyms) { + _numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4; + _synonyms += 4; // skip header + } } } From 844ef9ba1a08de70058cfa8014f55a801b7c77aa Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 18:35:13 +0000 Subject: [PATCH 168/249] Merged all the script relocation code inside script_instantiate(), and changed the warning when reading an invalid species into an error (as it's severe, and if it happens it means something is seriously wrong) svn-id: r49361 --- engines/sci/engine/script.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 304fd4d6fd3..3fb8a5763e6 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -252,10 +252,9 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { } } -int script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) { +void script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) { int objType; uint32 objLength = 0; - int relocation = -1; bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); uint16 curOffset = oldScriptHeader ? 2 : 0; @@ -293,11 +292,11 @@ int script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) { warning("Applying workaround for an off-by-one invalid species access"); segMan->resizeClassTable(segMan->classTableSize() + 1); } else { - warning("Invalid species %d(0x%x) not in interval " + error("Invalid species %d(0x%x) not in interval " "[0,%d) while instantiating script at segment %d\n", species, species, segMan->classTableSize(), segmentId); - return 0; + return; } } @@ -342,21 +341,12 @@ int script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) { } } // 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 < scr->getScriptSize() - 2); - - if (relocation >= 0) - scr->relocate(make_reg(segmentId, relocation)); - - return segmentId; // instantiation successful } int script_instantiate(ResourceManager *resMan, SegManager *segMan, int scriptNum) { @@ -381,10 +371,14 @@ int script_instantiate(ResourceManager *resMan, SegManager *segMan, int scriptNu segMan->scriptInitialiseLocals(make_reg(segmentId, heapStart + 4)); segMan->scriptInitialiseObjectsSci11(segmentId); scr->relocate(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(scr->_heapStart))); - return segmentId; } else { - return script_instantiate_sci0(scr, segmentId, segMan); + script_instantiate_sci0(scr, segmentId, segMan); + byte *relocationBlock = scr->findBlock(SCI_OBJ_POINTERS); + if (relocationBlock) + scr->relocate(make_reg(segmentId, relocationBlock - scr->_buf + 4)); } + + return segmentId; } void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg) { From 2138fe0d5afbcb8566c90e8338a5c2896282772f Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 31 May 2010 21:29:43 +0000 Subject: [PATCH 169/249] Fix our interpretation of the audio compression types to what FFmpeg currently does. Should fix bug #3009282. svn-id: r49362 --- graphics/video/smk_decoder.cpp | 35 +++++++++++++++++++++------------- graphics/video/smk_decoder.h | 10 ++++++++-- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/graphics/video/smk_decoder.cpp b/graphics/video/smk_decoder.cpp index adc96a78206..0b7de774ebb 100644 --- a/graphics/video/smk_decoder.cpp +++ b/graphics/video/smk_decoder.cpp @@ -422,27 +422,36 @@ bool SmackerDecoder::load(Common::SeekableReadStream &stream) { for (i = 0; i < 7; ++i) { // AudioRate - Frequency and format information for each sound track, up to 7 audio tracks. // The 32 constituent bits have the following meaning: - // * bit 31 - data is compressed + // * bit 31 - indicates Huffman + DPCM compression // * bit 30 - indicates that audio data is present for this track // * bit 29 - 1 = 16-bit audio; 0 = 8-bit audio // * bit 28 - 1 = stereo audio; 0 = mono audio - // * bits 27-26 - if both set to zero - use v2 sound decompression + // * bit 27 - indicates Bink RDFT compression + // * bit 26 - indicates Bink DCT compression // * bits 25-24 - unused // * bits 23-0 - audio sample rate uint32 audioInfo = _fileStream->readUint32LE(); - _header.audioInfo[i].isCompressed = audioInfo & 0x80000000; _header.audioInfo[i].hasAudio = audioInfo & 0x40000000; _header.audioInfo[i].is16Bits = audioInfo & 0x20000000; _header.audioInfo[i].isStereo = audioInfo & 0x10000000; - _header.audioInfo[i].hasV2Compression = !(audioInfo & 0x8000000) && - !(audioInfo & 0x4000000); _header.audioInfo[i].sampleRate = audioInfo & 0xFFFFFF; - if (_header.audioInfo[i].hasV2Compression) - warning("Unhandled Smacker v2 audio compression"); + if (audioInfo & 0x8000000) + _header.audioInfo[i].compression = kCompressionRDFT; + else if (audioInfo & 0x4000000) + _header.audioInfo[i].compression = kCompressionDCT; + else if (audioInfo & 0x80000000) + _header.audioInfo[i].compression = kCompressionDPCM; + else + _header.audioInfo[i].compression = kCompressionNone; - if (_header.audioInfo[i].hasAudio && i == 0) - _audioStream = Audio::makeQueuingAudioStream(_header.audioInfo[0].sampleRate, _header.audioInfo[0].isStereo); + if (_header.audioInfo[i].hasAudio) { + if (_header.audioInfo[i].compression == kCompressionRDFT || _header.audioInfo[i].compression == kCompressionDCT) + warning("Unhandled Smacker v2 audio compression"); + + if (i == 0) + _audioStream = Audio::makeQueuingAudioStream(_header.audioInfo[0].sampleRate, _header.audioInfo[0].isStereo); + } } _header.dummy = _fileStream->readUint32LE(); @@ -531,7 +540,7 @@ Surface *SmackerDecoder::decodeNextFrame() { chunkSize = _fileStream->readUint32LE(); chunkSize -= 4; // subtract the first 4 bytes (chunk size) - if (_header.audioInfo[i].isCompressed) { + if (_header.audioInfo[i].compression != kCompressionNone) { dataSizeUnpacked = _fileStream->readUint32LE(); chunkSize -= 4; // subtract the next 4 bytes (unpacked data size) } else { @@ -544,11 +553,11 @@ Surface *SmackerDecoder::decodeNextFrame() { _fileStream->read(soundBuffer, chunkSize); - if (_header.audioInfo[i].hasV2Compression) { - // TODO: Compressed audio (Bink RDFT encoded) + if (_header.audioInfo[i].compression == kCompressionRDFT || _header.audioInfo[i].compression == kCompressionDCT) { + // TODO: Compressed audio (Bink RDFT/DCT encoded) free(soundBuffer); continue; - } else if (_header.audioInfo[i].isCompressed) { + } else if (_header.audioInfo[i].compression == kCompressionDPCM) { // Compressed audio (Huffman DPCM encoded) queueCompressedBuffer(soundBuffer, chunkSize, dataSizeUnpacked, i); free(soundBuffer); diff --git a/graphics/video/smk_decoder.h b/graphics/video/smk_decoder.h index 437f47f2d64..6bf671f3182 100644 --- a/graphics/video/smk_decoder.h +++ b/graphics/video/smk_decoder.h @@ -80,12 +80,18 @@ private: uint getBlockRun(int index) { return (index <= 58) ? index + 1 : 128 << (index - 59); } void queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize, int streamNum); + enum AudioCompression { + kCompressionNone, + kCompressionDPCM, + kCompressionRDFT, + kCompressionDCT + }; + struct AudioInfo { - bool isCompressed; + AudioCompression compression; bool hasAudio; bool is16Bits; bool isStereo; - bool hasV2Compression; uint32 sampleRate; }; From c9a38abf605197c4641b74fcef06d44d8d87b2d7 Mon Sep 17 00:00:00 2001 From: Tony Puccinelli Date: Mon, 31 May 2010 22:41:46 +0000 Subject: [PATCH 170/249] modifications to get the ps2 to use the ps2loader svn-id: r49363 --- backends/module.mk | 1 + backends/platform/ps2/module.mk | 3 ++- backends/platform/ps2/systemps2.cpp | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/backends/module.mk b/backends/module.mk index 59df56b4685..46c9e166a66 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -35,6 +35,7 @@ MODULE_OBJS := \ plugins/sdl/sdl-provider.o \ plugins/win32/win32-provider.o \ plugins/psp/psp-provider.o \ + plugins/ps2/ps2-provider.o \ saves/savefile.o \ saves/default/default-saves.o \ saves/posix/posix-saves.o \ diff --git a/backends/platform/ps2/module.mk b/backends/platform/ps2/module.mk index 86b12cb6680..69a28b93c4b 100644 --- a/backends/platform/ps2/module.mk +++ b/backends/platform/ps2/module.mk @@ -16,7 +16,8 @@ MODULE_OBJS := \ systemps2.o \ ps2mutex.o \ ps2time.o \ - ps2debug.o + ps2debug.o \ + ps2loader.o MODULE_DIRS += \ backends/platform/ps2/ diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp index 49d583d1a12..fe8cc6b29cc 100644 --- a/backends/platform/ps2/systemps2.cpp +++ b/backends/platform/ps2/systemps2.cpp @@ -59,6 +59,7 @@ #include "backends/platform/ps2/ps2debug.h" #include "backends/fs/ps2/ps2-fs-factory.h" +#include "backends/plugins/ps2/ps2-provider.h" #include "backends/saves/default/default-saves.h" #include "common/config-manager.h" @@ -132,6 +133,10 @@ extern "C" int main(int argc, char *argv[]) { g_systemPs2->init(); +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new PS2PluginProvider()); +#endif + sioprintf("init done. starting ScummVM.\n"); int res = scummvm_main(argc, argv); sioprintf("scummvm_main terminated: %d\n", res); From 25fb93465df5903bf4b03f47b10b69def667ef26 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 31 May 2010 22:57:05 +0000 Subject: [PATCH 171/249] Added a new console command, verify_scripts, used for sanity checking of SCI1.1-SCI2.1 game scripts svn-id: r49364 --- engines/sci/console.cpp | 36 ++++++++++++++++++++++++++++++++++++ engines/sci/console.h | 1 + 2 files changed, 37 insertions(+) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 98046cfa324..3b237f44edf 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -105,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)); @@ -324,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"); @@ -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 *resources = _engine->getResMan()->listResources(kResourceTypeScript); + sort(resources->begin(), resources->end(), ResourceIdLess()); + Common::List::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"); diff --git a/engines/sci/console.h b/engines/sci/console.h index c88795ae269..2b13e03ef68 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); From 9d72dde5e7d3e92e7e870350c0b24bf556e425f6 Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Mon, 31 May 2010 22:58:22 +0000 Subject: [PATCH 172/249] Fix trunk compilation (don't try to compile non-existing files) svn-id: r49365 --- backends/module.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/backends/module.mk b/backends/module.mk index 46c9e166a66..59df56b4685 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -35,7 +35,6 @@ MODULE_OBJS := \ plugins/sdl/sdl-provider.o \ plugins/win32/win32-provider.o \ plugins/psp/psp-provider.o \ - plugins/ps2/ps2-provider.o \ saves/savefile.o \ saves/default/default-saves.o \ saves/posix/posix-saves.o \ From 400542a1fe688bb702a89333c833bc1d89dd1ed4 Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Mon, 31 May 2010 23:04:30 +0000 Subject: [PATCH 173/249] Revert the rest of 49362, which wasn't meant for trunk svn-id: r49366 --- backends/platform/ps2/module.mk | 3 +-- backends/platform/ps2/systemps2.cpp | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/backends/platform/ps2/module.mk b/backends/platform/ps2/module.mk index 69a28b93c4b..86b12cb6680 100644 --- a/backends/platform/ps2/module.mk +++ b/backends/platform/ps2/module.mk @@ -16,8 +16,7 @@ MODULE_OBJS := \ systemps2.o \ ps2mutex.o \ ps2time.o \ - ps2debug.o \ - ps2loader.o + ps2debug.o MODULE_DIRS += \ backends/platform/ps2/ diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp index fe8cc6b29cc..49d583d1a12 100644 --- a/backends/platform/ps2/systemps2.cpp +++ b/backends/platform/ps2/systemps2.cpp @@ -59,7 +59,6 @@ #include "backends/platform/ps2/ps2debug.h" #include "backends/fs/ps2/ps2-fs-factory.h" -#include "backends/plugins/ps2/ps2-provider.h" #include "backends/saves/default/default-saves.h" #include "common/config-manager.h" @@ -133,10 +132,6 @@ extern "C" int main(int argc, char *argv[]) { g_systemPs2->init(); -#ifdef DYNAMIC_MODULES - PluginManager::instance().addPluginProvider(new PS2PluginProvider()); -#endif - sioprintf("init done. starting ScummVM.\n"); int res = scummvm_main(argc, argv); sioprintf("scummvm_main terminated: %d\n", res); From e083c20da1aab0090a5fc3ea624c9810c63dad52 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 1 Jun 2010 14:41:48 +0000 Subject: [PATCH 174/249] The system strings segment is a fixed segment of the segment manager, which doesn't change during the game, thus move all the system strings code and variables inside the segment manager svn-id: r49372 --- engines/sci/engine/game.cpp | 15 ++------------- engines/sci/engine/kernel32.cpp | 14 +++++++------- engines/sci/engine/kfile.cpp | 2 +- engines/sci/engine/savegame.cpp | 4 +--- engines/sci/engine/seg_manager.cpp | 24 +++++++++++++++++++----- engines/sci/engine/seg_manager.h | 21 ++++++++++++++------- engines/sci/engine/state.cpp | 3 --- engines/sci/engine/state.h | 4 ---- engines/sci/sci.cpp | 5 ----- 9 files changed, 44 insertions(+), 48 deletions(-) diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 232e0eca554..02e66f2142d 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -67,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; @@ -108,7 +102,7 @@ int game_init(EngineState *s) { 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); + s->_voc->parser_base = make_reg(s->_segMan->getSysStringsSegment(), SYS_STRING_PARSER_BASE); } // Initialize menu TODO: Actually this should be another init() @@ -117,11 +111,6 @@ int game_init(EngineState *s) { 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->game_start_time = g_system->getMillis(); s->last_wait_time = s->game_start_time; diff --git a/engines/sci/engine/kernel32.cpp b/engines/sci/engine/kernel32.cpp index b705bbb7947..3dd596494d4 100644 --- a/engines/sci/engine/kernel32.cpp +++ b/engines/sci/engine/kernel32.cpp @@ -575,16 +575,16 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { uint32 count = argv[5].toSint16() == -1 ? string2.size() - 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); + if ((uint32)s->_segMan->sysStrings->_strings[argv[1].toUint16()]._maxSize < index1 + count) { + delete[] s->_segMan->sysStrings->_strings[argv[1].toUint16()]._value; + s->_segMan->sysStrings->_strings[argv[1].toUint16()]._maxSize = index1 + count; + s->_segMan->sysStrings->_strings[argv[1].toUint16()]._value = new char[index1 + count]; + memset(s->_segMan->sysStrings->_strings[argv[1].toUint16()]._value, 0, index1 + count); } - strncpy(s->sys_strings->_strings[argv[1].toUint16()]._value + index1, string2.c_str() + index2, count); + strncpy(s->_segMan->sysStrings->_strings[argv[1].toUint16()]._value + index1, string2.c_str() + index2, count); } else { SciString *string1 = s->_segMan->lookupString(argv[1]); diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index e6b9a5388c6..ba8714366fc 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -428,7 +428,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) { diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 20bcb687d59..85c9915d578 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -893,8 +893,6 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { 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]); // Time state: retval->last_wait_time = g_system->getMillis(); @@ -903,7 +901,7 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { // static parser information: if (retval->_voc) - retval->_voc->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE); + retval->_voc->parser_base = make_reg(s->_segMan->getSysStringsSegment(), SYS_STRING_PARSER_BASE); retval->successor = NULL; diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 92eb1c47175..4d3e6f754e9 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(); } @@ -81,6 +80,25 @@ void SegManager::resetSegMan() { 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. @@ -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"); diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index c3efd483c26..9312f51f9d5 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -182,16 +182,11 @@ 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 /** @@ -441,6 +436,11 @@ public: 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 _heap; // Only accessible from saveLoadWithSerializer() @@ -467,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/state.cpp b/engines/sci/engine/state.cpp index c9398d7ed53..3c36a05c2fc 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -94,9 +94,6 @@ EngineState::EngineState(Vocabulary *voc, SegManager *segMan) script_000 = 0; - sys_strings_segment = 0; - sys_strings = 0; - _gameObj = NULL_REG; gc_countdown = 0; diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index ad9de9e13e3..2025b49f51d 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -160,10 +160,6 @@ public: */ void shrinkStackToBase(); - /* System strings */ - SegmentId sys_strings_segment; - SystemStrings *sys_strings; - reg_t _gameObj; /**< Pointer to the game object */ int gc_countdown; /**< Number of kernel calls until next gc */ diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 39f117475bd..31d473a0b51 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -233,11 +233,6 @@ Common::Error SciEngine::run() { 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); From 9c92bd1b810621bdaa779bd3354b10ad048c7924 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 1 Jun 2010 15:11:20 +0000 Subject: [PATCH 175/249] The parser vocabulary remains static throughout the game, thus it has been removed from the engine state svn-id: r49373 --- engines/sci/engine/game.cpp | 10 ++++++---- engines/sci/engine/kevent.cpp | 4 ++-- engines/sci/engine/kparse.cpp | 28 +++++++++++++++------------- engines/sci/engine/savegame.cpp | 7 +------ engines/sci/engine/state.cpp | 4 ++-- engines/sci/engine/state.h | 3 +-- engines/sci/parser/said.cpp | 7 ++++--- engines/sci/parser/said.y | 7 ++++--- engines/sci/sci.cpp | 2 +- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 02e66f2142d..03c3594f038 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -99,10 +99,12 @@ 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->_segMan->getSysStringsSegment(), 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() diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index f0432f0c96d..35f71efedd6 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -67,8 +67,8 @@ 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 writeSelectorValue(segMan, obj, SELECTOR(x), mousePos.x); writeSelectorValue(segMan, obj, SELECTOR(y), mousePos.y); diff --git a/engines/sci/engine/kparse.cpp b/engines/sci/engine/kparse.cpp index 97a75dcb1cd..785ff39d228 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() || (readSelectorValue(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) - writeSelectorValue(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); @@ -117,17 +118,17 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) { s->r_acc = make_reg(0, 1); writeSelectorValue(segMan, event, SELECTOR(claimed), 1); - invokeSelector(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; + voc->parserIsValid = true; writeSelectorValue(segMan, event, SELECTOR(claimed), 0); #ifdef DEBUG_PARSER - s->_voc->dumpParseTree(); + voc->dumpParseTree(); #endif } @@ -136,11 +137,11 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) { s->r_acc = make_reg(0, 0); 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: */ - invokeSelector(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,12 +157,13 @@ 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(readSelector(segMan, object, SELECTOR(elements))); node = s->_segMan->lookupNode(list->first); @@ -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/savegame.cpp b/engines/sci/engine/savegame.cpp index 85c9915d578..bba087d9536 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -857,7 +857,7 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { } // Create a new EngineState object - retval = new EngineState(s->_voc, s->_segMan); + retval = new EngineState(s->_segMan); retval->_event = s->_event; // Copy some old data @@ -898,11 +898,6 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { 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->_segMan->getSysStringsSegment(), SYS_STRING_PARSER_BASE); - retval->successor = NULL; #ifdef USE_OLD_MUSIC_FUNCTIONS diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index 3c36a05c2fc..5325d128be9 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -69,8 +69,8 @@ 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() { #ifdef USE_OLD_MUSIC_FUNCTIONS sfx_init_flags = 0; diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index 2025b49f51d..0746e8e0a8a 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -95,14 +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; /* Non-VM information */ diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp index 5cd1310ad30..f49704372ab 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 27486c57949..cbb2ff3e624 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/sci.cpp b/engines/sci/sci.cpp index 31d473a0b51..1de42ab1157 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -190,7 +190,7 @@ Common::Error SciEngine::run() { _features = new GameFeatures(segMan, _kernel); - _gamestate = new EngineState(_vocabulary, segMan); + _gamestate = new EngineState(segMan); _gamestate->_event = new SciEvent(_resMan); From caf1a6bee4bb60014290a2208ec0daa0c68496cd Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 1 Jun 2010 15:38:09 +0000 Subject: [PATCH 176/249] Remove dead code from PS2 and GP2x backends svn-id: r49374 --- backends/platform/gp2x/gp2x-common.h | 18 ------------------ backends/platform/gp2x/gp2x.cpp | 25 +------------------------ backends/platform/ps2/systemps2.cpp | 17 ----------------- backends/platform/ps2/systemps2.h | 6 ------ 4 files changed, 1 insertion(+), 65 deletions(-) diff --git a/backends/platform/gp2x/gp2x-common.h b/backends/platform/gp2x/gp2x-common.h index 79eb3f65cff..9f3a79ff975 100644 --- a/backends/platform/gp2x/gp2x-common.h +++ b/backends/platform/gp2x/gp2x-common.h @@ -121,19 +121,6 @@ public: virtual Audio::Mixer *getMixer(); - // Poll CD status - // Returns true if cd audio is playing - bool pollCD(); - - // Play CD audio track - void playCD(int track, int num_loops, int start_frame, int duration); - - // Stop CD audio track - void stopCD(); - - // Update CD audio status - void updateCD(); - // Quit void quit(); @@ -206,11 +193,6 @@ protected: bool _overlayVisible; Graphics::PixelFormat _overlayFormat; - // CD Audio - SDL_CD *_cdrom; - int _cdTrack, _cdNumLoops, _cdStartFrame, _cdDuration; - uint32 _cdEndTime, _cdStopTime; - enum { DF_WANT_RECT_OPTIM = 1 << 0 }; diff --git a/backends/platform/gp2x/gp2x.cpp b/backends/platform/gp2x/gp2x.cpp index 3d4ed51c1f9..8669671c4ee 100644 --- a/backends/platform/gp2x/gp2x.cpp +++ b/backends/platform/gp2x/gp2x.cpp @@ -246,7 +246,7 @@ OSystem_GP2X::OSystem_GP2X() _hwscreen(0), _screen(0), _tmpscreen(0), _overlayVisible(false), _overlayscreen(0), _tmpscreen2(0), - _cdrom(0), _scalerProc(0), _modeChanged(false), _screenChangeCount(0), _dirtyChecksums(0), + _scalerProc(0), _modeChanged(false), _screenChangeCount(0), _dirtyChecksums(0), _mouseVisible(false), _mouseNeedsRedraw(false), _mouseData(0), _mouseSurface(0), _mouseOrigSurface(0), _cursorTargetScale(1), _cursorPaletteDisabled(true), _joystick(0), @@ -650,26 +650,3 @@ Audio::Mixer *OSystem_GP2X::getMixer() { assert(_mixer); return _mixer; } - -#pragma mark - -#pragma mark --- CD Audio --- -#pragma mark - - -bool OSystem_GP2X::openCD(int drive) { - return (_cdrom = NULL); -} - -void OSystem_GP2X::stopCD() { -} - -void OSystem_GP2X::playCD(int track, int num_loops, int start_frame, int duration) { - return; -} - -bool OSystem_GP2X::pollCD() { - return false; -} - -void OSystem_GP2X::updateCD() { - return; -} diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp index 49d583d1a12..7659d5194d3 100644 --- a/backends/platform/ps2/systemps2.cpp +++ b/backends/platform/ps2/systemps2.cpp @@ -624,23 +624,6 @@ void OSystem_PS2::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, _screen->setMouseOverlay(buf, w, h, hotspot_x, hotspot_y, keycolor); } -bool OSystem_PS2::openCD(int drive) { - return false; -} - -bool OSystem_PS2::pollCD(void) { - return false; -} - -void OSystem_PS2::playCD(int track, int num_loops, int start_frame, int duration) { -} - -void OSystem_PS2::stopCD(void) { -} - -void OSystem_PS2::updateCD(void) { -} - void OSystem_PS2::showOverlay(void) { _screen->showOverlay(); } diff --git a/backends/platform/ps2/systemps2.h b/backends/platform/ps2/systemps2.h index 0068ffd93f5..78973ed3f0c 100644 --- a/backends/platform/ps2/systemps2.h +++ b/backends/platform/ps2/systemps2.h @@ -97,12 +97,6 @@ public: virtual Audio::Mixer *getMixer(); - virtual bool openCD(int drive); - virtual bool pollCD(); - virtual void playCD(int track, int num_loops, int start_frame, int duration); - virtual void stopCD(); - virtual void updateCD(); - virtual MutexRef createMutex(void); virtual void lockMutex(MutexRef mutex); virtual void unlockMutex(MutexRef mutex); From 1f54cdf90d5d14c4acee4cd2a358585b43abb188 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 1 Jun 2010 15:38:34 +0000 Subject: [PATCH 177/249] SCI: Fix malloc<->new mismatch in SysStrings, try to increase readability svn-id: r49375 --- engines/sci/engine/kernel32.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/engines/sci/engine/kernel32.cpp b/engines/sci/engine/kernel32.cpp index 3dd596494d4..b1325432069 100644 --- a/engines/sci/engine/kernel32.cpp +++ b/engines/sci/engine/kernel32.cpp @@ -577,14 +577,14 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { // We have a special case here for argv[1] being a system string if (argv[1].segment == s->_segMan->getSysStringsSegment()) { // Resize if necessary - if ((uint32)s->_segMan->sysStrings->_strings[argv[1].toUint16()]._maxSize < index1 + count) { - delete[] s->_segMan->sysStrings->_strings[argv[1].toUint16()]._value; - s->_segMan->sysStrings->_strings[argv[1].toUint16()]._maxSize = index1 + count; - s->_segMan->sysStrings->_strings[argv[1].toUint16()]._value = new char[index1 + count]; - memset(s->_segMan->sysStrings->_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->_segMan->sysStrings->_strings[argv[1].toUint16()]._value + index1, string2.c_str() + index2, count); + strncpy(s->_segMan->sysStrings->_strings[sysStringId]._value + index1, string2.c_str() + index2, count); } else { SciString *string1 = s->_segMan->lookupString(argv[1]); From 65f3cfcbd816fe05437298cd46621d9f058aaea3 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 1 Jun 2010 15:48:17 +0000 Subject: [PATCH 178/249] Stop reconstructing the engine state when restoring, but reset it instead svn-id: r49376 --- engines/sci/engine/game.cpp | 7 ++-- engines/sci/engine/savegame.cpp | 65 ++++++++++++++------------------- engines/sci/engine/state.cpp | 56 +++++++++++++++------------- engines/sci/engine/state.h | 7 +++- engines/sci/engine/vm.cpp | 19 ++++------ 5 files changed, 74 insertions(+), 80 deletions(-) diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 03c3594f038..bc10099e52b 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -111,7 +111,7 @@ int game_init(EngineState *s) { if (g_sci->_gfxMenu) g_sci->_gfxMenu->reset(); - s->successor = NULL; // No successor + s->restoring = false; s->game_start_time = g_system->getMillis(); s->last_wait_time = s->game_start_time; @@ -134,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/savegame.cpp b/engines/sci/engine/savegame.cpp index bba087d9536..798f8894600 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -821,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 @@ -856,76 +855,66 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { thumbnail = 0; } - // Create a new EngineState object - retval = new EngineState(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; + 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(); + s->last_wait_time = g_system->getMillis(); + s->game_start_time = g_system->getMillis(); - retval->successor = NULL; + 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 + s->restoring = true; script_abort_flag = 2; // Abort current game with replay s->shrinkStackToBase(); } diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index 5325d128be9..b642cd8dc9b 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -72,45 +72,49 @@ static const uint16 s_halfWidthSJISMap[256] = { 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; + if (!isRestoring) { + script_000 = 0; + _gameObj = NULL_REG; + + _memorySegmentSize = 0; + _soundCmd = 0; + + restarting_flags = 0; + + execution_stack_base = 0; + _executionStackPosChanged = false; + + _fileHandles.resize(5); + + r_acc = NULL_REG; + restAdjust = 0; + r_prev = NULL_REG; + + stack_base = 0; + stack_top = 0; + } last_wait_time = 0; - _fileHandles.resize(5); - - execution_stack_base = 0; - _executionStackPosChanged = false; - - r_acc = NULL_REG; - restAdjust = 0; - r_prev = NULL_REG; - - stack_base = 0; - stack_top = 0; - - script_000 = 0; - - _gameObj = NULL_REG; - gc_countdown = 0; - successor = 0; - _throttleCounter = 0; _throttleLastTime = 0; _throttleTrigger = false; - _memorySegmentSize = 0; - - _soundCmd = 0; -} - -EngineState::~EngineState() { - delete _msgState; + restoring = false; } void EngineState::wait(int16 ticks) { diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index 0746e8e0a8a..431aac884ea 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -174,7 +174,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 3aee20692ad..36f5ec6893d 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -1695,17 +1695,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; @@ -1723,12 +1722,10 @@ static EngineState *_game_run(EngineState *&s) { 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; - + s->restoring = false; if (script_abort_flag == 2) { debugC(2, kDebugLevelVM, "Restarting with replay()"); s->_executionStack.clear(); // Restart with replay @@ -1741,9 +1738,9 @@ static EngineState *_game_run(EngineState *&s) { script_abort_flag = 0; } else - game_is_finished = 1; + break; // exit loop } - } while (!game_is_finished); + } while (true); return s; } From 42b22d16f6f4f8defc3bc276343b3066c8603877 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Tue, 1 Jun 2010 17:01:22 +0000 Subject: [PATCH 179/249] Fix videos in Riven activated from a different card from which they are played; minor cleanup. svn-id: r49377 --- engines/mohawk/riven.cpp | 2 +- engines/mohawk/video.cpp | 17 ++++++++++++++--- engines/mohawk/video.h | 8 ++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 744b3f2d2cf..f3e4703c111 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -233,6 +233,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 +311,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/video.cpp b/engines/mohawk/video.cpp index deeb5daabf3..ed1fc6b2c62 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -35,7 +35,6 @@ VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) { } VideoManager::~VideoManager() { - _mlstRecords.clear(); stopVideos(); } @@ -125,7 +124,7 @@ void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) { delete _videoStreams[videoHandle].video; _videoStreams[videoHandle].video = 0; _videoStreams[videoHandle].id = 0; - _videoStreams[videoHandle].filename = ""; + _videoStreams[videoHandle].filename.clear(); } void VideoManager::playBackgroundMovie(Common::String filename, int16 x, int16 y, bool loop) { @@ -158,7 +157,7 @@ bool VideoManager::updateBackgroundMovies() { delete _videoStreams[i].video; _videoStreams[i].video = 0; _videoStreams[i].id = 0; - _videoStreams[i].filename = ""; + _videoStreams[i].filename.clear(); continue; } } @@ -245,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 a duplicate + for (uint32 j = 0; j < _mlstRecords.size(); j++) + if (_mlstRecords[j].index == mlstId) { + _mlstRecords.remove_at(j); + break; + } + _mlstRecords.push_back(mlstRecord); break; } @@ -254,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) { diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 5620a5412a7..6aa553e26bb 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -82,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(); @@ -89,9 +90,6 @@ public: void stopMovie(uint16 id); void playMovieBlocking(uint16 id); - // Riven-related variables - Common::Array _mlstRecords; - // Handle functions VideoHandle findVideoHandle(uint16 id); int32 getCurFrame(const VideoHandle &handle); @@ -100,13 +98,15 @@ public: private: MohawkEngine *_vm; - void waitUntilMovieEnds(VideoHandle videoHandle); + // Riven-related variables + Common::Array _mlstRecords; // Keep tabs on any videos playing Common::Array _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 From 4cb3a2b41b5f92fda50f6db15e4e69be7dd0129a Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Tue, 1 Jun 2010 17:03:43 +0000 Subject: [PATCH 180/249] This hopefully fixes the compilation of the GP2x backend. svn-id: r49378 --- backends/platform/gp2x/gp2x-common.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/backends/platform/gp2x/gp2x-common.h b/backends/platform/gp2x/gp2x-common.h index 9f3a79ff975..8183a87300d 100644 --- a/backends/platform/gp2x/gp2x-common.h +++ b/backends/platform/gp2x/gp2x-common.h @@ -150,8 +150,6 @@ public: bool setGraphicsMode(int mode); int getGraphicsMode() const; - bool openCD(int drive); - bool hasFeature(Feature f); void setFeatureState(Feature f, bool enable); bool getFeatureState(Feature f); From 95001e3676c98b5d13dee3340efcc20e6f4d9f77 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 1 Jun 2010 20:37:55 +0000 Subject: [PATCH 181/249] Add support for SCI2.1 resource patches to the fallback detector svn-id: r49380 --- engines/sci/resource.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index c36feb57c66..96bef504f75 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -537,8 +537,6 @@ 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")) { map = addExternalMap(file); break; @@ -564,6 +562,14 @@ int ResourceManager::addAppropriateSources(const Common::FSList &fslist) { } } +#ifdef ENABLE_SCI32 + // SCI2.1 resource patches + 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); + } +#endif + // This function is only called by the advanced detector, and we don't really need // to add a patch directory or message.map here From a6efbf8880d56680e5503bcf1f68fdf2c9ef9156 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 1 Jun 2010 22:06:52 +0000 Subject: [PATCH 182/249] Fixed the detection of SCI2.1 games in the fallback detector svn-id: r49382 --- engines/sci/detection.cpp | 18 ++++++++++-- engines/sci/resource.cpp | 60 +++++++++++++++++++++++---------------- engines/sci/resource.h | 6 ++-- 3 files changed, 55 insertions(+), 29 deletions(-) diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index 06a83a98dcb..dbd65c7aaa8 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -140,9 +140,11 @@ static const OldNewIdTableEntry s_oldNewTable[] = { { "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 }, @@ -152,6 +154,9 @@ static const OldNewIdTableEntry s_oldNewTable[] = { { "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 }, @@ -165,24 +170,30 @@ static const OldNewIdTableEntry s_oldNewTable[] = { // 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 - { "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 }, + // 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: SCI2.1, SCI3 IDs + + // TODO: SCI3 IDs { "", "", SCI_VERSION_NONE } }; @@ -222,6 +233,9 @@ Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, R 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 diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 96bef504f75..b07b76f9c97 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -183,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; @@ -191,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; @@ -447,11 +447,11 @@ int sci0_get_compression_method(Common::ReadStream &stream) { 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(); @@ -462,8 +462,8 @@ 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 @@ -486,8 +486,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()) @@ -509,9 +509,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 @@ -520,14 +520,16 @@ 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; + ResourceSource *sci21PatchMap = 0; + const Common::FSNode *sci21PatchRes = 0; // First, find resource.map for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { @@ -537,15 +539,33 @@ int ResourceManager::addAppropriateSources(const Common::FSList &fslist) { Common::String filename = file->getName(); filename.toLowercase(); - 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()) @@ -562,14 +582,6 @@ int ResourceManager::addAppropriateSources(const Common::FSList &fslist) { } } -#ifdef ENABLE_SCI32 - // SCI2.1 resource patches - 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); - } -#endif - // This function is only called by the advanced detector, and we don't really need // to add a patch directory or message.map here @@ -1282,7 +1294,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); diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 8147763f4f7..65717e41248 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -321,8 +321,8 @@ protected: ResourceMap _resMap; Common::List _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 @@ -358,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. From 93867d567fd76f909bfbb64f8300d6841af584e2 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 1 Jun 2010 22:28:24 +0000 Subject: [PATCH 183/249] Inline palettes in SDL backend into class OSystem_SDL svn-id: r49383 --- backends/platform/sdl/sdl.cpp | 10 +++------- backends/platform/sdl/sdl.h | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 9fa43cb3895..c947e32cd8b 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -251,9 +251,9 @@ OSystem_SDL::OSystem_SDL() _screenIsLocked(false), _graphicsMutex(0), _transactionMode(kTransactionNone) { - // allocate palette storage - _currentPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256); - _cursorPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256); + // clear palette storage + memset(_currentPalette, 0, sizeof(_currentPalette)); + memset(_cursorPalette, 0, sizeof(_cursorPalette)); _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0; @@ -282,8 +282,6 @@ OSystem_SDL::~OSystem_SDL() { closeMixer(); free(_dirtyChecksums); - free(_currentPalette); - free(_cursorPalette); free(_mouseData); delete _savefile; @@ -513,8 +511,6 @@ void OSystem_SDL::deinit() { closeMixer(); free(_dirtyChecksums); - free(_currentPalette); - free(_cursorPalette); free(_mouseData); delete _timer; diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index c850ec5ab16..bfaabab80a7 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -422,11 +422,11 @@ protected: int _newShakePos; // Palette data - SDL_Color *_currentPalette; + SDL_Color _currentPalette[256]; uint _paletteDirtyStart, _paletteDirtyEnd; // Cursor palette data - SDL_Color *_cursorPalette; + SDL_Color _cursorPalette[256]; /** * Mutex which prevents multiple threads from interfering with each other From 9f14e43d16a45c37b041ed2e3041fd8e7690121d Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 1 Jun 2010 22:29:55 +0000 Subject: [PATCH 184/249] Fix bug #2999153: "IPHONE: No grabPalette() implementation" svn-id: r49384 --- backends/platform/iphone/osys_video.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/backends/platform/iphone/osys_video.cpp b/backends/platform/iphone/osys_video.cpp index 6cb5e18d95c..76c2031758b 100644 --- a/backends/platform/iphone/osys_video.cpp +++ b/backends/platform/iphone/osys_video.cpp @@ -86,7 +86,7 @@ int16 OSystem_IPHONE::getWidth() { } void OSystem_IPHONE::setPalette(const byte *colors, uint start, uint num) { - //printf("setPalette()\n"); + assert(start + num <= 256); const byte *b = colors; for (uint i = start; i < start + num; ++i) { @@ -98,7 +98,14 @@ void OSystem_IPHONE::setPalette(const byte *colors, uint start, uint num) { } void OSystem_IPHONE::grabPalette(byte *colors, uint start, uint num) { - //printf("grabPalette()\n"); + assert(start + num <= 256); + byte *b = colors; + + for (uint i = start; i < start + num; ++i) { + Graphics::colorToRGB >(_palette[i], b[0], b[1], b[2]); + b[3] = 0xFF; + b += 4; + } } void OSystem_IPHONE::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { From 24673b9ee91f6d80ae1b32f239fbe25489c519a0 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 2 Jun 2010 00:20:52 +0000 Subject: [PATCH 185/249] Fix warning svn-id: r49386 --- engines/sci/resource.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index b07b76f9c97..8f4fd64d901 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -528,8 +528,10 @@ int ResourceManager::addAppropriateSources() { 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) { From c4c63223cc45ce192f8b03f27fff56fcdf56a502 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 2 Jun 2010 00:25:11 +0000 Subject: [PATCH 186/249] IPHONE: Disable RTTI and C++ exceptions svn-id: r49387 --- dists/iphone/scummvm.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dists/iphone/scummvm.xcodeproj/project.pbxproj b/dists/iphone/scummvm.xcodeproj/project.pbxproj index 95bf0690a35..6876492a95e 100755 --- a/dists/iphone/scummvm.xcodeproj/project.pbxproj +++ b/dists/iphone/scummvm.xcodeproj/project.pbxproj @@ -10061,6 +10061,8 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = ""; GCC_C_LANGUAGE_STANDARD = c99; + GCC_ENABLE_CPP_EXCEPTIONS = NO; + GCC_ENABLE_CPP_RTTI = NO; GCC_INPUT_FILETYPE = automatic; GCC_PREPROCESSOR_DEFINITIONS = ( XCODE, @@ -10128,6 +10130,8 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = ""; + GCC_ENABLE_CPP_EXCEPTIONS = NO; + GCC_ENABLE_CPP_RTTI = NO; GCC_INPUT_FILETYPE = automatic; GCC_PREPROCESSOR_DEFINITIONS = ( XCODE, From 767edc91faebdc1a60e5c8b3764b169dc9807ea5 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 2 Jun 2010 00:52:57 +0000 Subject: [PATCH 187/249] OSYSTEM: Get rid of kFeatureAutoComputeDirtyRects svn-id: r49388 --- backends/platform/gp2x/gp2x-common.h | 11 -- backends/platform/gp2x/gp2x.cpp | 15 +- backends/platform/gp2x/graphics.cpp | 145 +++--------------- .../platform/gp2xwiz/gp2xwiz-graphics.cpp | 5 - .../platform/linuxmoto/linuxmoto-graphics.cpp | 5 - backends/platform/samsungtv/samsungtv.cpp | 9 -- backends/platform/sdl/graphics.cpp | 100 +----------- backends/platform/sdl/sdl.cpp | 15 +- backends/platform/sdl/sdl.h | 11 -- backends/platform/symbian/src/SymbianOS.cpp | 1 - backends/platform/wince/wince-sdl.cpp | 69 +++------ common/system.h | 12 -- engines/saga/saga.cpp | 14 -- 13 files changed, 52 insertions(+), 360 deletions(-) diff --git a/backends/platform/gp2x/gp2x-common.h b/backends/platform/gp2x/gp2x-common.h index 8183a87300d..b54e2d4d4f6 100644 --- a/backends/platform/gp2x/gp2x-common.h +++ b/backends/platform/gp2x/gp2x-common.h @@ -191,10 +191,6 @@ protected: bool _overlayVisible; Graphics::PixelFormat _overlayFormat; - enum { - DF_WANT_RECT_OPTIM = 1 << 0 - }; - enum { kTransactionNone = 0, kTransactionActive = 1, @@ -235,7 +231,6 @@ protected: Graphics::Surface _framebuffer; /** Current video mode flags (see DF_* constants) */ - uint32 _modeFlags; bool _modeChanged; int _screenChangeCount; @@ -252,9 +247,6 @@ protected: // Dirty rect management SDL_Rect _dirtyRectList[NUM_DIRTY_RECT]; int _numDirtyRects; - uint32 *_dirtyChecksums; - bool _cksumValid; - int _cksumNum; // Keyboard mouse emulation. Disabled by fingolfin 2004-12-18. // I am keeping the rest of the code in for now, since the joystick @@ -351,9 +343,6 @@ protected: Common::TimerManager *_timer; protected: - void addDirtyRgnAuto(const byte *buf); - void makeChecksums(const byte *buf); - virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false); void drawMouse(); diff --git a/backends/platform/gp2x/gp2x.cpp b/backends/platform/gp2x/gp2x.cpp index 8669671c4ee..88d4f9d6323 100644 --- a/backends/platform/gp2x/gp2x.cpp +++ b/backends/platform/gp2x/gp2x.cpp @@ -193,13 +193,11 @@ void OSystem_GP2X::initBackend() { memset(&_videoMode, 0, sizeof(_videoMode)); memset(&_transactionDetails, 0, sizeof(_transactionDetails)); - _cksumValid = false; _videoMode.mode = GFX_NORMAL; _videoMode.scaleFactor = 1; _scalerProc = Normal1x; _videoMode.aspectRatioCorrection = ConfMan.getBool("aspect_ratio"); _scalerType = 0; - _modeFlags = 0; _adjustZoomOnMouse = false; ConfMan.setBool("FM_low_quality", true); @@ -246,7 +244,7 @@ OSystem_GP2X::OSystem_GP2X() _hwscreen(0), _screen(0), _tmpscreen(0), _overlayVisible(false), _overlayscreen(0), _tmpscreen2(0), - _scalerProc(0), _modeChanged(false), _screenChangeCount(0), _dirtyChecksums(0), + _scalerProc(0), _modeChanged(false), _screenChangeCount(0), _mouseVisible(false), _mouseNeedsRedraw(false), _mouseData(0), _mouseSurface(0), _mouseOrigSurface(0), _cursorTargetScale(1), _cursorPaletteDisabled(true), _joystick(0), @@ -281,7 +279,6 @@ OSystem_GP2X::~OSystem_GP2X() { SDL_RemoveTimer(_timerID); closeMixer(); - free(_dirtyChecksums); free(_currentPalette); free(_cursorPalette); free(_mouseData); @@ -380,7 +377,6 @@ bool OSystem_GP2X::hasFeature(Feature f) { return (f == kFeatureFullscreenMode) || (f == kFeatureAspectRatioCorrection) || - (f == kFeatureAutoComputeDirtyRects) || (f == kFeatureCursorHasPalette); } @@ -391,12 +387,6 @@ void OSystem_GP2X::setFeatureState(Feature f, bool enable) { case kFeatureAspectRatioCorrection: setAspectRatioCorrection(enable); break; - case kFeatureAutoComputeDirtyRects: - if (enable) - _modeFlags |= DF_WANT_RECT_OPTIM; - else - _modeFlags &= ~DF_WANT_RECT_OPTIM; - break; case kFeatureDisableKeyFiltering: // TODO: Extend as more support for this is added to engines. return; @@ -413,8 +403,6 @@ bool OSystem_GP2X::getFeatureState(Feature f) { return false; case kFeatureAspectRatioCorrection: return _videoMode.aspectRatioCorrection; - case kFeatureAutoComputeDirtyRects: - return _modeFlags & DF_WANT_RECT_OPTIM; default: return false; } @@ -431,7 +419,6 @@ void OSystem_GP2X::quit() { SDL_RemoveTimer(_timerID); closeMixer(); - free(_dirtyChecksums); free(_currentPalette); free(_cursorPalette); free(_mouseData); diff --git a/backends/platform/gp2x/graphics.cpp b/backends/platform/gp2x/graphics.cpp index 449e744e8bc..4a3c668c524 100644 --- a/backends/platform/gp2x/graphics.cpp +++ b/backends/platform/gp2x/graphics.cpp @@ -270,12 +270,7 @@ void OSystem_GP2X::initSize(uint w, uint h, const Graphics::PixelFormat *format) _videoMode.screenWidth = w; _videoMode.screenHeight = h; - _cksumNum = (w * h / (8 * 8)); - _transactionDetails.sizeChanged = true; - - free(_dirtyChecksums); - _dirtyChecksums = (uint32 *)calloc(_cksumNum * 2, sizeof(uint32)); } int OSystem_GP2X::effectiveScreenHeight() const { @@ -724,41 +719,32 @@ void OSystem_GP2X::copyRectToScreen(const byte *src, int pitch, int x, int y, in assert(h > 0 && y + h <= _videoMode.screenHeight); assert(w > 0 && x + w <= _videoMode.screenWidth); - if (IS_ALIGNED(src, 4) && pitch == _videoMode.screenWidth && x == 0 && y == 0 && - w == _videoMode.screenWidth && h == _videoMode.screenHeight && _modeFlags & DF_WANT_RECT_OPTIM) { - /* Special, optimized case for full screen updates. - * It tries to determine what areas were actually changed, - * and just updates those, on the actual display. */ - addDirtyRgnAuto(src); - } else { - /* Clip the coordinates */ - if (x < 0) { - w += x; - src -= x; - x = 0; - } - - if (y < 0) { - h += y; - src -= y * pitch; - y = 0; - } - - if (w > _videoMode.screenWidth - x) { - w = _videoMode.screenWidth - x; - } - - if (h > _videoMode.screenHeight - y) { - h = _videoMode.screenHeight - y; - } - - if (w <= 0 || h <= 0) - return; - - _cksumValid = false; - addDirtyRect(x, y, w, h); + /* Clip the coordinates */ + if (x < 0) { + w += x; + src -= x; + x = 0; } + if (y < 0) { + h += y; + src -= y * pitch; + y = 0; + } + + if (w > _videoMode.screenWidth - x) { + w = _videoMode.screenWidth - x; + } + + if (h > _videoMode.screenHeight - y) { + h = _videoMode.screenHeight - y; + } + + if (w <= 0 || h <= 0) + return; + + addDirtyRect(x, y, w, h); + // Try to lock the screen surface if (SDL_LockSurface(_screen) == -1) error("SDL_LockSurface failed: %s", SDL_GetError()); @@ -885,88 +871,6 @@ void OSystem_GP2X::addDirtyRect(int x, int y, int w, int h, bool realCoordinates } } -void OSystem_GP2X::makeChecksums(const byte *buf) { - assert(buf); - uint32 *sums = _dirtyChecksums; - uint x,y; - const uint last_x = (uint)_videoMode.screenWidth / 8; - const uint last_y = (uint)_videoMode.screenHeight / 8; - - const uint BASE = 65521; /* largest prime smaller than 65536 */ - - /* the 8x8 blocks in buf are enumerated starting in the top left corner and - * reading each line at a time from left to right */ - for (y = 0; y != last_y; y++, buf += _videoMode.screenWidth * (8 - 1)) - for (x = 0; x != last_x; x++, buf += 8) { - // Adler32 checksum algorithm (from RFC1950, used by gzip and zlib). - // This computes the Adler32 checksum of a 8x8 pixel block. Note - // that we can do the modulo operation (which is the slowest part) - // of the algorithm) at the end, instead of doing each iteration, - // since we only have 64 iterations in total - and thus s1 and - // s2 can't overflow anyway. - uint32 s1 = 1; - uint32 s2 = 0; - const byte *ptr = buf; - for (int subY = 0; subY < 8; subY++) { - for (int subX = 0; subX < 8; subX++) { - s1 += ptr[subX]; - s2 += s1; - } - ptr += _videoMode.screenWidth; - } - - s1 %= BASE; - s2 %= BASE; - - /* output the checksum for this block */ - *sums++ = (s2 << 16) + s1; - } -} - -void OSystem_GP2X::addDirtyRgnAuto(const byte *buf) { - assert(buf); - assert(IS_ALIGNED(buf, 4)); - - /* generate a table of the checksums */ - makeChecksums(buf); - - if (!_cksumValid) { - _forceFull = true; - _cksumValid = true; - } - - /* go through the checksum list, compare it with the previous checksums, - and add all dirty rectangles to a list. try to combine small rectangles - into bigger ones in a simple way */ - if (!_forceFull) { - int x, y, w; - uint32 *ck = _dirtyChecksums; - - for (y = 0; y != _videoMode.screenHeight / 8; y++) { - for (x = 0; x != _videoMode.screenWidth / 8; x++, ck++) { - if (ck[0] != ck[_cksumNum]) { - /* found a dirty 8x8 block, now go as far to the right as possible, - and at the same time, unmark the dirty status by setting old to new. */ - w=0; - do { - ck[w + _cksumNum] = ck[w]; - w++; - } while (x + w != _videoMode.screenWidth / 8 && ck[w] != ck[w + _cksumNum]); - - addDirtyRect(x * 8, y * 8, w * 8, 8); - - if (_forceFull) - goto get_out; - } - } - } - } else { - get_out:; - /* Copy old checksums to new */ - memcpy(_dirtyChecksums + _cksumNum, _dirtyChecksums, _cksumNum * sizeof(uint32)); - } -} - int16 OSystem_GP2X::getHeight() { return _videoMode.screenHeight; } @@ -1175,7 +1079,6 @@ void OSystem_GP2X::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, return; // Mark the modified region as dirty - _cksumValid = false; addDirtyRect(x, y, w, h); if (SDL_LockSurface(_overlayscreen) == -1) diff --git a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp index 28c03db4b02..6abddd52f3f 100644 --- a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp +++ b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp @@ -127,12 +127,7 @@ void OSystem_GP2XWIZ::initSize(uint w, uint h) { toggleMouseGrab(); } - _cksumNum = (w * h / (8 * 8)); - _transactionDetails.sizeChanged = true; - - free(_dirtyChecksums); - _dirtyChecksums = (uint32 *)calloc(_cksumNum * 2, sizeof(uint32)); } bool OSystem_GP2XWIZ::loadGFXMode() { diff --git a/backends/platform/linuxmoto/linuxmoto-graphics.cpp b/backends/platform/linuxmoto/linuxmoto-graphics.cpp index 482ed772c7c..a39416ebc4a 100644 --- a/backends/platform/linuxmoto/linuxmoto-graphics.cpp +++ b/backends/platform/linuxmoto/linuxmoto-graphics.cpp @@ -128,12 +128,7 @@ void OSystem_LINUXMOTO::initSize(uint w, uint h) { toggleMouseGrab(); } - _cksumNum = (w * h / (8 * 8)); - _transactionDetails.sizeChanged = true; - - free(_dirtyChecksums); - _dirtyChecksums = (uint32 *)calloc(_cksumNum * 2, sizeof(uint32)); } bool OSystem_LINUXMOTO::loadGFXMode() { diff --git a/backends/platform/samsungtv/samsungtv.cpp b/backends/platform/samsungtv/samsungtv.cpp index 4f0f3a1e3e9..aa79b925581 100644 --- a/backends/platform/samsungtv/samsungtv.cpp +++ b/backends/platform/samsungtv/samsungtv.cpp @@ -30,7 +30,6 @@ bool OSystem_SDL_SamsungTV::hasFeature(Feature f) { return (f == kFeatureAspectRatioCorrection) || - (f == kFeatureAutoComputeDirtyRects) || (f == kFeatureCursorHasPalette); } @@ -39,12 +38,6 @@ void OSystem_SDL_SamsungTV::setFeatureState(Feature f, bool enable) { case kFeatureAspectRatioCorrection: setAspectRatioCorrection(enable); break; - case kFeatureAutoComputeDirtyRects: - if (enable) - _modeFlags |= DF_WANT_RECT_OPTIM; - else - _modeFlags &= ~DF_WANT_RECT_OPTIM; - break; default: break; } @@ -56,8 +49,6 @@ bool OSystem_SDL_SamsungTV::getFeatureState(Feature f) { switch (f) { case kFeatureAspectRatioCorrection: return _videoMode.aspectRatioCorrection; - case kFeatureAutoComputeDirtyRects: - return _modeFlags & DF_WANT_RECT_OPTIM; default: return false; } diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp index e0bf7565fbb..82670cfcb79 100644 --- a/backends/platform/sdl/graphics.cpp +++ b/backends/platform/sdl/graphics.cpp @@ -469,12 +469,7 @@ void OSystem_SDL::initSize(uint w, uint h, const Graphics::PixelFormat *format) _videoMode.screenWidth = w; _videoMode.screenHeight = h; - _cksumNum = (w * h / (8 * 8)); - _transactionDetails.sizeChanged = true; - - free(_dirtyChecksums); - _dirtyChecksums = (uint32 *)calloc(_cksumNum * 2, sizeof(uint32)); } int OSystem_SDL::effectiveScreenHeight() const { @@ -976,16 +971,7 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int assert(h > 0 && y + h <= _videoMode.screenHeight); assert(w > 0 && x + w <= _videoMode.screenWidth); - if (IS_ALIGNED(src, 4) && pitch == _videoMode.screenWidth && x == 0 && y == 0 && - w == _videoMode.screenWidth && h == _videoMode.screenHeight && _modeFlags & DF_WANT_RECT_OPTIM) { - /* Special, optimized case for full screen updates. - * It tries to determine what areas were actually changed, - * and just updates those, on the actual display. */ - addDirtyRgnAuto(src); - } else { - _cksumValid = false; - addDirtyRect(x, y, w, h); - } + addDirtyRect(x, y, w, h); // Try to lock the screen surface if (SDL_LockSurface(_screen) == -1) @@ -1131,89 +1117,6 @@ void OSystem_SDL::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) } } - -void OSystem_SDL::makeChecksums(const byte *buf) { - assert(buf); - uint32 *sums = _dirtyChecksums; - uint x,y; - const uint last_x = (uint)_videoMode.screenWidth / 8; - const uint last_y = (uint)_videoMode.screenHeight / 8; - - const uint BASE = 65521; /* largest prime smaller than 65536 */ - - /* the 8x8 blocks in buf are enumerated starting in the top left corner and - * reading each line at a time from left to right */ - for (y = 0; y != last_y; y++, buf += _videoMode.screenWidth * (8 - 1)) - for (x = 0; x != last_x; x++, buf += 8) { - // Adler32 checksum algorithm (from RFC1950, used by gzip and zlib). - // This computes the Adler32 checksum of a 8x8 pixel block. Note - // that we can do the modulo operation (which is the slowest part) - // of the algorithm) at the end, instead of doing each iteration, - // since we only have 64 iterations in total - and thus s1 and - // s2 can't overflow anyway. - uint32 s1 = 1; - uint32 s2 = 0; - const byte *ptr = buf; - for (int subY = 0; subY < 8; subY++) { - for (int subX = 0; subX < 8; subX++) { - s1 += ptr[subX]; - s2 += s1; - } - ptr += _videoMode.screenWidth; - } - - s1 %= BASE; - s2 %= BASE; - - /* output the checksum for this block */ - *sums++ = (s2 << 16) + s1; - } -} - -void OSystem_SDL::addDirtyRgnAuto(const byte *buf) { - assert(buf); - assert(IS_ALIGNED(buf, 4)); - - /* generate a table of the checksums */ - makeChecksums(buf); - - if (!_cksumValid) { - _forceFull = true; - _cksumValid = true; - } - - /* go through the checksum list, compare it with the previous checksums, - and add all dirty rectangles to a list. try to combine small rectangles - into bigger ones in a simple way */ - if (!_forceFull) { - int x, y, w; - uint32 *ck = _dirtyChecksums; - - for (y = 0; y != _videoMode.screenHeight / 8; y++) { - for (x = 0; x != _videoMode.screenWidth / 8; x++, ck++) { - if (ck[0] != ck[_cksumNum]) { - /* found a dirty 8x8 block, now go as far to the right as possible, - and at the same time, unmark the dirty status by setting old to new. */ - w=0; - do { - ck[w + _cksumNum] = ck[w]; - w++; - } while (x + w != _videoMode.screenWidth / 8 && ck[w] != ck[w + _cksumNum]); - - addDirtyRect(x * 8, y * 8, w * 8, 8); - - if (_forceFull) - goto get_out; - } - } - } - } else { - get_out:; - /* Copy old checksums to new */ - memcpy(_dirtyChecksums + _cksumNum, _dirtyChecksums, _cksumNum * sizeof(uint32)); - } -} - int16 OSystem_SDL::getHeight() { return _videoMode.screenHeight; } @@ -1432,7 +1335,6 @@ void OSystem_SDL::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, i return; // Mark the modified region as dirty - _cksumValid = false; addDirtyRect(x, y, w, h); if (SDL_LockSurface(_overlayscreen) == -1) diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index c947e32cd8b..f8ae824acf5 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -149,7 +149,6 @@ void OSystem_SDL::initBackend() { memset(&_videoMode, 0, sizeof(_videoMode)); memset(&_transactionDetails, 0, sizeof(_transactionDetails)); - _cksumValid = false; #if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) && defined(USE_SCALERS) _videoMode.mode = GFX_DOUBLESIZE; _videoMode.scaleFactor = 2; @@ -163,7 +162,6 @@ void OSystem_SDL::initBackend() { _scalerProc = Normal1x; #endif _scalerType = 0; - _modeFlags = 0; #if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) _videoMode.fullscreen = ConfMan.getBool("fullscreen"); @@ -233,7 +231,7 @@ OSystem_SDL::OSystem_SDL() #endif _overlayVisible(false), _overlayscreen(0), _tmpscreen2(0), - _cdrom(0), _scalerProc(0), _modeChanged(false), _screenChangeCount(0), _dirtyChecksums(0), + _cdrom(0), _scalerProc(0), _modeChanged(false), _screenChangeCount(0), _scrollLock(false), _mouseVisible(false), _mouseNeedsRedraw(false), _mouseData(0), _mouseSurface(0), _mouseOrigSurface(0), _cursorTargetScale(1), _cursorPaletteDisabled(true), @@ -281,7 +279,6 @@ OSystem_SDL::~OSystem_SDL() { SDL_RemoveTimer(_timerID); closeMixer(); - free(_dirtyChecksums); free(_mouseData); delete _savefile; @@ -451,7 +448,6 @@ bool OSystem_SDL::hasFeature(Feature f) { return (f == kFeatureFullscreenMode) || (f == kFeatureAspectRatioCorrection) || - (f == kFeatureAutoComputeDirtyRects) || (f == kFeatureCursorHasPalette) || (f == kFeatureIconifyWindow); } @@ -464,12 +460,6 @@ void OSystem_SDL::setFeatureState(Feature f, bool enable) { case kFeatureAspectRatioCorrection: setAspectRatioCorrection(enable); break; - case kFeatureAutoComputeDirtyRects: - if (enable) - _modeFlags |= DF_WANT_RECT_OPTIM; - else - _modeFlags &= ~DF_WANT_RECT_OPTIM; - break; case kFeatureIconifyWindow: if (enable) SDL_WM_IconifyWindow(); @@ -487,8 +477,6 @@ bool OSystem_SDL::getFeatureState(Feature f) { return _videoMode.fullscreen; case kFeatureAspectRatioCorrection: return _videoMode.aspectRatioCorrection; - case kFeatureAutoComputeDirtyRects: - return _modeFlags & DF_WANT_RECT_OPTIM; default: return false; } @@ -510,7 +498,6 @@ void OSystem_SDL::deinit() { SDL_RemoveTimer(_timerID); closeMixer(); - free(_dirtyChecksums); free(_mouseData); delete _timer; diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index bfaabab80a7..341a59c8cfd 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -290,10 +290,6 @@ protected: int _cdTrack, _cdNumLoops, _cdStartFrame, _cdDuration; uint32 _cdEndTime, _cdStopTime; - enum { - DF_WANT_RECT_OPTIM = 1 << 0 - }; - enum { kTransactionNone = 0, kTransactionActive = 1, @@ -342,7 +338,6 @@ protected: Graphics::Surface _framebuffer; /** Current video mode flags (see DF_* constants) */ - uint32 _modeFlags; bool _modeChanged; int _screenChangeCount; @@ -354,9 +349,6 @@ protected: // Dirty rect management SDL_Rect _dirtyRectList[NUM_DIRTY_RECT]; int _numDirtyRects; - uint32 *_dirtyChecksums; - bool _cksumValid; - int _cksumNum; // Keyboard mouse emulation. Disabled by fingolfin 2004-12-18. // I am keeping the rest of the code in for now, since the joystick @@ -459,9 +451,6 @@ protected: Common::TimerManager *_timer; protected: - void addDirtyRgnAuto(const byte *buf); - void makeChecksums(const byte *buf); - virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false); // overloaded by CE backend virtual void drawMouse(); // overloaded by CE backend diff --git a/backends/platform/symbian/src/SymbianOS.cpp b/backends/platform/symbian/src/SymbianOS.cpp index f8df2a5d5c4..2ae47b07a81 100644 --- a/backends/platform/symbian/src/SymbianOS.cpp +++ b/backends/platform/symbian/src/SymbianOS.cpp @@ -83,7 +83,6 @@ bool OSystem_SDL_Symbian::hasFeature(Feature f) { switch (f) { case kFeatureFullscreenMode: case kFeatureAspectRatioCorrection: - case kFeatureAutoComputeDirtyRects: case kFeatureCursorHasPalette: #ifdef USE_VIBRA_SE_PXXX case kFeatureVibration: diff --git a/backends/platform/wince/wince-sdl.cpp b/backends/platform/wince/wince-sdl.cpp index 7ce689fb63e..b3480702b5d 100644 --- a/backends/platform/wince/wince-sdl.cpp +++ b/backends/platform/wince/wince-sdl.cpp @@ -926,7 +926,7 @@ const OSystem::GraphicsMode *OSystem_WINCE3::getSupportedGraphicsModes() const { } bool OSystem_WINCE3::hasFeature(Feature f) { - return (f == kFeatureAutoComputeDirtyRects || f == kFeatureVirtualKeyboard); + return (f == kFeatureVirtualKeyboard); } void OSystem_WINCE3::setFeatureState(Feature f, bool enable) { @@ -1151,14 +1151,12 @@ bool OSystem_WINCE3::update_scalers() { _scaleFactorYm = 1; _scaleFactorYd = 1; _scalerProc = DownscaleHorizByThreeQuarters; - _modeFlags = 0; } else { _scaleFactorXm = 1; _scaleFactorXd = 1; _scaleFactorYm = 1; _scaleFactorYd = 1; _scalerProc = Normal1x; - _modeFlags = 0; } } else if ( _orientationLandscape && (_videoMode.screenWidth == 320 || !_videoMode.screenWidth)) { if (!_panelVisible && !_hasSmartphoneResolution && !_overlayVisible && _canBeAspectScaled) { @@ -1167,7 +1165,6 @@ bool OSystem_WINCE3::update_scalers() { _scaleFactorYm = 6; _scaleFactorYd = 5; _scalerProc = Normal1xAspect; - _modeFlags = 0; _videoMode.aspectRatioCorrection = true; } else { _scaleFactorXm = 1; @@ -1175,7 +1172,6 @@ bool OSystem_WINCE3::update_scalers() { _scaleFactorYm = 1; _scaleFactorYd = 1; _scalerProc = Normal1x; - _modeFlags = 0; } } else if (_videoMode.screenWidth == 640 && !(isOzone() && (getScreenWidth() >= 640 || getScreenHeight() >= 640))) { _scaleFactorXm = 1; @@ -1183,14 +1179,12 @@ bool OSystem_WINCE3::update_scalers() { _scaleFactorYm = 1; _scaleFactorYd = 2; _scalerProc = DownscaleAllByHalf; - _modeFlags = 0; } else if (_videoMode.screenWidth == 640 && (isOzone() && (getScreenWidth() >= 640 || getScreenHeight() >= 640))) { _scaleFactorXm = 1; _scaleFactorXd = 1; _scaleFactorYm = 1; _scaleFactorYd = 1; _scalerProc = Normal1x; - _modeFlags = 0; } return true; @@ -1203,7 +1197,6 @@ bool OSystem_WINCE3::update_scalers() { _scaleFactorYm = 12; _scaleFactorYd = 5; _scalerProc = Normal2xAspect; - _modeFlags = 0; _videoMode.aspectRatioCorrection = true; } else if ( (_panelVisible || _overlayVisible) && _canBeAspectScaled ) { _scaleFactorXm = 2; @@ -1211,7 +1204,6 @@ bool OSystem_WINCE3::update_scalers() { _scaleFactorYm = 2; _scaleFactorYd = 1; _scalerProc = Normal2x; - _modeFlags = 0; } return true; } @@ -1232,7 +1224,6 @@ bool OSystem_WINCE3::update_scalers() { _scaleFactorYm = 7; _scaleFactorYd = 8; _scalerProc = SmartphoneLandscape; - _modeFlags = 0; initZones(); return true; } @@ -1824,7 +1815,6 @@ void OSystem_WINCE3::copyRectToOverlay(const OverlayColor *buf, int pitch, int x return; // Mark the modified region as dirty - _cksumValid = false; addDirtyRect(x, y, w, h); undrawMouse(); @@ -1851,41 +1841,32 @@ void OSystem_WINCE3::copyRectToScreen(const byte *src, int pitch, int x, int y, Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends - if (((long)src & 3) == 0 && pitch == _videoMode.screenWidth && x == 0 && y == 0 && - w == _videoMode.screenWidth && h == _videoMode.screenHeight && _modeFlags & DF_WANT_RECT_OPTIM) { - /* Special, optimized case for full screen updates. - * It tries to determine what areas were actually changed, - * and just updates those, on the actual display. */ - addDirtyRgnAuto(src); - } else { - /* Clip the coordinates */ - if (x < 0) { - w += x; - src -= x; - x = 0; - } - - if (y < 0) { - h += y; - src -= y * pitch; - y = 0; - } - - if (w > _videoMode.screenWidth - x) { - w = _videoMode.screenWidth - x; - } - - if (h > _videoMode.screenHeight - y) { - h = _videoMode.screenHeight - y; - } - - if (w <= 0 || h <= 0) - return; - - _cksumValid = false; - addDirtyRect(x, y, w, h); + /* Clip the coordinates */ + if (x < 0) { + w += x; + src -= x; + x = 0; } + if (y < 0) { + h += y; + src -= y * pitch; + y = 0; + } + + if (w > _videoMode.screenWidth - x) { + w = _videoMode.screenWidth - x; + } + + if (h > _videoMode.screenHeight - y) { + h = _videoMode.screenHeight - y; + } + + if (w <= 0 || h <= 0) + return; + + addDirtyRect(x, y, w, h); + undrawMouse(); // Try to lock the screen surface diff --git a/common/system.h b/common/system.h index 76689bf3814..60cea49f873 100644 --- a/common/system.h +++ b/common/system.h @@ -150,18 +150,6 @@ public: */ kFeatureVirtualKeyboard, - /** - * This flag is a bit more obscure: it gives a hint to the backend that - * the frontend code is very inefficient in doing screen updates. So - * the frontend might do a lot of fullscreen blits even though only a - * tiny portion of the actual screen data changed. In that case, it - * might pay off for the backend to compute which parts actually changed, - * and then only mark those as dirty. - * Implementing this is purely optional, and no harm should arise - * when not doing so (except for decreased speed in said frontends). - */ - kFeatureAutoComputeDirtyRects, - /** * This flag determines whether or not the cursor can have its own palette. * It is currently used only by some Macintosh versions of Humongous diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index 2911d9c4514..ed8a9055ba1 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(); From 4493080220a98d596ee578bddc8a64c0d3955eac Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 2 Jun 2010 02:55:55 +0000 Subject: [PATCH 188/249] If we can't find the game object or game ID in fallback detection, break out instead of assuming the script is there. Fixes a segfault when detecting an LSCI game. svn-id: r49389 --- engines/sci/detection.cpp | 11 ++++++++++- engines/sci/resource.cpp | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index dbd65c7aaa8..aba2b0b74ec 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -464,7 +464,16 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl s_fallbackDesc.platform = Common::kPlatformAmiga; // Determine the game id - Common::String gameId = convertSierraGameId(resMan->findSierraGameId(), &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()) { + SearchMan.remove("SCI_detection"); + 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; diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 8f4fd64d901..11d9492ad55 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1935,6 +1935,10 @@ bool ResourceManager::hasSci1Voc900() { reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) { Resource *script = findResource(ResourceId(kResourceTypeScript, 0), false); + + if (!script) + return NULL_REG; + int extraBytes = 0; if (getSciVersion() == SCI_VERSION_0_EARLY || getSciVersion() >= SCI_VERSION_1_1) extraBytes = 2; @@ -1966,8 +1970,14 @@ Common::String ResourceManager::findSierraGameId() { nameSelector += 5; } + if (!heap) + return ""; + 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; From af3fec8c26d92005b507dca65d1d50f820feb0e7 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 2 Jun 2010 13:17:36 +0000 Subject: [PATCH 189/249] - Fixed findGameObject() to properly handle SCI0-SCI1 games where the first block of script 0 isn't the exports block - Changed many places where Common::File is used directly to use Common::SeekableReadStream instead (in order to ultimately remove the SCI_detection hack in the fallback detector) svn-id: r49391 --- engines/sci/resource.cpp | 125 ++++++++++++++++++++++++--------- engines/sci/resource.h | 8 +-- engines/sci/resource_audio.cpp | 30 ++++---- 3 files changed, 109 insertions(+), 54 deletions(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 11d9492ad55..449effd7372 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -237,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; @@ -257,7 +258,7 @@ ResourceSource *ResourceManager::getVolume(ResourceSource *map, int volume_nr) { // Resource manager constructors and operations -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) @@ -272,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); @@ -295,7 +296,7 @@ bool ResourceManager::loadFromPatchFile(Resource *res) { } // Skip resourceid and header size byte file.seek(2, SEEK_SET); - return loadPatch(res, file); + return loadPatch(res, &file); } Common::File *ResourceManager::getVolumeFile(const char *filename) { @@ -352,10 +353,15 @@ void ResourceManager::loadResource(Resource *res) { return; } - Common::File *file; + Common::SeekableReadStream *fileStream; + // Either loading from volume or patch loading failed - file = getVolumeFile(res->_source->location_name.c_str()); - if (!file) { + if (res->_source->resourceFile) + fileStream = res->_source->resourceFile->createReadStream(); + else + fileStream = getVolumeFile(res->_source->location_name.c_str()); + + if (!fileStream) { warning("Failed to open %s", res->_source->location_name.c_str()); res->unalloc(); return; @@ -363,8 +369,8 @@ 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); return; case kSourceAudioVolume: @@ -395,30 +401,30 @@ 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); 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); 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 (error) { warning("Error %d occured while reading %s from resource file: %s", error, res->_id.toString().c_str(), sci_error_types[error]); @@ -872,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; @@ -883,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; @@ -963,7 +968,6 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() { ResourceManager::ResVersion ResourceManager::detectVolVersion() { Common::SeekableReadStream *fileStream = 0; - Common::File *file = 0; ResourceSource *rsrc; for (Common::List::iterator it = _sources.begin(); it != _sources.end(); ++it) { @@ -973,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; @@ -1063,7 +1067,7 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() { // version-agnostic patch application void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, int resnumber) { - Common::File file; + Common::SeekableReadStream *fileStream = 0; Resource *newrsc; ResourceId resId = ResourceId(restype, resnumber); byte patchtype, patch_data_offset; @@ -1071,18 +1075,27 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, if (resnumber == -1) return; - if (!file.open(source->location_name)) { - warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str()); - 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()); @@ -1097,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; } } @@ -1180,6 +1197,7 @@ void ResourceManager::readResourcePatches(ResourceSource *source) { psrcPatch = new ResourceSource; psrcPatch->source_type = kSourcePatch; psrcPatch->location_name = name; + psrcPatch->resourceFile = 0; processPatch(psrcPatch, (ResourceType)i, number); } } @@ -1931,7 +1949,31 @@ bool ResourceManager::hasSci1Voc900() { return offset == res->size; } -#define READ_UINT16(ptr) (!isSci11Mac() ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) +// 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); + + if (oldScriptHeader) + buf += 2; + + do { + int seekerType = READ_LE_UINT16(buf); + + if (seekerType == 0) + break; + if (seekerType == 7) // exports + return buf; + + int seekerSize = READ_LE_UINT16(buf + 2); + assert(seekerSize > 0); + buf += seekerSize; + } while (1); + + return NULL; +} reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) { Resource *script = findResource(ResourceId(kResourceTypeScript, 0), false); @@ -1939,11 +1981,26 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) { if (!script) return NULL_REG; - int extraBytes = 0; - if (getSciVersion() == SCI_VERSION_0_EARLY || getSciVersion() >= SCI_VERSION_1_1) - extraBytes = 2; + byte *offsetPtr = 0; + + if (getSciVersion() < SCI_VERSION_1_1) { + byte *buf = (getSciVersion() == SCI_VERSION_0_EARLY) ? script->data + 2 : script->data; + + // 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 { + 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 = READ_UINT16(script->data + extraBytes + 4 + 2); + int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr); // In SCI1.1 and newer, the heap is appended at the end of the script, // so adjust the offset accordingly @@ -1986,6 +2043,4 @@ Common::String ResourceManager::findSierraGameId() { return sierraId; } -#undef READ_UINT16 - } // End of namespace Sci diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 65717e41248..f722ca57684 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -395,11 +395,11 @@ protected: Common::File *getVolumeFile(const char *filename); 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); diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index 5dea36bb07d..2fe6a7f3d56 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -62,10 +62,10 @@ void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) { } } -bool ResourceManager::loadFromWaveFile(Resource *res, Common::File &file) { +bool ResourceManager::loadFromWaveFile(Resource *res, Common::SeekableReadStream *file) { res->data = new byte[res->size]; - uint32 really_read = file.read(res->data, 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); @@ -73,26 +73,26 @@ bool ResourceManager::loadFromWaveFile(Resource *res, Common::File &file) { return true; } -bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::File &file) { +bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::SeekableReadStream *file) { // Check for WAVE files here - uint32 riffTag = file.readUint32BE(); + uint32 riffTag = file->readUint32BE(); if (riffTag == MKID_BE('RIFF')) { res->_headerSize = 0; - res->size = file.readUint32LE(); - file.seek(-8, SEEK_CUR); + res->size = file->readUint32LE(); + file->seek(-8, SEEK_CUR); return loadFromWaveFile(res, file); } - file.seek(-4, SEEK_CUR); + file->seek(-4, SEEK_CUR); - ResourceType type = (ResourceType)(file.readByte() & 0x7f); + 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()); + warning("Resource type mismatch loading %s", res->_id.toString().c_str()); res->unalloc(); return false; } - res->_headerSize = file.readByte(); + res->_headerSize = file->readByte(); if (type == kResourceTypeAudio) { if (res->_headerSize != 11 && res->_headerSize != 12) { @@ -102,23 +102,23 @@ bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::File &file } // Load sample size - file.seek(7, SEEK_CUR); - res->size = file.readUint32LE(); + file->seek(7, SEEK_CUR); + res->size = file->readUint32LE(); // Adjust offset to point at the header data again - file.seek(-11, SEEK_CUR); + file->seek(-11, SEEK_CUR); } return loadPatch(res, file); } -bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::File &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); + 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); From a8deacfc7eaf6b845d93b7a3f7343b55ee7ec097 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 2 Jun 2010 15:26:35 +0000 Subject: [PATCH 190/249] In Riven, if we get a change card opcode on a mouse down event, ignore the next mouse up event so we don't misinterpret that as an event in the next card; minor cleanup. svn-id: r49393 --- engines/mohawk/riven.cpp | 14 ++++++++++---- engines/mohawk/riven.h | 8 +++++++- engines/mohawk/riven_external.cpp | 2 +- engines/mohawk/riven_scripts.cpp | 13 ++++++++----- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index f3e4703c111..c646855bc78 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -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) { diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index f014b76fb87..11c3a4c0cb4 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 fd70de517f4..4e6bba1c2a5 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -210,7 +210,7 @@ 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() { diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp index b175b3af528..d574a455c61 100644 --- a/engines/mohawk/riven_scripts.cpp +++ b/engines/mohawk/riven_scripts.cpp @@ -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 From c4bdca72d7fcd837e51a449ff68a1d93977a0d18 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 2 Jun 2010 15:31:20 +0000 Subject: [PATCH 191/249] Fixed regression from commit #49332 (merging of the SCI0 and SCI11 relocate functions, where the SCI0 equivalent had a +1 count): it seems that we should skip over zero exports, however the total number of valid exports remains the same. Fixes KQ5 and QFG2. This also fixes the relocation calculation of script 71 in SQ3, so remove the comment that the script has broken relocation entries svn-id: r49394 --- engines/sci/engine/segment.cpp | 38 +++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 10d73d73255..988ee677414 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -101,7 +101,7 @@ Script::Script() : SegmentObj(SEG_TYPE_SCRIPT) { _localsSegment = 0; _localsBlock = NULL; - _markedAsDeleted = 0; + _markedAsDeleted = false; } Script::~Script() { @@ -306,17 +306,20 @@ void Script::relocate(reg_t block) { "Relocation block outside of script\n"); int count = READ_SCI11ENDIAN_UINT16(heap + block.offset); + int exportIndex = 0; for (int i = 0; i < count; i++) { - int pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (i * 2)) + heapOffset; - // This occurs in SCI01/SCI1 games where every other export - // value is zero. I have no idea what it's supposed to mean. - // - // Yes, there is code in the original to handle this situation, - // but we need an example of it happening in order to determine - // what to do. - if (!pos) - continue; // FIXME: Just ignore it for now. + 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; @@ -339,18 +342,19 @@ void Script::relocate(reg_t block) { } 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()); - // SQ3 script 71 has broken relocation entries. - printf("Trying to continue anyway...\n"); + debug("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount()); + debug("Trying to continue anyway...\n"); } } + + exportIndex++; } } From 14a4d8f8b06abb095cf6c9db718b4e26c266e78b Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 2 Jun 2010 17:04:55 +0000 Subject: [PATCH 192/249] Fix a regression from r49377 - we should be checking against code in addition to index for duplicate MLST's. svn-id: r49395 --- engines/mohawk/video.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index ed1fc6b2c62..a45a4294c83 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -246,11 +246,11 @@ void VideoManager::activateMLST(uint16 mlstId, uint16 card) { // We've found a match, add it if (mlstRecord.index == mlstId) { - // Make sure we don't have a duplicate + // Make sure we don't have any duplicates for (uint32 j = 0; j < _mlstRecords.size(); j++) - if (_mlstRecords[j].index == mlstId) { + if (_mlstRecords[j].index == mlstRecord.index || _mlstRecords[j].code == mlstRecord.code) { _mlstRecords.remove_at(j); - break; + j--; } _mlstRecords.push_back(mlstRecord); From 0d0abbc91a5fb0559e891a6f1f528a8c0dfa0b2f Mon Sep 17 00:00:00 2001 From: Oystein Eftevaag Date: Thu, 3 Jun 2010 03:11:19 +0000 Subject: [PATCH 193/249] Updated xcode project svn-id: r49402 --- .../iphone/scummvm.xcodeproj/project.pbxproj | 100 ++++++++++++++++-- 1 file changed, 90 insertions(+), 10 deletions(-) diff --git a/dists/iphone/scummvm.xcodeproj/project.pbxproj b/dists/iphone/scummvm.xcodeproj/project.pbxproj index 6876492a95e..032470cf254 100755 --- a/dists/iphone/scummvm.xcodeproj/project.pbxproj +++ b/dists/iphone/scummvm.xcodeproj/project.pbxproj @@ -735,7 +735,6 @@ DF09418A0F63CB26002D821E /* detection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAAAFFB0F0112DF003E9390 /* detection.cpp */; }; DF09418B0F63CB26002D821E /* thumbnail_intern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAAB0010F011392003E9390 /* thumbnail_intern.cpp */; }; DF09418C0F63CB26002D821E /* dither.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFB900F485D890006E566 /* dither.cpp */; }; - DF0941910F63CB26002D821E /* video_player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBA70F485D950006E566 /* video_player.cpp */; }; DF0941920F63CB26002D821E /* debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBD10F485DFB0006E566 /* debug.cpp */; }; DF0941930F63CB26002D821E /* GuiManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBD50F485E360006E566 /* GuiManager.cpp */; }; DF0941940F63CB26002D821E /* posix-saves.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBF80F4860A60006E566 /* posix-saves.cpp */; }; @@ -875,7 +874,6 @@ DF2EC51910E64EE600765801 /* wave6581.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2EC51710E64EE600765801 /* wave6581.cpp */; }; DF2EC51A10E64EE600765801 /* wave6581.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2EC51710E64EE600765801 /* wave6581.cpp */; }; DF2FFB930F485D890006E566 /* dither.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFB900F485D890006E566 /* dither.cpp */; }; - DF2FFBB70F485D950006E566 /* video_player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBA70F485D950006E566 /* video_player.cpp */; }; DF2FFBD30F485DFB0006E566 /* debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBD10F485DFB0006E566 /* debug.cpp */; }; DF2FFBD90F485E360006E566 /* GuiManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBD50F485E360006E566 /* GuiManager.cpp */; }; DF2FFBFC0F4860A60006E566 /* posix-saves.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBF80F4860A60006E566 /* posix-saves.cpp */; }; @@ -1915,6 +1913,33 @@ DFAAAFFC0F0112DF003E9390 /* detection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAAAFFB0F0112DF003E9390 /* detection.cpp */; }; DFAAB0020F011392003E9390 /* thumbnail_intern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAAB0010F011392003E9390 /* thumbnail_intern.cpp */; }; DFAAD23D0F50120E00C3A4E2 /* console.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAAD2390F50120E00C3A4E2 /* console.cpp */; }; + DFB0576811B753AF0015AE65 /* mpeg_player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0576211B753AF0015AE65 /* mpeg_player.cpp */; }; + DFB0576911B753AF0015AE65 /* qt_decoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0576411B753AF0015AE65 /* qt_decoder.cpp */; }; + DFB0576A11B753AF0015AE65 /* video_decoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0576611B753AF0015AE65 /* video_decoder.cpp */; }; + DFB0576B11B753AF0015AE65 /* mpeg_player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0576211B753AF0015AE65 /* mpeg_player.cpp */; }; + DFB0576C11B753AF0015AE65 /* qt_decoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0576411B753AF0015AE65 /* qt_decoder.cpp */; }; + DFB0576D11B753AF0015AE65 /* video_decoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0576611B753AF0015AE65 /* video_decoder.cpp */; }; + DFB0576E11B753AF0015AE65 /* mpeg_player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0576211B753AF0015AE65 /* mpeg_player.cpp */; }; + DFB0576F11B753AF0015AE65 /* qt_decoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0576411B753AF0015AE65 /* qt_decoder.cpp */; }; + DFB0577011B753AF0015AE65 /* video_decoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0576611B753AF0015AE65 /* video_decoder.cpp */; }; + DFB0577611B753DA0015AE65 /* rational.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0577411B753DA0015AE65 /* rational.cpp */; }; + DFB0577711B753DA0015AE65 /* rational.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0577411B753DA0015AE65 /* rational.cpp */; }; + DFB0577811B753DA0015AE65 /* rational.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0577411B753DA0015AE65 /* rational.cpp */; }; + DFB0578011B7541F0015AE65 /* resource_audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0577D11B7541F0015AE65 /* resource_audio.cpp */; }; + DFB0578111B7541F0015AE65 /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0577E11B7541F0015AE65 /* util.cpp */; }; + DFB0578211B7541F0015AE65 /* resource_audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0577D11B7541F0015AE65 /* resource_audio.cpp */; }; + DFB0578311B7541F0015AE65 /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0577E11B7541F0015AE65 /* util.cpp */; }; + DFB0578411B7541F0015AE65 /* resource_audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0577D11B7541F0015AE65 /* resource_audio.cpp */; }; + DFB0578511B7541F0015AE65 /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0577E11B7541F0015AE65 /* util.cpp */; }; + DFB0578A11B754570015AE65 /* maciconbar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0578811B754570015AE65 /* maciconbar.cpp */; }; + DFB0578B11B754570015AE65 /* maciconbar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0578811B754570015AE65 /* maciconbar.cpp */; }; + DFB0578C11B754570015AE65 /* maciconbar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0578811B754570015AE65 /* maciconbar.cpp */; }; + DFB0579111B7547D0015AE65 /* pict.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0578F11B7547D0015AE65 /* pict.cpp */; }; + DFB0579211B7547D0015AE65 /* pict.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0578F11B7547D0015AE65 /* pict.cpp */; }; + DFB0579311B7547D0015AE65 /* pict.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0578F11B7547D0015AE65 /* pict.cpp */; }; + DFB0579811B7549C0015AE65 /* cinepak.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0579611B7549C0015AE65 /* cinepak.cpp */; }; + DFB0579911B7549C0015AE65 /* cinepak.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0579611B7549C0015AE65 /* cinepak.cpp */; }; + DFB0579A11B7549C0015AE65 /* cinepak.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFB0579611B7549C0015AE65 /* cinepak.cpp */; }; DFC831210F48AF19005EF03C /* detection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC8301A0F48AF18005EF03C /* detection.cpp */; }; DFC831230F48AF19005EF03C /* game.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC8301D0F48AF18005EF03C /* game.cpp */; }; DFC831240F48AF19005EF03C /* gc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFC8301E0F48AF18005EF03C /* gc.cpp */; }; @@ -2796,7 +2821,6 @@ DFF95C1F0FB22D5700A3EC78 /* detection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAAAFFB0F0112DF003E9390 /* detection.cpp */; }; DFF95C200FB22D5700A3EC78 /* thumbnail_intern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAAB0010F011392003E9390 /* thumbnail_intern.cpp */; }; DFF95C210FB22D5700A3EC78 /* dither.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFB900F485D890006E566 /* dither.cpp */; }; - DFF95C260FB22D5700A3EC78 /* video_player.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBA70F485D950006E566 /* video_player.cpp */; }; DFF95C270FB22D5700A3EC78 /* debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBD10F485DFB0006E566 /* debug.cpp */; }; DFF95C280FB22D5700A3EC78 /* GuiManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBD50F485E360006E566 /* GuiManager.cpp */; }; DFF95C290FB22D5700A3EC78 /* posix-saves.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF2FFBF80F4860A60006E566 /* posix-saves.cpp */; }; @@ -2985,8 +3009,6 @@ DF2FFB900F485D890006E566 /* dither.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dither.cpp; sourceTree = ""; }; DF2FFB910F485D890006E566 /* dither.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dither.h; sourceTree = ""; }; DF2FFB920F485D890006E566 /* pixelformat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pixelformat.h; sourceTree = ""; }; - DF2FFBA70F485D950006E566 /* video_player.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = video_player.cpp; sourceTree = ""; }; - DF2FFBA80F485D950006E566 /* video_player.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = video_player.h; sourceTree = ""; }; DF2FFBD10F485DFB0006E566 /* debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debug.cpp; sourceTree = ""; }; DF2FFBD20F485DFB0006E566 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = ""; }; DF2FFBD50F485E360006E566 /* GuiManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GuiManager.cpp; sourceTree = ""; }; @@ -4358,6 +4380,24 @@ DFAAB0010F011392003E9390 /* thumbnail_intern.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thumbnail_intern.cpp; sourceTree = ""; }; DFAAD2390F50120E00C3A4E2 /* console.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = console.cpp; sourceTree = ""; }; DFAAD23A0F50120E00C3A4E2 /* console.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = console.h; sourceTree = ""; }; + DFB0576211B753AF0015AE65 /* mpeg_player.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mpeg_player.cpp; sourceTree = ""; }; + DFB0576311B753AF0015AE65 /* mpeg_player.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mpeg_player.h; sourceTree = ""; }; + DFB0576411B753AF0015AE65 /* qt_decoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = qt_decoder.cpp; sourceTree = ""; }; + DFB0576511B753AF0015AE65 /* qt_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = qt_decoder.h; sourceTree = ""; }; + DFB0576611B753AF0015AE65 /* video_decoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = video_decoder.cpp; sourceTree = ""; }; + DFB0576711B753AF0015AE65 /* video_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = video_decoder.h; sourceTree = ""; }; + DFB0577311B753DA0015AE65 /* debug-channels.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "debug-channels.h"; sourceTree = ""; }; + DFB0577411B753DA0015AE65 /* rational.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rational.cpp; sourceTree = ""; }; + DFB0577511B753DA0015AE65 /* rational.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rational.h; sourceTree = ""; }; + DFB0577D11B7541F0015AE65 /* resource_audio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = resource_audio.cpp; sourceTree = ""; }; + DFB0577E11B7541F0015AE65 /* util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = util.cpp; sourceTree = ""; }; + DFB0577F11B7541F0015AE65 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = ""; }; + DFB0578811B754570015AE65 /* maciconbar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = maciconbar.cpp; sourceTree = ""; }; + DFB0578911B754570015AE65 /* maciconbar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = maciconbar.h; sourceTree = ""; }; + DFB0578F11B7547D0015AE65 /* pict.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pict.cpp; sourceTree = ""; }; + DFB0579011B7547D0015AE65 /* pict.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pict.h; sourceTree = ""; }; + DFB0579611B7549C0015AE65 /* cinepak.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cinepak.cpp; sourceTree = ""; }; + DFB0579711B7549C0015AE65 /* cinepak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cinepak.h; sourceTree = ""; }; DFC8301A0F48AF18005EF03C /* detection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = detection.cpp; sourceTree = ""; }; DFC8301D0F48AF18005EF03C /* game.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = game.cpp; sourceTree = ""; }; DFC8301E0F48AF18005EF03C /* gc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gc.cpp; sourceTree = ""; }; @@ -4776,6 +4816,12 @@ DF2FFB940F485D950006E566 /* video */ = { isa = PBXGroup; children = ( + DFB0576211B753AF0015AE65 /* mpeg_player.cpp */, + DFB0576311B753AF0015AE65 /* mpeg_player.h */, + DFB0576411B753AF0015AE65 /* qt_decoder.cpp */, + DFB0576511B753AF0015AE65 /* qt_decoder.h */, + DFB0576611B753AF0015AE65 /* video_decoder.cpp */, + DFB0576711B753AF0015AE65 /* video_decoder.h */, DF90EABF10B023F300C8F93F /* codecs */, DF90EAB610B023D100C8F93F /* avi_decoder.cpp */, DF90EAB710B023D100C8F93F /* avi_decoder.h */, @@ -4786,8 +4832,6 @@ DF6118630FE3A9410042AD3F /* flic_decoder.h */, DF6118640FE3A9410042AD3F /* smk_decoder.cpp */, DF6118650FE3A9410042AD3F /* smk_decoder.h */, - DF2FFBA70F485D950006E566 /* video_player.cpp */, - DF2FFBA80F485D950006E566 /* video_player.h */, ); path = video; sourceTree = ""; @@ -4884,6 +4928,8 @@ DF45B175116628A5009B85CC /* graphics */ = { isa = PBXGroup; children = ( + DFB0578811B754570015AE65 /* maciconbar.cpp */, + DFB0578911B754570015AE65 /* maciconbar.h */, DF9B924F118E46A00069C19D /* fontsjis.cpp */, DF9B9250118E46A00069C19D /* fontsjis.h */, DF45B176116628A5009B85CC /* animate.cpp */, @@ -6388,6 +6434,8 @@ DF90EABF10B023F300C8F93F /* codecs */ = { isa = PBXGroup; children = ( + DFB0579611B7549C0015AE65 /* cinepak.cpp */, + DFB0579711B7549C0015AE65 /* cinepak.h */, DFCDC6FC11662AD700A7D2A0 /* msrle.cpp */, DFCDC6FD11662AD700A7D2A0 /* msrle.h */, DF90EAC010B023F400C8F93F /* codec.h */, @@ -6414,6 +6462,9 @@ DFC830190F48AF18005EF03C /* sci */ = { isa = PBXGroup; children = ( + DFB0577D11B7541F0015AE65 /* resource_audio.cpp */, + DFB0577E11B7541F0015AE65 /* util.cpp */, + DFB0577F11B7541F0015AE65 /* util.h */, DF45B175116628A5009B85CC /* graphics */, DF45B1A5116628A5009B85CC /* parser */, DF45B1AB116628A5009B85CC /* sound */, @@ -6685,6 +6736,9 @@ DFE473950D81F4E800B6D1FB /* common */ = { isa = PBXGroup; children = ( + DFB0577311B753DA0015AE65 /* debug-channels.h */, + DFB0577411B753DA0015AE65 /* rational.cpp */, + DFB0577511B753DA0015AE65 /* rational.h */, DF9B9261118E46FE0069C19D /* error.cpp */, DFEC5D0A1166C5CF00C90552 /* random.cpp */, DFEC5D0B1166C5CF00C90552 /* random.h */, @@ -6767,6 +6821,8 @@ DFE477520D81F4E900B6D1FB /* graphics */ = { isa = PBXGroup; children = ( + DFB0578F11B7547D0015AE65 /* pict.cpp */, + DFB0579011B7547D0015AE65 /* pict.h */, DF6BF4C010529DA50069811F /* conversion.cpp */, DF6BF4C110529DA50069811F /* conversion.h */, DF6BF4C210529DA50069811F /* jpeg.cpp */, @@ -7834,7 +7890,6 @@ DFAAAFFC0F0112DF003E9390 /* detection.cpp in Sources */, DFAAB0020F011392003E9390 /* thumbnail_intern.cpp in Sources */, DF2FFB930F485D890006E566 /* dither.cpp in Sources */, - DF2FFBB70F485D950006E566 /* video_player.cpp in Sources */, DF2FFBD30F485DFB0006E566 /* debug.cpp in Sources */, DF2FFBD90F485E360006E566 /* GuiManager.cpp in Sources */, DF2FFBFC0F4860A60006E566 /* posix-saves.cpp in Sources */, @@ -8055,6 +8110,15 @@ DF9B9249118E46730069C19D /* error.cpp in Sources */, DF9B9254118E46A00069C19D /* fontsjis.cpp in Sources */, DF9B9263118E46FE0069C19D /* error.cpp in Sources */, + DFB0576B11B753AF0015AE65 /* mpeg_player.cpp in Sources */, + DFB0576C11B753AF0015AE65 /* qt_decoder.cpp in Sources */, + DFB0576D11B753AF0015AE65 /* video_decoder.cpp in Sources */, + DFB0577711B753DA0015AE65 /* rational.cpp in Sources */, + DFB0578211B7541F0015AE65 /* resource_audio.cpp in Sources */, + DFB0578311B7541F0015AE65 /* util.cpp in Sources */, + DFB0578B11B754570015AE65 /* maciconbar.cpp in Sources */, + DFB0579211B7547D0015AE65 /* pict.cpp in Sources */, + DFB0579911B7549C0015AE65 /* cinepak.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -8781,7 +8845,6 @@ DF09418A0F63CB26002D821E /* detection.cpp in Sources */, DF09418B0F63CB26002D821E /* thumbnail_intern.cpp in Sources */, DF09418C0F63CB26002D821E /* dither.cpp in Sources */, - DF0941910F63CB26002D821E /* video_player.cpp in Sources */, DF0941920F63CB26002D821E /* debug.cpp in Sources */, DF0941930F63CB26002D821E /* GuiManager.cpp in Sources */, DF0941940F63CB26002D821E /* posix-saves.cpp in Sources */, @@ -9006,6 +9069,15 @@ DF9B924A118E46730069C19D /* error.cpp in Sources */, DF9B9256118E46A00069C19D /* fontsjis.cpp in Sources */, DF9B9264118E46FE0069C19D /* error.cpp in Sources */, + DFB0576E11B753AF0015AE65 /* mpeg_player.cpp in Sources */, + DFB0576F11B753AF0015AE65 /* qt_decoder.cpp in Sources */, + DFB0577011B753AF0015AE65 /* video_decoder.cpp in Sources */, + DFB0577811B753DA0015AE65 /* rational.cpp in Sources */, + DFB0578411B7541F0015AE65 /* resource_audio.cpp in Sources */, + DFB0578511B7541F0015AE65 /* util.cpp in Sources */, + DFB0578C11B754570015AE65 /* maciconbar.cpp in Sources */, + DFB0579311B7547D0015AE65 /* pict.cpp in Sources */, + DFB0579A11B7549C0015AE65 /* cinepak.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -9737,7 +9809,6 @@ DFF95C1F0FB22D5700A3EC78 /* detection.cpp in Sources */, DFF95C200FB22D5700A3EC78 /* thumbnail_intern.cpp in Sources */, DFF95C210FB22D5700A3EC78 /* dither.cpp in Sources */, - DFF95C260FB22D5700A3EC78 /* video_player.cpp in Sources */, DFF95C270FB22D5700A3EC78 /* debug.cpp in Sources */, DFF95C280FB22D5700A3EC78 /* GuiManager.cpp in Sources */, DFF95C290FB22D5700A3EC78 /* posix-saves.cpp in Sources */, @@ -9958,6 +10029,15 @@ DF9B9248118E46730069C19D /* error.cpp in Sources */, DF9B9252118E46A00069C19D /* fontsjis.cpp in Sources */, DF9B9262118E46FE0069C19D /* error.cpp in Sources */, + DFB0576811B753AF0015AE65 /* mpeg_player.cpp in Sources */, + DFB0576911B753AF0015AE65 /* qt_decoder.cpp in Sources */, + DFB0576A11B753AF0015AE65 /* video_decoder.cpp in Sources */, + DFB0577611B753DA0015AE65 /* rational.cpp in Sources */, + DFB0578011B7541F0015AE65 /* resource_audio.cpp in Sources */, + DFB0578111B7541F0015AE65 /* util.cpp in Sources */, + DFB0578A11B754570015AE65 /* maciconbar.cpp in Sources */, + DFB0579111B7547D0015AE65 /* pict.cpp in Sources */, + DFB0579811B7549C0015AE65 /* cinepak.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 90649938d2d70115967c45cdd1cbb8dab1635794 Mon Sep 17 00:00:00 2001 From: Oystein Eftevaag Date: Thu, 3 Jun 2010 03:22:10 +0000 Subject: [PATCH 194/249] We'll now default to non-touchpad mode on the iPad svn-id: r49403 --- backends/platform/iphone/iphone_common.h | 1 + backends/platform/iphone/iphone_video.h | 2 -- backends/platform/iphone/iphone_video.m | 6 ++++++ backends/platform/iphone/osys_main.cpp | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/backends/platform/iphone/iphone_common.h b/backends/platform/iphone/iphone_common.h index 9f7e3e808f5..1f5ed019824 100644 --- a/backends/platform/iphone/iphone_common.h +++ b/backends/platform/iphone/iphone_common.h @@ -72,6 +72,7 @@ void iPhone_updateScreenRect(unsigned short* screen, int x1, int y1, int x2, int void iPhone_initSurface(int width, int height); bool iPhone_fetchEvent(int *outEvent, float *outX, float *outY); const char* iPhone_getDocumentsDir(); +bool iPhone_isHighResDevice(); #ifdef __cplusplus } diff --git a/backends/platform/iphone/iphone_video.h b/backends/platform/iphone/iphone_video.h index daa5e1d18e1..1060a2a223e 100644 --- a/backends/platform/iphone/iphone_video.h +++ b/backends/platform/iphone/iphone_video.h @@ -43,8 +43,6 @@ SoftKeyboard* _keyboardView; CALayer* _screenLayer; - int _fullWidth; - int _fullHeight; int _widthOffset; int _heightOffset; diff --git a/backends/platform/iphone/iphone_video.m b/backends/platform/iphone/iphone_video.m index e8977be2f23..faa0719b6cd 100644 --- a/backends/platform/iphone/iphone_video.m +++ b/backends/platform/iphone/iphone_video.m @@ -29,6 +29,8 @@ static iPhoneView *sharedInstance = nil; static int _width = 0; static int _height = 0; +static int _fullWidth; +static int _fullHeight; static CGRect _screenRect; static char* _textureBuffer = 0; static int _textureWidth = 0; @@ -42,6 +44,10 @@ static UITouch* _secondTouch = NULL; // static long lastTick = 0; // static int frames = 0; +bool iPhone_isHighResDevice() { + return _fullHeight > 480; +} + void iPhone_updateScreen() { if (!_needsScreenUpdate) { _needsScreenUpdate = 1; diff --git a/backends/platform/iphone/osys_main.cpp b/backends/platform/iphone/osys_main.cpp index b151688e4ed..6c26b6ca8dc 100644 --- a/backends/platform/iphone/osys_main.cpp +++ b/backends/platform/iphone/osys_main.cpp @@ -57,7 +57,7 @@ OSystem_IPHONE::OSystem_IPHONE() : _overlayVisible(false), _overlayBuffer(NULL), _fullscreen(NULL), _mouseHeight(0), _mouseWidth(0), _mouseBuf(NULL), _lastMouseTap(0), _secondaryTapped(false), _lastSecondaryTap(0), _screenOrientation(kScreenOrientationFlippedLandscape), - _needEventRestPeriod(false), _mouseClickAndDragEnabled(false), _touchpadModeEnabled(true), + _needEventRestPeriod(false), _mouseClickAndDragEnabled(false), _gestureStartX(-1), _gestureStartY(-1), _fullScreenIsDirty(false), _fullScreenOverlayIsDirty(false), _mouseDirty(false), _timeSuspended(0), _lastDragPosX(-1), _lastDragPosY(-1), _screenChangeCount(0) @@ -65,6 +65,7 @@ OSystem_IPHONE::OSystem_IPHONE() : _queuedInputEvent.type = (Common::EventType)0; _lastDrawnMouseRect = Common::Rect(0, 0, 0, 0); + _touchpadModeEnabled = !iPhone_isHighResDevice(); _fsFactory = new POSIXFilesystemFactory(); } From 86dcc28342021933f04ff3542932fc8823ff2360 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Thu, 3 Jun 2010 09:34:32 +0000 Subject: [PATCH 195/249] Moved the MADS interface view into mads_scene.cpp and did a major cleanup of scene loading code svn-id: r49405 --- engines/m4/animation.cpp | 28 +- engines/m4/animation.h | 5 +- engines/m4/console.cpp | 8 +- engines/m4/graphics.cpp | 26 ++ engines/m4/graphics.h | 14 +- engines/m4/mads_scene.cpp | 552 +++++++++++++++++++++++++++++++++++--- engines/m4/mads_scene.h | 67 ++++- engines/m4/mads_views.cpp | 445 +----------------------------- engines/m4/mads_views.h | 62 +---- 9 files changed, 647 insertions(+), 560 deletions(-) diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index 9c31cd35d72..412f514e5ba 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -26,6 +26,7 @@ #include "m4/assets.h" #include "m4/animation.h" #include "m4/compression.h" +#include "m4/mads_scene.h" namespace M4 { @@ -44,7 +45,7 @@ MadsAnimation::~MadsAnimation() { delete _font; } -void MadsAnimation::load(const Common::String &filename) { +void MadsAnimation::load(const Common::String &filename, uint16 flags, M4Surface *walkSurface, M4Surface *sceneSurface) { MadsPack anim(filename.c_str(), _vm); bool madsRes = filename[0] == '*'; char buffer[20]; @@ -64,7 +65,6 @@ void MadsAnimation::load(const Common::String &filename) { animStream->skip(2); _animMode = animStream->readUint16LE(); - assert(_animMode != 4); _roomNumber = animStream->readUint16LE(); _field12 = animStream->readUint16LE() != 0; animStream->skip(4); @@ -74,7 +74,7 @@ void MadsAnimation::load(const Common::String &filename) { animStream->skip(10); animStream->read(buffer, 13); - _field24 = Common::String(buffer, 13); + _infoFilename = Common::String(buffer, 13); for (int i = 0; i < 10; ++i) { animStream->read(buffer, 13); @@ -93,8 +93,10 @@ void MadsAnimation::load(const Common::String &filename) { animStream->read(buffer, 13); Common::String fontResource(buffer, 13); - // TODO: Based on a weird usage of a flags word, a secondary method gets called here. - // Figure out secondary method, and when/if it's called + if (_animMode == 4) + flags |= 0x4000; + if (flags & 0x100) + loadInterface(walkSurface, sceneSurface); // Initialise the reference list for (int i = 0; i < spriteListCount; ++i) @@ -416,12 +418,24 @@ void MadsAnimation::load1(int frameNumber) { if (proc1(spriteSet, pt, frameNumber)) error("proc1 failure"); - - } bool MadsAnimation::proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber) { return 0; } +void MadsAnimation::loadInterface(M4Surface *walkSurface, M4Surface *sceneSurface) { + walkSurface->madsloadInterface(0); + + + /* TODO - implement properly + if (_animMode > 2) { + warning("Mode1"); + } else { + MadsSceneResources sceneResources; + sceneResources.load(_roomNumber, _infoFilename.c_str(), 0, walkSurface, sceneSurface); + } + */ +} + } // End of namespace M4 diff --git a/engines/m4/animation.h b/engines/m4/animation.h index a5f3ea30856..cb68b278537 100644 --- a/engines/m4/animation.h +++ b/engines/m4/animation.h @@ -83,7 +83,7 @@ private: int _spriteListIndex; int _scrollX; int _scrollY; - Common::String _field24; + Common::String _infoFilename; Common::String _spriteSetNames[10]; Common::String _lbmFilename; Common::String _spritesFilename; @@ -104,11 +104,12 @@ private: void load1(int frameNumber); bool proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber); + void loadInterface(M4Surface *walkSurface, M4Surface *sceneSurface); public: MadsAnimation(MadsM4Engine *vm, MadsView *view); virtual ~MadsAnimation(); - virtual void load(const Common::String &filename); + virtual void load(const Common::String &filename, uint16 flags, M4Surface *walkSurface, M4Surface *sceneSurface); virtual void start(); virtual bool update(); virtual void stop(); diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp index d568584d30c..ccb1c8c1825 100644 --- a/engines/m4/console.cpp +++ b/engines/m4/console.cpp @@ -375,10 +375,10 @@ bool MadsConsole::cmdPlayAnimation(int argc, const char **argv) { _vm->_viewManager->moveToFront(view); if (argc == 3 && atoi(argv[2]) == 1) - _madsVm->scene()->_sceneAnimation.loadFullScreen(resourceName); - else - _madsVm->scene()->_sceneAnimation.load(resourceName); - _madsVm->scene()->_sceneAnimation.start(); + _madsVm->_palette->deleteAllRanges(); + + _madsVm->scene()->_sceneAnimation->load(resourceName, 0, NULL, NULL); + _madsVm->scene()->_sceneAnimation->start(); view->restore(0, 0, view->width(), view->height()); return false; diff --git a/engines/m4/graphics.cpp b/engines/m4/graphics.cpp index 66668142899..edabcd8b228 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) @@ -717,6 +733,10 @@ void M4Surface::madsloadInterface(int index, RGBList **palData) { MadsPack intFile(resourceName, _vm); RGB8 *palette = new RGB8[16]; + bool hasPalette = palData != NULL; + if (!hasPalette) + palData = &_rgbList; + // Chunk 0, palette Common::SeekableReadStream *intStream = intFile.getItemStream(0); @@ -736,6 +756,12 @@ void M4Surface::madsloadInterface(int index, RGBList **palData) { create(320, 44, 1); intStream->read(pixels, 320 * 44); delete intStream; + + if (!hasPalette) { + // Translate the interface palette + _vm->_palette->addRange(_rgbList); + this->translate(_rgbList); + } } void M4Surface::scrollX(int xAmount) { diff --git a/engines/m4/graphics.h b/engines/m4/graphics.h index c140140f976..97fdfc0d6ce 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,7 @@ 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 setColor(byte value) { _color = value; } void setColour(byte value) { _color = value; } diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp index 60e480e6fb0..b69c8bd116e 100644 --- a/engines/m4/mads_scene.cpp +++ b/engines/m4/mads_scene.cpp @@ -40,6 +40,13 @@ 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; @@ -66,10 +73,17 @@ void MadsScene::loadScene2(const char *aaName) { _kernelMessages.clear(); // Load up the properties for the scene - _sceneResources.load(_currentScene); + _sceneResources.load(_currentScene, 0/*word_83546*/, NULL, _walkSurface, _backgroundSurface); // Load scene walk paths loadSceneCodes(_currentScene); + + // Initialise the scene animation + uint16 flags = 0x4100; + if (_madsVm->globals()->_config.textWindowStill) + flags |= 0x200; + + _sceneAnimation->load(aaName, flags, _interfaceSurface, NULL); } /** @@ -83,22 +97,7 @@ void MadsScene::loadSceneTemporary() { {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); @@ -185,15 +184,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; - } } } @@ -614,45 +604,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 sceneId, const char *resName, int v0, M4Surface *depthSurface, M4Surface *surface) { + char buffer[80]; + const char *sceneName; + + // TODO: Initialise spriteSet / xp_list + + if (sceneId > 0) { + sceneName = MADSResourceManager::getResourceName(RESPREFIX_RM, sceneId, ".DAT"); + } else { + strcat(buffer, "*"); + strcat(buffer, resName); + sceneName = buffer; // 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 == sceneId); artFileNum = stream->readUint16LE(); - field_4 = stream->readUint16LE(); + dialogStyle = 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 buffer[64]; + Common::String s(buffer, 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 (dialogStyle == 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(sceneId); + + // Final cleanup + if (ssFlag) + delete surface; + if (dsFlag) + delete depthSurface; } + /*--------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------- + * 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->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 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->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; + } + + 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 c8a0da3aea3..e3e4c3c084c 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 dialogStyle; int width; int height; - - int objectCount; - MadsObject objects[32]; + Common::Array objects; + Common::Array 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}; @@ -137,6 +134,56 @@ public: void setStatusText(const char *text) {}//***DEPRECATED*** }; +#define CHEAT_SEQUENCE_MAX 8 + +class IntegerList : public Common::Array { +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 f4f43c48f12..79ca2c51b7f 100644 --- a/engines/m4/mads_views.cpp +++ b/engines/m4/mads_views.cpp @@ -37,13 +37,6 @@ 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); @@ -1149,17 +1142,11 @@ Animation::Animation(MadsM4Engine *vm): _vm(vm) { Animation::~Animation() { } -void Animation::loadFullScreen(const Common::String &filename) { - _vm->_palette->deleteAllRanges(); - load(filename); -} - //-------------------------------------------------------------------------- MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceList(*this), - _kernelMessages(*this), _spriteSlots(*this), _dirtyAreas(*this), _textDisplay(*this), - // FIXME: There's probably a cleaner way to do this, and I don't think the destructor is ever called - _sceneAnimation(*new MadsAnimation(_vm, this)) { + _kernelMessages(*this), _spriteSlots(*this), _dirtyAreas(*this), _textDisplay(*this) { + _textSpacing = -1; _ticksAmount = 3; _newTimeout = 0; @@ -1170,6 +1157,11 @@ MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceL _depthSurface = NULL; _bgSurface = NULL; + _sceneAnimation = new MadsAnimation(_vm, this); +} + +MadsView::~MadsView() { + delete _sceneAnimation; } void MadsView::refresh() { @@ -1203,427 +1195,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->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 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->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; - } - - 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 6f264312d19..31b8cd891f4 100644 --- a/engines/m4/mads_views.h +++ b/engines/m4/mads_views.h @@ -34,11 +34,6 @@ 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}; @@ -372,9 +367,7 @@ protected: public: Animation(MadsM4Engine *vm); virtual ~Animation(); - void loadFullScreen(const Common::String &filename); - - virtual void load(const Common::String &filename) = 0; + virtual void load(const Common::String &filename, uint16 flags, M4Surface *walkSurface, M4Surface *sceneSurface) = 0; virtual void start() = 0; virtual bool update() = 0; virtual void stop() = 0; @@ -386,7 +379,7 @@ class MadsView { private: View *_view; public: - Animation &_sceneAnimation; + Animation *_sceneAnimation; MadsSpriteSlots _spriteSlots; MadsTextDisplay _textDisplay; MadsKernelMessageList _kernelMessages; @@ -408,60 +401,11 @@ public: M4Surface *_bgSurface; public: MadsView(View *view); + ~MadsView(); void refresh(); }; -#define CHEAT_SEQUENCE_MAX 8 - -class IntegerList : public Common::Array { -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 From 86b452d36cb781c24e1b167dd6cef768b7c6286b Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 3 Jun 2010 10:16:21 +0000 Subject: [PATCH 196/249] Moved several object-related defines inside vm.h into segment.h, where the Object class resides. Also, removed several unused defines svn-id: r49406 --- engines/sci/console.cpp | 2 +- engines/sci/engine/kscripts.cpp | 4 ++-- engines/sci/engine/script.cpp | 2 +- engines/sci/engine/segment.cpp | 12 +++++----- engines/sci/engine/segment.h | 21 ++++++++++++++++- engines/sci/engine/vm.h | 40 +-------------------------------- 6 files changed, 31 insertions(+), 50 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 3b237f44edf..bad39d30653 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -3067,7 +3067,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++) { diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index 2f260bc03ab..722d0175d17 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -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,7 +154,7 @@ 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; diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 3fb8a5763e6..1f32e50b671 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -205,7 +205,7 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) { 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) { // -info- selector + if (READ_SCI11ENDIAN_UINT16(seeker + 14) & kInfoFlagClass) { // -info- selector int classpos = seeker - scr->_buf; int species = READ_SCI11ENDIAN_UINT16(seeker + 10); diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 988ee677414..0e0a759d4bb 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -240,7 +240,7 @@ Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) { 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, fullObjectInit); @@ -693,9 +693,9 @@ void Object::init(byte *buf, reg_t obj_pos, bool initVariables) { _pos = obj_pos; if (getSciVersion() < SCI_VERSION_1_1) { - _variables.resize(READ_LE_UINT16(data + SCRIPT_SELECTORCTR_OFFSET)); + _variables.resize(READ_LE_UINT16(data + kOffsetSelectorCounter)); _baseVars = (const uint16 *)(_baseObj + _variables.size() * 2); - _baseMethod = (const uint16 *)(data + READ_LE_UINT16(data + SCRIPT_FUNCTAREAPTR_OFFSET)); + _baseMethod = (const uint16 *)(data + READ_LE_UINT16(data + kOffsetFunctionArea)); _methodCount = READ_LE_UINT16(_baseMethod - 1); } else { _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2)); @@ -720,7 +720,7 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) const { 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 { const Object *obj = getClass(segMan); @@ -749,11 +749,11 @@ int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const { } if (getSciVersion() < SCI_VERSION_1_1) { - const byte *selectoroffset = ((const byte *)(_baseObj)) + SCRIPT_SELECTOR_OFFSET + selectors * 2; + const byte *selectoroffset = ((const byte *)(_baseObj)) + kOffsetSelectorSegment + selectors * 2; return READ_SCI11ENDIAN_UINT16(selectoroffset + propertyOffset); } else { const Object *obj = this; - if (!(getInfoSelector().offset & SCRIPT_INFO_CLASS)) + if (!isClass()) obj = segMan->getObject(getSuperClassSelector()); return READ_SCI11ENDIAN_UINT16((const byte *)obj->_baseVars + propertyOffset); diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 051354bf7a0..d89f54fbe26 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -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() { @@ -264,9 +280,12 @@ public: */ int locateVarSelector(SegManager *segMan, Selector slc) const; - bool isClass() const { return (getInfoSelector().offset & SCRIPT_INFO_CLASS); } + bool isClass() const { return (getInfoSelector().offset & kInfoFlagClass); } const Object *getClass(SegManager *segMan) const; + void markAsClone() { setInfoSelector(make_reg(0, kInfoFlagClone)); } + bool isClone() const { return (getInfoSelector().offset & kInfoFlagClone); } + void markAsFreed() { _flags |= OBJECT_FLAG_FREED; } bool isFreed() const { return _flags & OBJECT_FLAG_FREED; } diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 7ea0b2e5482..dd1294b59c8 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,9 +54,6 @@ 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 From f1af6bad6db5714a8a2f4664b080d5d45c0810d1 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 3 Jun 2010 10:26:51 +0000 Subject: [PATCH 197/249] Fixed compilation svn-id: r49407 --- engines/sci/engine/segment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index d89f54fbe26..f1b6dccaa25 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -218,7 +218,7 @@ enum ObjectOffsets { kOffsetInfoSelectorSci0 = 4, kOffsetNamePointerSci0 = 6, kOffsetInfoSelectorSci11 = 14, - kOffsetNamePointerSci11 = 16, + kOffsetNamePointerSci11 = 16 }; class Object { From 2ae4c5796b44f6ab6ecf68425e096dde50cb9f95 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 3 Jun 2010 10:44:50 +0000 Subject: [PATCH 198/249] The setCursor selector is no longer used for the detection of the kSetCursor() kernel function semantics svn-id: r49408 --- engines/sci/engine/selector.cpp | 1 - engines/sci/engine/vm.h | 1 - 2 files changed, 2 deletions(-) diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp index 92fed6e13eb..04a1b8fbba6 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -153,7 +153,6 @@ void Kernel::mapSelectors() { FIND_SELECTOR(subtitleLang); FIND_SELECTOR(parseLang); FIND_SELECTOR(overlay); - FIND_SELECTOR(setCursor); FIND_SELECTOR(topString); FIND_SELECTOR(scaleSignal); FIND_SELECTOR(scaleX); diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index dd1294b59c8..42ee55cd06a 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -157,7 +157,6 @@ 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 From 26860b8e5170d9da92b5da82325c137fddfd8778 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Thu, 3 Jun 2010 10:46:55 +0000 Subject: [PATCH 199/249] Properly implemented the logic for loading the correct interface background as specified in a scene's resources svn-id: r49409 --- engines/m4/animation.cpp | 36 +++++++++++++++++++++++------------- engines/m4/animation.h | 4 ++-- engines/m4/graphics.cpp | 20 ++++++-------------- engines/m4/graphics.h | 3 ++- 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index 412f514e5ba..58d829c4a23 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -45,7 +45,7 @@ MadsAnimation::~MadsAnimation() { delete _font; } -void MadsAnimation::load(const Common::String &filename, uint16 flags, M4Surface *walkSurface, M4Surface *sceneSurface) { +void MadsAnimation::load(const Common::String &filename, uint16 flags, M4Surface *interfaceSurface, M4Surface *sceneSurface) { MadsPack anim(filename.c_str(), _vm); bool madsRes = filename[0] == '*'; char buffer[20]; @@ -66,8 +66,8 @@ void MadsAnimation::load(const Common::String &filename, uint16 flags, M4Surface animStream->skip(2); _animMode = animStream->readUint16LE(); _roomNumber = animStream->readUint16LE(); + animStream->skip(2); _field12 = animStream->readUint16LE() != 0; - animStream->skip(4); _spriteListIndex = animStream->readUint16LE(); _scrollX = animStream->readUint16LE(); _scrollY = animStream->readSint16LE(); @@ -96,7 +96,7 @@ void MadsAnimation::load(const Common::String &filename, uint16 flags, M4Surface if (_animMode == 4) flags |= 0x4000; if (flags & 0x100) - loadInterface(walkSurface, sceneSurface); + loadInterface(interfaceSurface, sceneSurface); // Initialise the reference list for (int i = 0; i < spriteListCount; ++i) @@ -424,18 +424,28 @@ bool MadsAnimation::proc1(SpriteAsset &spriteSet, const Common::Point &pt, int f return 0; } -void MadsAnimation::loadInterface(M4Surface *walkSurface, M4Surface *sceneSurface) { - walkSurface->madsloadInterface(0); - - - /* TODO - implement properly - if (_animMode > 2) { - warning("Mode1"); - } else { +void MadsAnimation::loadInterface(M4Surface *&interfaceSurface, M4Surface *&depthSurface) { + if (_animMode <= 2) { MadsSceneResources sceneResources; - sceneResources.load(_roomNumber, _infoFilename.c_str(), 0, walkSurface, sceneSurface); + sceneResources.load(_roomNumber, _infoFilename.c_str(), 0, depthSurface, interfaceSurface); + + // Rex only supports a single dialog draw style + assert(sceneResources.dialogStyle == 2); + + } else if (_animMode == 4) { + // Load a scene interface + interfaceSurface->madsLoadInterface(_infoFilename); + } 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(); } - */ } } // End of namespace M4 diff --git a/engines/m4/animation.h b/engines/m4/animation.h index cb68b278537..838e4b6175c 100644 --- a/engines/m4/animation.h +++ b/engines/m4/animation.h @@ -104,12 +104,12 @@ private: void load1(int frameNumber); bool proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber); - void loadInterface(M4Surface *walkSurface, M4Surface *sceneSurface); + void loadInterface(M4Surface *&interfaceSurface, M4Surface *&depthSurface); public: MadsAnimation(MadsM4Engine *vm, MadsView *view); virtual ~MadsAnimation(); - virtual void load(const Common::String &filename, uint16 flags, M4Surface *walkSurface, M4Surface *sceneSurface); + virtual void load(const Common::String &filename, uint16 flags, M4Surface *interfaceSurface, M4Surface *sceneSurface); virtual void start(); virtual bool update(); virtual void stop(); diff --git a/engines/m4/graphics.cpp b/engines/m4/graphics.cpp index edabcd8b228..29aaa184a34 100644 --- a/engines/m4/graphics.cpp +++ b/engines/m4/graphics.cpp @@ -727,16 +727,10 @@ 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]; - bool hasPalette = palData != NULL; - if (!hasPalette) - palData = &_rgbList; - // Chunk 0, palette Common::SeekableReadStream *intStream = intFile.getItemStream(0); @@ -748,7 +742,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 @@ -757,11 +751,9 @@ void M4Surface::madsloadInterface(int index, RGBList **palData) { intStream->read(pixels, 320 * 44); delete intStream; - if (!hasPalette) { - // Translate the interface palette - _vm->_palette->addRange(_rgbList); - this->translate(_rgbList); - } + // Translate the interface palette + _vm->_palette->addRange(_rgbList); + this->translate(_rgbList); } void M4Surface::scrollX(int xAmount) { diff --git a/engines/m4/graphics.h b/engines/m4/graphics.h index 97fdfc0d6ce..8c4b9ac072e 100644 --- a/engines/m4/graphics.h +++ b/engines/m4/graphics.h @@ -122,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 = NULL); + 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; } From 7f0b0a83edfee3b139dea783293282e05898f070 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 3 Jun 2010 20:42:06 +0000 Subject: [PATCH 200/249] Fixed crashing with wave file patches, a regression from commit #49391 svn-id: r49411 --- engines/sci/resource_audio.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index 2fe6a7f3d56..b626a259890 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -168,6 +168,7 @@ void ResourceManager::readWaveAudioPatches() { 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; From 038ac90482863d60567e64c11ed138d79000fe28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbj=C3=B6rn=20Andersson?= Date: Thu, 3 Jun 2010 21:13:08 +0000 Subject: [PATCH 201/249] Renamed some variables to silence GCC warnings. svn-id: r49412 --- engines/m4/mads_scene.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp index b69c8bd116e..1f88ad771d6 100644 --- a/engines/m4/mads_scene.cpp +++ b/engines/m4/mads_scene.cpp @@ -604,18 +604,18 @@ void MadsAction::set() { /*--------------------------------------------------------------------------*/ -void MadsSceneResources::load(int sceneId, const char *resName, int v0, M4Surface *depthSurface, M4Surface *surface) { - char buffer[80]; +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 (sceneId > 0) { - sceneName = MADSResourceManager::getResourceName(RESPREFIX_RM, sceneId, ".DAT"); + if (sceneNumber > 0) { + sceneName = MADSResourceManager::getResourceName(RESPREFIX_RM, sceneNumber, ".DAT"); } else { - strcat(buffer, "*"); - strcat(buffer, resName); - sceneName = buffer; // TODO: Check whether this needs to be converted to 'HAG form' + 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); @@ -626,7 +626,7 @@ void MadsSceneResources::load(int sceneId, const char *resName, int v0, M4Surfac Common::SeekableReadStream *stream = sceneInfo.getItemStream(0); int resSceneId = stream->readUint16LE(); - assert(resSceneId == sceneId); + assert(resSceneId == sceneNumber); artFileNum = stream->readUint16LE(); dialogStyle = stream->readUint16LE(); width = stream->readUint16LE(); @@ -651,8 +651,8 @@ void MadsSceneResources::load(int sceneId, const char *resName, int v0, M4Surfac int setCount = stream->readUint16LE(); stream->readUint16LE(); for (int i = 0; i < setCount; ++i) { - char buffer[64]; - Common::String s(buffer, 64); + char buffer2[64]; + Common::String s(buffer2, 64); setNames.push_back(s); } @@ -696,7 +696,7 @@ void MadsSceneResources::load(int sceneId, const char *resName, int v0, M4Surfac _vm->_resourceManager->toss(sceneName); // Load the surface artwork - surface->loadBackground(sceneId); + surface->loadBackground(sceneNumber); // Final cleanup if (ssFlag) From 576306c323d092b590e184ececb70745633aae4e Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 3 Jun 2010 21:52:21 +0000 Subject: [PATCH 202/249] Re-enabled the cursor position limiting code svn-id: r49413 --- engines/sci/engine/kevent.cpp | 2 ++ engines/sci/event.cpp | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index 35f71efedd6..3e096074e67 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -49,6 +49,8 @@ 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 diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp index 53f4675f562..c3be22b1436 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); From 1973bd5a71fc2847b123e0f1d769220210eceba4 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 3 Jun 2010 21:57:49 +0000 Subject: [PATCH 203/249] Added channel remapping to MidiParser_SCI (currently unused) svn-id: r49414 --- engines/sci/sound/midiparser_sci.cpp | 16 ++++++++++++++-- engines/sci/sound/midiparser_sci.h | 11 +++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 2068ea9a33b..83a67509cf8 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() { @@ -120,17 +123,26 @@ 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) { + byte remappedChannel = _channelRemap[info.channel()]; + + // Remap channel. Keep the upper 4 bits (command code) and change + // the lower 4 bits (channel) + info.event = (info.event & 0xF0) | (remappedChannel & 0xF); + // 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) { diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h index f95c71ce2f6..d9ae583aff0 100644 --- a/engines/sci/sound/midiparser_sci.h +++ b/engines/sci/sound/midiparser_sci.h @@ -71,7 +71,16 @@ 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; + } + protected: + bool isChannelUsed(byte channel) { return _channelsUsed & (1 << channel); } + void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); } + void parseNextEvent(EventInfo &info); byte *midiMixChannels(); byte *midiFilterChannels(int channelMask); @@ -93,6 +102,8 @@ protected: // A 16-bit mask, containing the channels used // by the currently parsed song uint16 _channelsUsed; + + byte _channelRemap[16]; }; } // End of namespace Sci From ddf7449b00d15c5419c667f9df553053e8dc0cec Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 3 Jun 2010 22:00:50 +0000 Subject: [PATCH 204/249] Added code to get which channels are used by a sound. Also, fixed a crash when using Sierra's GM patches, a regression from commit #49391. svn-id: r49415 --- engines/sci/resource.h | 2 ++ engines/sci/resource_audio.cpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/engines/sci/resource.h b/engines/sci/resource.h index f722ca57684..6d9da3c200b 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -512,6 +512,7 @@ public: Track *getDigitalTrack(); int getChannelFilterMask(int hardwareMask, bool wantsRhythm); byte getInitialVoiceCount(byte channel); + bool isChannelUsed(byte channel) { return _usedChannels[channel]; } private: SciVersion _soundVersion; @@ -519,6 +520,7 @@ private: Track *_tracks; Resource *_innerResource; ResourceManager *_resMan; + bool _usedChannels[16]; }; } // End of namespace Sci diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index b626a259890..6dfd190d974 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -151,6 +151,7 @@ void ResourceManager::addNewGMPatch(const Common::String &gameId) { 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); } @@ -467,6 +468,9 @@ SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersi byte *dataEnd; Channel *channel, *sampleChannel; + for (int i = 0; i < 16; i++) + _usedChannels[i] = false; + switch (_soundVersion) { case SCI_VERSION_0_EARLY: case SCI_VERSION_0_LATE: @@ -556,6 +560,7 @@ SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersi 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); + _usedChannels[channel->number] = true; channel->poly = *(channel->data - 1); channel->time = channel->prev = 0; if (channel->number == 0xFE) { // Digital channel From 8dd7537a55add13179520ec751641baac47373c7 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Thu, 3 Jun 2010 22:13:23 +0000 Subject: [PATCH 205/249] A first attempt at channel remapping (currently disabled) svn-id: r49416 --- engines/sci/sound/music.cpp | 34 ++++++++++++++++++++++++++++++++++ engines/sci/sound/music.h | 11 ++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index bfa2c3b3eef..1d186647f8e 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -173,6 +173,21 @@ void SciMusic::sortPlayList() { MusicEntry ** pData = _playList.begin(); qsort(pData, _playList.size(), sizeof(MusicEntry *), &f_compare); } + +void SciMusic::findUsedChannels() { + // Reset list + for (int k = 0; k < 16; k++) + _usedChannels[k] = false; + + const MusicList::iterator end = _playList.end(); + for (MusicList::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()); @@ -220,6 +235,25 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel()); pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion); + // TODO: Fix channel remapping. This doesn't quite work... (e.g. no difference in LSL1VGA) +#if 0 + // Remap channels + findUsedChannels(); + + 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 + // Fast forward to the last position and perform associated events when loading pSnd->pMidiParser->jumpToTick(pSnd->ticker, true); _mutex.unlock(); diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index 8f08065b99a..f5eb7ce8d92 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() { + 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 From 02ed1a684ae54b1ae3124aa3064889164e33ed69 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 3 Jun 2010 23:07:53 +0000 Subject: [PATCH 206/249] - Made some methods const - Prefer const_iterator over iterator in SciMusic::findUsedChannels svn-id: r49417 --- engines/sci/sound/midiparser_sci.h | 2 +- engines/sci/sound/music.cpp | 4 ++-- engines/sci/sound/music.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h index d9ae583aff0..e33e613dd60 100644 --- a/engines/sci/sound/midiparser_sci.h +++ b/engines/sci/sound/midiparser_sci.h @@ -78,7 +78,7 @@ public: } protected: - bool isChannelUsed(byte channel) { return _channelsUsed & (1 << channel); } + bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); } void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); } void parseNextEvent(EventInfo &info); diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 1d186647f8e..e1300373e7e 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -179,8 +179,8 @@ void SciMusic::findUsedChannels() { for (int k = 0; k < 16; k++) _usedChannels[k] = false; - const MusicList::iterator end = _playList.end(); - for (MusicList::iterator i = _playList.begin(); i != end; ++i) { + 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; diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index f5eb7ce8d92..83cd59e89b5 100644 --- a/engines/sci/sound/music.h +++ b/engines/sci/sound/music.h @@ -211,7 +211,7 @@ protected: private: static void miditimerCallback(void *p); void findUsedChannels(); - int16 getNextUnusedChannel() { + int16 getNextUnusedChannel() const { for (int i = 0; i < 16; i++) { if (!_usedChannels[i]) return i; From 664c86f25d5476089194650fe3d6509c5c4d7c2f Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Thu, 3 Jun 2010 23:37:05 +0000 Subject: [PATCH 207/249] Replace two uses of ::qsort by Common::sort. svn-id: r49418 --- engines/sci/engine/kfile.cpp | 13 +++++-------- engines/sci/sound/music.cpp | 8 ++++---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index ba8714366fc..18b1e02eba3 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -245,13 +245,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 &saves) { @@ -285,7 +282,7 @@ void listSavegames(Common::Array &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) { diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index e1300373e7e..f0356be709f 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -165,13 +165,13 @@ 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() { From f1a55a9c67886209e69900159c7917dfedc1d79f Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Fri, 4 Jun 2010 10:15:13 +0000 Subject: [PATCH 208/249] SCI: Cleanup svn-id: r49423 --- engines/sci/engine/kfile.cpp | 98 ++++++++---------------------------- 1 file changed, 20 insertions(+), 78 deletions(-) diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index 18b1e02eba3..ce501bab474 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -44,6 +44,7 @@ struct SavegameDesc { int id; int date; int time; + char name[SCI_MAX_SAVENAME_LENGTH]; }; /* @@ -262,7 +263,7 @@ void listSavegames(Common::Array &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; @@ -275,6 +276,13 @@ void listSavegames(Common::Array &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; + + if (meta.savegame_name.lastChar() == '\n') + meta.savegame_name.deleteLastChar(); + + strncpy(desc.name, meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH - 1); + desc.name[SCI_MAX_SAVENAME_LENGTH - 1] = 0; + debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id); saves.push_back(desc); @@ -289,28 +297,11 @@ bool Console::cmdListSaves(int argc, const char **argv) { Common::Array 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; } @@ -446,44 +437,20 @@ 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 saves; listSavegames(saves); - savedir_nr = saves[savedir_nr].id; - - if (savedir_nr > MAX_SAVEGAME_NR - 1) { - 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); - } - - return s->r_acc; + return make_reg(0, savedir_nr < saves.size()); } 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); + reg_t *slot = s->_segMan->derefRegPtr(argv[2], 0); debug(3, "kGetSaveFiles(%s)", game_id.c_str()); @@ -491,42 +458,17 @@ reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) { listSavegames(saves); s->r_acc = NULL_REG; - 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))) { - // found a savegame file + for (uint i = 0; i < MIN(saves.size(), MAX_SAVEGAME_NR); i++) { + *slot++ = s->r_acc; // Store savegame ID + ++s->r_acc.offset; // Increase number of files found - SavegameMetadata meta; - if (!get_savegame_metadata(in, &meta)) { - // invalid - delete in; - continue; - } + s->_segMan->strcpy(nametarget, saves[i].name); - 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 - - 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()); - - // Increase name offset pointer accordingly - nametarget.offset += SCI_MAX_SAVENAME_LENGTH; - } - delete in; - } + // Increase name offset pointer accordingly + nametarget.offset += SCI_MAX_SAVENAME_LENGTH; } - //free(gfname); s->_segMan->strcpy(nametarget, ""); // Terminate list return s->r_acc; From a8acf7468c8f795355bb85962052eb8c02e2a4de Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Fri, 4 Jun 2010 10:36:49 +0000 Subject: [PATCH 209/249] SCI: Add savegame version check in CheckSaveGame svn-id: r49424 --- engines/sci/engine/kfile.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index ce501bab474..4be92015abb 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -44,6 +44,7 @@ struct SavegameDesc { int id; int date; int time; + int version; char name[SCI_MAX_SAVENAME_LENGTH]; }; @@ -276,6 +277,7 @@ void listSavegames(Common::Array &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(); @@ -444,7 +446,17 @@ reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) { Common::Array saves; listSavegames(saves); - return make_reg(0, savedir_nr < saves.size()); + // Check for savegame slot being out of range + if (savedir_nr >= saves.size()) + return NULL_REG; + + // Check for compatible savegame version + int ver = saves[savedir_nr].version; + if (ver < MINIMUM_SAVEGAME_VERSION || ver > CURRENT_SAVEGAME_VERSION) + return NULL_REG; + + // Otherwise we assume the savegame is OK + return make_reg(0, 1); } reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) { From 997fdac4271aac6a345bbdd0782d55d48ed0b400 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Fri, 4 Jun 2010 10:51:27 +0000 Subject: [PATCH 210/249] SCI: Replace strncpy with Common::strlcpy svn-id: r49425 --- engines/sci/engine/kfile.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index 4be92015abb..c48fb4035f9 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -282,8 +282,7 @@ void listSavegames(Common::Array &saves) { if (meta.savegame_name.lastChar() == '\n') meta.savegame_name.deleteLastChar(); - strncpy(desc.name, meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH - 1); - desc.name[SCI_MAX_SAVENAME_LENGTH - 1] = 0; + 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); From 86462c66a04fd208716f072d4ba0028a04bf9ad8 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 4 Jun 2010 11:28:30 +0000 Subject: [PATCH 211/249] Added code and support routines for destroying animations correctly, which also necessitated changing the sprite list code svn-id: r49426 --- engines/m4/animation.cpp | 83 +++++++++++++++++++++++++-------------- engines/m4/animation.h | 12 +++--- engines/m4/console.cpp | 3 +- engines/m4/mads_logic.cpp | 4 +- engines/m4/mads_logic.h | 2 + engines/m4/mads_scene.cpp | 31 ++++++++++++--- engines/m4/mads_scene.h | 4 +- engines/m4/mads_views.cpp | 30 +++++++++++++- engines/m4/mads_views.h | 16 ++++---- 9 files changed, 128 insertions(+), 57 deletions(-) diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index 58d829c4a23..43823c5ff19 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -33,19 +33,31 @@ namespace M4 { // TODO: this code needs cleanup MadsAnimation::MadsAnimation(MadsM4Engine *vm, MadsView *view): Animation(vm), _view(view) { - _playing = false; _font = NULL; - _unk1 = 0; + _freeFlag = false; _skipLoad = false; _unkIndex = -1; _messageCtr= 0; } 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 MadsAnimation::load(const Common::String &filename, uint16 flags, M4Surface *interfaceSurface, M4Surface *sceneSurface) { +/** + * 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]; @@ -74,7 +86,7 @@ void MadsAnimation::load(const Common::String &filename, uint16 flags, M4Surface animStream->skip(10); animStream->read(buffer, 13); - _infoFilename = Common::String(buffer, 13); + _interfaceFile = Common::String(buffer, 13); for (int i = 0; i < 10; ++i) { animStream->read(buffer, 13); @@ -160,7 +172,8 @@ void MadsAnimation::load(const Common::String &filename, uint16 flags, M4Surface for (int i = 0; i < miscEntriesCount; ++i) { AnimMiscEntry rec; - rec.soundNum = animStream->readUint16LE(); + rec.soundNum = animStream->readByte(); + animStream->skip(1); rec.numTicks = animStream->readUint16LE(); rec.posAdjust.x = animStream->readUint16LE(); rec.posAdjust.y = animStream->readUint16LE(); @@ -204,20 +217,37 @@ void MadsAnimation::load(const Common::String &filename, uint16 flags, M4Surface } -void MadsAnimation::start() { +/** + * Loads an animation file for display + */ +void MadsAnimation::load(const Common::String &filename, int abortTimers) { + initialise(filename, 0, NULL, NULL); + _messageCtr = 0; + _skipLoad = true; + + if (_field12) { + _unkIndex = -1; + int listIndex = _spriteListIndexes[_spriteListIndex]; + SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(listIndex); +warning("%d", spriteSet.getCount()); + } + + // Initialise miscellaneous fields _currentFrame = 0; _oldFrameEntry = 0; - //for (int i = 0; i < _seriesCount; i++) { - //_spriteSeries[i] = new SpriteSeries((char*)_spriteSeriesNames[i].c_str()); - //} - _playing = true; - update(); + _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 MadsAnimation::update() { - if (!_playing) - return true; - +void MadsAnimation::update() { if (_field12) { int spriteListIndex = _spriteListIndexes[_spriteListIndex]; int newIndex = -1; @@ -235,7 +265,8 @@ bool MadsAnimation::update() { // If it's not time for the next frame, then exit if (_madsVm->_currentTimer < _nextFrameTimer) - return false; + return; +return;//*** TODO: This routine still needs to be properly tested // Loop checks for any prior animation sprite slots to be expired for (int slotIndex = 0; slotIndex < _view->_spriteSlots.startIndex; ++slotIndex) { @@ -253,8 +284,8 @@ bool MadsAnimation::update() { _currentFrame = 0; _oldFrameEntry = 0; } else { - _unk1 = true; - return true; + _freeFlag = true; + return; } } @@ -368,8 +399,6 @@ bool MadsAnimation::update() { _currentFrame++; if (_currentFrame >= (int)_miscEntries.size()) { // Animation is complete - stop(); - if (_abortTimers != 0) { _view->_abortTimers = _abortTimers; _view->_abortTimersMode = _abortMode; @@ -384,18 +413,12 @@ bool MadsAnimation::update() { int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1); _nextFrameTimer = _madsVm->_currentTimer + _miscEntries[frameNum].numTicks; - - return _currentFrame >= (int)_miscEntries.size(); -} - -void MadsAnimation::stop() { - _playing = false; } void MadsAnimation::setCurrentFrame(int frameNumber) { _currentFrame = frameNumber; _oldFrameEntry = 0; - _unk1 = 0; + _freeFlag = false; } void MadsAnimation::load1(int frameNumber) { @@ -427,14 +450,14 @@ bool MadsAnimation::proc1(SpriteAsset &spriteSet, const Common::Point &pt, int f void MadsAnimation::loadInterface(M4Surface *&interfaceSurface, M4Surface *&depthSurface) { if (_animMode <= 2) { MadsSceneResources sceneResources; - sceneResources.load(_roomNumber, _infoFilename.c_str(), 0, depthSurface, interfaceSurface); + sceneResources.load(_roomNumber, _interfaceFile.c_str(), 0, depthSurface, interfaceSurface); // Rex only supports a single dialog draw style - assert(sceneResources.dialogStyle == 2); + assert(sceneResources.drawStyle == 2); } else if (_animMode == 4) { // Load a scene interface - interfaceSurface->madsLoadInterface(_infoFilename); + interfaceSurface->madsLoadInterface(_interfaceFile); } else { // This mode allocates two large surfaces for the animation // TODO: Are these ever properly freed? diff --git a/engines/m4/animation.h b/engines/m4/animation.h index 838e4b6175c..59cb52cd87a 100644 --- a/engines/m4/animation.h +++ b/engines/m4/animation.h @@ -67,7 +67,6 @@ enum MadsAnimationFlags {ANIM_CUSTOM_FONT = 0x20}; class MadsAnimation: public Animation { private: - bool _playing; MadsView *_view; int _spriteListCount; @@ -83,7 +82,7 @@ private: int _spriteListIndex; int _scrollX; int _scrollY; - Common::String _infoFilename; + Common::String _interfaceFile; Common::String _spriteSetNames[10]; Common::String _lbmFilename; Common::String _spritesFilename; @@ -92,7 +91,7 @@ private: int _currentFrame, _oldFrameEntry; bool _resetFlag; - int _unk1; + bool _freeFlag; bool _skipLoad; int _unkIndex; Common::Point _unkList[2]; @@ -109,10 +108,9 @@ public: MadsAnimation(MadsM4Engine *vm, MadsView *view); virtual ~MadsAnimation(); - virtual void load(const Common::String &filename, uint16 flags, M4Surface *interfaceSurface, M4Surface *sceneSurface); - virtual void start(); - virtual bool update(); - virtual void stop(); + 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); }; diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp index ccb1c8c1825..4e14afdfaf6 100644 --- a/engines/m4/console.cpp +++ b/engines/m4/console.cpp @@ -377,8 +377,7 @@ bool MadsConsole::cmdPlayAnimation(int argc, const char **argv) { if (argc == 3 && atoi(argv[2]) == 1) _madsVm->_palette->deleteAllRanges(); - _madsVm->scene()->_sceneAnimation->load(resourceName, 0, NULL, NULL); - _madsVm->scene()->_sceneAnimation->start(); + _madsVm->scene()->_sceneAnimation->load(resourceName, 0); view->restore(0, 0, view->width(), view->height()); return false; diff --git a/engines/m4/mads_logic.cpp b/engines/m4/mads_logic.cpp index 00ed1463996..9cb053a876b 100644 --- a/engines/m4/mads_logic.cpp +++ b/engines/m4/mads_logic.cpp @@ -146,6 +146,7 @@ void MadsSceneLogic::lowRoomsEntrySound() { } } + /*--------------------------------------------------------------------------*/ /** @@ -233,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; diff --git a/engines/m4/mads_logic.h b/engines/m4/mads_logic.h index 774ed016a64..8c3f41d08bf 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 { diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp index 1f88ad771d6..69de12e4f6d 100644 --- a/engines/m4/mads_scene.cpp +++ b/engines/m4/mads_scene.cpp @@ -37,6 +37,7 @@ #include "m4/mads_views.h" #include "m4/compression.h" #include "m4/staticres.h" +#include "m4/animation.h" namespace M4 { @@ -49,6 +50,7 @@ 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; @@ -58,6 +60,8 @@ MadsScene::MadsScene(MadsEngine *vm): _sceneResources(), Scene(vm, &_sceneResour } MadsScene::~MadsScene() { + delete _activeAnimation; + _activeAnimation = NULL; leaveScene(); _vm->_viewManager->deleteView(_interfaceSurface); } @@ -83,7 +87,7 @@ void MadsScene::loadScene2(const char *aaName) { if (_madsVm->globals()->_config.textWindowStill) flags |= 0x200; - _sceneAnimation->load(aaName, flags, _interfaceSurface, NULL); + _sceneAnimation->initialise(aaName, flags, _interfaceSurface, NULL); } /** @@ -166,6 +170,11 @@ void MadsScene::leaveScene() { delete _sceneResources.props; delete _walkSurface; + if (_activeAnimation) { + delete _activeAnimation; + _activeAnimation = NULL; + } + Scene::leaveScene(); } @@ -286,14 +295,15 @@ void MadsScene::update() { _vm->_font->setFont(FONT_MAIN_MADS); _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(); + _kernelMessages.update(); } @@ -427,6 +437,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() { @@ -628,7 +647,7 @@ void MadsSceneResources::load(int sceneNumber, const char *resName, int v0, M4Su int resSceneId = stream->readUint16LE(); assert(resSceneId == sceneNumber); artFileNum = stream->readUint16LE(); - dialogStyle = stream->readUint16LE(); + drawStyle = stream->readUint16LE(); width = stream->readUint16LE(); height = stream->readUint16LE(); assert((width == 320) && (height == 156)); @@ -664,7 +683,7 @@ void MadsSceneResources::load(int sceneNumber, const char *resName, int v0, M4Su ssFlag = true; } int walkSize = gfxSize; - if (dialogStyle == 2) { + if (drawStyle == 2) { width >>= 2; walkSize = width * height; } diff --git a/engines/m4/mads_scene.h b/engines/m4/mads_scene.h index e3e4c3c084c..0269de75c8d 100644 --- a/engines/m4/mads_scene.h +++ b/engines/m4/mads_scene.h @@ -39,7 +39,7 @@ class MadsSceneResources: public SceneResources { public: int sceneId; int artFileNum; - int dialogStyle; + int drawStyle; int width; int height; Common::Array objects; @@ -93,6 +93,7 @@ private: MadsEngine *_vm; MadsSceneResources _sceneResources; MadsAction _action; + Animation *_activeAnimation; MadsSceneLogic _sceneLogic; SpriteAsset *_playerSprites; @@ -127,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; } diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp index 79ca2c51b7f..c656db83f1f 100644 --- a/engines/m4/mads_views.cpp +++ b/engines/m4/mads_views.cpp @@ -62,8 +62,15 @@ 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 @@ -86,12 +93,22 @@ int MadsSpriteSlots::addSprites(const char *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 */ @@ -173,7 +190,7 @@ 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 @@ -1134,6 +1151,15 @@ void MadsSequenceList::setAnimRange(int seqIndex, 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) { diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h index 31b8cd891f4..98944e6468e 100644 --- a/engines/m4/mads_views.h +++ b/engines/m4/mads_views.h @@ -72,17 +72,16 @@ enum SpriteIdSpecial { SPRITE_FOUR = 4 }; -typedef Common::Array > SpriteList; - class MadsSpriteSlots { private: MadsView &_owner; Common::Array _entries; - SpriteList _sprites; + Common::Array _sprites; public: int startIndex; MadsSpriteSlots(MadsView &owner); + ~MadsSpriteSlots(); MadsSpriteSlot &operator[](int idx) { assert(idx < SPRITE_SLOTS_SIZE); @@ -90,11 +89,12 @@ 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 seqIndex); @@ -359,6 +359,7 @@ public: void tick(); void delay(uint32 v1, uint32 v2); void setAnimRange(int seqIndex, int startVal, int endVal); + void scan(); }; class Animation { @@ -367,10 +368,9 @@ protected: public: Animation(MadsM4Engine *vm); virtual ~Animation(); - virtual void load(const Common::String &filename, uint16 flags, M4Surface *walkSurface, M4Surface *sceneSurface) = 0; - virtual void start() = 0; - virtual bool update() = 0; - virtual void stop() = 0; + 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; }; From 3d98f679e72b5dcf16d4c85a286bdaf5a35c95a6 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 4 Jun 2010 12:51:06 +0000 Subject: [PATCH 212/249] Bugfix for the loading of the animation frame list svn-id: r49427 --- engines/m4/animation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index 43823c5ff19..55566aad7e0 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -154,11 +154,12 @@ void MadsAnimation::initialise(const Common::String &filename, uint16 flags, M4S 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->readUint16LE(); - rec.spriteSlot.scale = animStream->readUint16LE(); + rec.spriteSlot.depth = animStream->readByte(); + rec.spriteSlot.scale = animStream->readByte(); _frameEntries.push_back(rec); } @@ -266,7 +267,6 @@ void MadsAnimation::update() { // If it's not time for the next frame, then exit if (_madsVm->_currentTimer < _nextFrameTimer) return; -return;//*** TODO: This routine still needs to be properly tested // Loop checks for any prior animation sprite slots to be expired for (int slotIndex = 0; slotIndex < _view->_spriteSlots.startIndex; ++slotIndex) { From 9906030312842ae3f3537824c36697c2f5eb60bf Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Fri, 4 Jun 2010 13:48:09 +0000 Subject: [PATCH 213/249] Ensure that zones/animations always get the same index number. When a zone/animation is skipped by the parser because already loaded, the index is now increased. This does not affect NS, since indexes are only used for scene sorting there, but is relevant for BRA, where indexes need to be coherent across location changes. Patch #3004008 by fuzzie. svn-id: r49428 --- engines/parallaction/parser_ns.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp index be72cf73a16..ff24a06ceb5 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; } From fdc9bbcbf5cee1b5e0cca6838ff30b0133b882fa Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Fri, 4 Jun 2010 14:53:12 +0000 Subject: [PATCH 214/249] Simplified the channel monitoring code inside the SoundResource class svn-id: r49429 --- engines/sci/resource.h | 6 ++++-- engines/sci/resource_audio.cpp | 5 ++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 6d9da3c200b..bc08154fedc 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -512,7 +512,7 @@ public: Track *getDigitalTrack(); int getChannelFilterMask(int hardwareMask, bool wantsRhythm); byte getInitialVoiceCount(byte channel); - bool isChannelUsed(byte channel) { return _usedChannels[channel]; } + bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); } private: SciVersion _soundVersion; @@ -520,7 +520,9 @@ private: Track *_tracks; Resource *_innerResource; ResourceManager *_resMan; - bool _usedChannels[16]; + 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 index 6dfd190d974..67bac974fc1 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -468,8 +468,7 @@ SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersi byte *dataEnd; Channel *channel, *sampleChannel; - for (int i = 0; i < 16; i++) - _usedChannels[i] = false; + _channelsUsed = 0; switch (_soundVersion) { case SCI_VERSION_0_EARLY: @@ -560,7 +559,7 @@ SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersi 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); - _usedChannels[channel->number] = true; + setChannelUsed(channel->number); channel->poly = *(channel->data - 1); channel->time = channel->prev = 0; if (channel->number == 0xFE) { // Digital channel From 722c4f1b8dd9a25e94e48ea1368e786250de7a5c Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Fri, 4 Jun 2010 15:01:26 +0000 Subject: [PATCH 215/249] Some more work on channel remapping: Moved the remapping code to the music loading code (still disabled) svn-id: r49430 --- engines/sci/sound/midiparser_sci.cpp | 22 ++++++++++++---------- engines/sci/sound/midiparser_sci.h | 2 ++ engines/sci/sound/music.cpp | 10 ++++++---- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 83a67509cf8..3ee8a3a83db 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -88,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 @@ -135,12 +134,6 @@ void MidiParser_SCI::unloadMusic() { } void MidiParser_SCI::parseNextEvent(EventInfo &info) { - byte remappedChannel = _channelRemap[info.channel()]; - - // Remap channel. Keep the upper 4 bits (command code) and change - // the lower 4 bits (channel) - info.event = (info.event & 0xF0) | (remappedChannel & 0xF); - // Monitor which channels are used by this song setChannelUsed(info.channel()); @@ -334,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; @@ -401,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 e33e613dd60..9d4b5a39da6 100644 --- a/engines/sci/sound/midiparser_sci.h +++ b/engines/sci/sound/midiparser_sci.h @@ -77,6 +77,8 @@ public: _channelRemap[channel] = newChannel; } + void clearUsedChannels() { _channelsUsed = 0; } + protected: bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); } void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); } diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index f0356be709f..fa5716e7cc6 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -231,15 +231,13 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { pSnd->pauseCounter = 0; - // Find out what channels to filter for SCI0 - channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel()); - pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion); - // 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(); @@ -254,6 +252,10 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) { } #endif + // Find out what channels to filter for SCI0 + channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel()); + pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion); + // Fast forward to the last position and perform associated events when loading pSnd->pMidiParser->jumpToTick(pSnd->ticker, true); _mutex.unlock(); From 8b102ab7afae80d57bbbd03d2cd4a9bea09c9115 Mon Sep 17 00:00:00 2001 From: David Turner Date: Fri, 4 Jun 2010 20:06:59 +0000 Subject: [PATCH 216/249] SCI: Fix for Valgrind Warning in Palette. svn-id: r49433 --- engines/sci/graphics/palette.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index ab968566741..3c4cf7e9644 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -56,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(); @@ -64,7 +65,6 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen, bool autoSetP else kernelSetFromResource(999, true); } - _sysPaletteChanged = false; } GfxPalette::~GfxPalette() { From 3a5fe4ca002a85f7c4549c8d36203553553c53f9 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 4 Jun 2010 22:53:26 +0000 Subject: [PATCH 217/249] Bugfix for wrong parameter order in scene resources load method call. Also added fragment to destroy an active animation when it's finished animating svn-id: r49434 --- engines/m4/animation.h | 2 ++ engines/m4/mads_scene.cpp | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/engines/m4/animation.h b/engines/m4/animation.h index 59cb52cd87a..883d3f2de6f 100644 --- a/engines/m4/animation.h +++ b/engines/m4/animation.h @@ -112,6 +112,8 @@ public: virtual void load(const Common::String &filename, int abortTimers); virtual void update(); virtual void setCurrentFrame(int frameNumber); + + bool freeFlag() const { return _freeFlag; } }; } // End of namespace M4 diff --git a/engines/m4/mads_scene.cpp b/engines/m4/mads_scene.cpp index 69de12e4f6d..a65224c7224 100644 --- a/engines/m4/mads_scene.cpp +++ b/engines/m4/mads_scene.cpp @@ -77,7 +77,7 @@ void MadsScene::loadScene2(const char *aaName) { _kernelMessages.clear(); // Load up the properties for the scene - _sceneResources.load(_currentScene, 0/*word_83546*/, NULL, _walkSurface, _backgroundSurface); + _sceneResources.load(_currentScene, NULL, 0/*word_83546*/, _walkSurface, _backgroundSurface); // Load scene walk paths loadSceneCodes(_currentScene); @@ -301,8 +301,13 @@ void MadsScene::updateState() { _sceneLogic.sceneStep(); _sequenceList.tick(); - if ((_activeAnimation) && !_abortTimers) + if ((_activeAnimation) && !_abortTimers) { _activeAnimation->update(); + if (((MadsAnimation *) _activeAnimation)->freeFlag()) { + delete _activeAnimation; + _activeAnimation = NULL; + } + } _kernelMessages.update(); } From 5686c251f09fa25432d5db8195ac1df2fcda88fb Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 5 Jun 2010 01:55:17 +0000 Subject: [PATCH 218/249] Added missing animation initialisation code svn-id: r49436 --- engines/m4/animation.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index 55566aad7e0..bf49c649fb1 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -198,6 +198,10 @@ void MadsAnimation::initialise(const Common::String &filename, uint16 flags, M4S // 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()); } @@ -211,11 +215,17 @@ void MadsAnimation::initialise(const Common::String &filename, uint16 flags, M4S _spriteListIndexes[_spriteListIndex] = _view->_spriteSlots.addSprites(resName.c_str()); } - // TODO: Unknown section about handling palette entries - I think it's adjusting sprite sets - // to the palette of the game screen + // TODO: Unknown section about handling sprite set list combined with messages size - // Process the sprite list indexes to remap them to the actual sprite list indexes - + // 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]; + } } /** @@ -270,8 +280,7 @@ void MadsAnimation::update() { // 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) && - (_view->_spriteSlots[slotIndex].seqIndex <= 0xFD)) { + if (_view->_spriteSlots[slotIndex].seqIndex >= 0x80) { // Flag the frame as animation sprite slot _view->_spriteSlots[slotIndex].spriteType = EXPIRED_SPRITE; } @@ -334,8 +343,10 @@ void MadsAnimation::update() { if ((spriteSlotIndex == 0) && (index < spriteSlotsMax)) { int seqIndex = _frameEntries[_oldFrameEntry].seqIndex - _view->_spriteSlots[index].seqIndex; if (seqIndex == 0x80) { - if (_view->_spriteSlots[index] == _frameEntries[_oldFrameEntry].spriteSlot) + if (_view->_spriteSlots[index] == _frameEntries[_oldFrameEntry].spriteSlot) { _view->_spriteSlots[index].spriteType = SPRITE_ZERO; + spriteSlotIndex = -1; + } } ++index; continue; From b9065aa2d23d87c5da887ebe1f685230a4693827 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 5 Jun 2010 04:18:23 +0000 Subject: [PATCH 219/249] Various bugfixes to the animation code - first Rex animation now plays, albeit in the wrong place svn-id: r49437 --- engines/m4/animation.cpp | 9 ++++----- engines/m4/assets.cpp | 11 ++++++----- engines/m4/assets.h | 5 +++-- engines/m4/mads_views.cpp | 12 ++++++------ engines/m4/mads_views.h | 3 +-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index bf49c649fb1..a4e4ccbc0e6 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -354,14 +354,13 @@ void MadsAnimation::update() { if (spriteSlotIndex == 0) { int slotIndex = _view->_spriteSlots.getIndex(); - _view->_spriteSlots[slotIndex].copy(_frameEntries[_oldFrameEntry].spriteSlot); - _view->_spriteSlots[slotIndex].seqIndex += 0x80; + 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); - - _view->_spriteSlots[slotIndex].spriteType = (spriteSet.getAssetType() == 0) ? - SPRITE_FOUR : SPRITE_ZERO; + slot.spriteType = spriteSet.isBackground() ? BACKGROUND_SPRITE : FOREGROUND_SPRITE; } break; } diff --git a/engines/m4/assets.cpp b/engines/m4/assets.cpp index 91c371dec59..1f3cf278ae0 100644 --- a/engines/m4/assets.cpp +++ b/engines/m4/assets.cpp @@ -210,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 816a8dcff0c..e5beffbcae8 100644 --- a/engines/m4/assets.h +++ b/engines/m4/assets.h @@ -114,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; } @@ -137,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/mads_views.cpp b/engines/m4/mads_views.cpp index c656db83f1f..bfd57c4add3 100644 --- a/engines/m4/mads_views.cpp +++ b/engines/m4/mads_views.cpp @@ -156,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); } } } @@ -954,9 +954,9 @@ void MadsSequenceList::remove(int seqIndex) { void MadsSequenceList::setSpriteSlot(int seqIndex, MadsSpriteSlot &spriteSlot) { MadsSequenceEntry &timerEntry = _entries[seqIndex]; - SpriteAsset &sprite = _owner._spriteSlots.getSprite(timerEntry.spriteListIndex); + SpriteAsset &spriteSet = _owner._spriteSlots.getSprite(timerEntry.spriteListIndex); - spriteSlot.spriteType = sprite.getAssetType() == 1 ? BACKGROUND_SPRITE : FOREGROUND_SPRITE; + 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; @@ -967,8 +967,8 @@ void MadsSequenceList::setSpriteSlot(int seqIndex, MadsSpriteSlot &spriteSlot) { 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; } } diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h index 98944e6468e..f44d640c8b8 100644 --- a/engines/m4/mads_views.h +++ b/engines/m4/mads_views.h @@ -68,8 +68,7 @@ public: #define SPRITE_SLOTS_SIZE 50 enum SpriteIdSpecial { - BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, EXPIRED_SPRITE = -1, SPRITE_ZERO = 0, FOREGROUND_SPRITE = 1, - SPRITE_FOUR = 4 + BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, EXPIRED_SPRITE = -1, SPRITE_ZERO = 0, FOREGROUND_SPRITE = 1 }; class MadsSpriteSlots { From e9f35fbf4ce36b2a7cbdada429c5e7a2d49cbab8 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 5 Jun 2010 14:09:52 +0000 Subject: [PATCH 220/249] Rewrote the remaining parts of the ResourceManager class to work with file streams, thus removing the SCI_detection hack in the fallback detector svn-id: r49438 --- engines/sci/detection.cpp | 23 +------- engines/sci/resource.cpp | 105 +++++++++++++++++++++------------ engines/sci/resource_audio.cpp | 26 +++++--- 3 files changed, 88 insertions(+), 66 deletions(-) diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index aba2b0b74ec..adec23c95e2 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -373,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; } @@ -429,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; } @@ -437,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; } @@ -449,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; } @@ -468,7 +452,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl // If we don't have a game id, the game is not SCI if (sierraGameId.empty()) { - SearchMan.remove("SCI_detection"); delete resMan; return 0; } @@ -522,8 +505,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl if (s_fallbackDesc.flags & ADGF_DEMO) s_fallbackDesc.extra = "demo"; - SearchMan.remove("SCI_detection"); - return (const ADGameDescription *)&s_fallbackDesc; } diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 449effd7372..b17117a1cdc 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -371,6 +371,8 @@ void ResourceManager::loadResource(Resource *res) { case kSourceWave: fileStream->seek(res->_fileOffset, SEEK_SET); loadFromWaveFile(res, fileStream); + if (res->_source->resourceFile) + delete fileStream; return; case kSourceAudioVolume: @@ -408,6 +410,8 @@ void ResourceManager::loadResource(Resource *res) { case kResourceTypeAudio36: // Directly read the stream, compressed audio wont have resource type id and header size for SCI1.1 loadFromAudioVolumeSCI1(res, fileStream); + if (res->_source->resourceFile) + delete fileStream; return; default: break; @@ -420,11 +424,18 @@ void ResourceManager::loadResource(Resource *res) { loadFromAudioVolumeSCI1(res, fileStream); else loadFromAudioVolumeSCI11(res, fileStream); + + if (res->_source->resourceFile) + delete fileStream; return; default: 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]); @@ -437,19 +448,6 @@ 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; @@ -1205,25 +1203,34 @@ void ResourceManager::readResourcePatches(ResourceSource *source) { } 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; } @@ -1252,15 +1259,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); @@ -1271,8 +1289,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; @@ -1283,18 +1301,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 @@ -1302,7 +1320,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; } @@ -1322,6 +1341,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) { } } } + + delete fileStream; return 0; } @@ -1574,7 +1595,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) @@ -1583,16 +1604,26 @@ ResourceCompression ResourceManager::getViewCompression() { if (res->_source->source_type != kSourceVolume) continue; - file = getVolumeFile(res->_source->location_name.c_str()); - if (!file) + if (res->_source->resourceFile) + fileStream = res->_source->resourceFile->createReadStream(); + else + fileStream = getVolumeFile(res->_source->location_name.c_str()); + + 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; diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index 67bac974fc1..ebc549c7722 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -33,13 +33,20 @@ namespace Sci { void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) { - Common::File *file = getVolumeFile(source->location_name.c_str()); - if (!file) { + Common::SeekableReadStream *fileStream; + + if (source->resourceFile) + fileStream = source->resourceFile->createReadStream(); + else + fileStream = getVolumeFile(source->location_name.c_str()); + + if (!fileStream) { warning("Failed to open %s", source->location_name.c_str()); return; } - file->seek(0, SEEK_SET); - uint32 compressionType = file->readUint32BE(); + + fileStream->seek(0, SEEK_SET); + uint32 compressionType = fileStream->readUint32BE(); switch (compressionType) { case MKID_BE('MP3 '): case MKID_BE('OGG '): @@ -47,19 +54,22 @@ void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) { // Detected a compressed audio volume source->audioCompressionType = compressionType; // Now read the whole offset mapping table for later usage - int32 recordCount = file->readUint32LE(); + 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++ = file->readUint32LE(); - *offsetMapping++ = file->readUint32LE(); + *offsetMapping++ = fileStream->readUint32LE(); + *offsetMapping++ = fileStream->readUint32LE(); } // Put ending zero *offsetMapping++ = 0; - *offsetMapping++ = file->size(); + *offsetMapping++ = fileStream->size(); } + + if (source->resourceFile) + delete fileStream; } bool ResourceManager::loadFromWaveFile(Resource *res, Common::SeekableReadStream *file) { From c00d645506d60aea320a72cea2c5b9cb5368891c Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 5 Jun 2010 18:15:41 +0000 Subject: [PATCH 221/249] Fixed the cursor limiting code in GK1 svn-id: r49440 --- engines/sci/engine/kgraphics.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 17d2cd630ed..abe55455de2 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -148,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); From 6a796c2bb0b2a6d46546a97c24320bdceae2c69d Mon Sep 17 00:00:00 2001 From: John Willis Date: Sat, 5 Jun 2010 18:24:28 +0000 Subject: [PATCH 222/249] GP2X Wiz: Update handy shell scripts. svn-id: r49441 --- backends/platform/gp2xwiz/build/build.sh | 4 ++-- backends/platform/gp2xwiz/build/bundle.sh | 6 ++++-- backends/platform/gp2xwiz/build/config.sh | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/backends/platform/gp2xwiz/build/build.sh b/backends/platform/gp2xwiz/build/build.sh index 1bdc020f176..876c3e378a7 100755 --- a/backends/platform/gp2xwiz/build/build.sh +++ b/backends/platform/gp2xwiz/build/build.sh @@ -13,7 +13,7 @@ export ASFLAGS=-mfloat-abi=soft cd ../../../.. -echo Building ScummVM for GP2X. +echo Building ScummVM for GP2X Wiz. make -echo Build for GP2X - SDL - complete - Please check build logs. +echo Build for GP2X Wiz - complete - Please check build logs. diff --git a/backends/platform/gp2xwiz/build/bundle.sh b/backends/platform/gp2xwiz/build/bundle.sh index 492ba9e1c67..065bd7a6857 100755 --- a/backends/platform/gp2xwiz/build/bundle.sh +++ b/backends/platform/gp2xwiz/build/bundle.sh @@ -35,10 +35,12 @@ loc=`dirname "$f"` cp $loc/../lib/libz.so.1.2.3 ./scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/lib/libz.so.1 cp $loc/../lib/libvorbisidec.so.1.0.2 ./scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/lib/libvorbisidec.so.1 - -echo Making Stripped exe. +echo Making Stripped Binary. arm-open2x-linux-strip ./scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/scummvm.wiz +echo Making Stripped Plugins. +arm-open2x-linux-strip ./scummvm-wiz-`date '+%Y-%m-%d'`/scummvm/plugins/* + echo Building ZIP bundle. if [ -f /usr/bin/zip ] then diff --git a/backends/platform/gp2xwiz/build/config.sh b/backends/platform/gp2xwiz/build/config.sh index 27c1fbf0bf2..54c4795298a 100755 --- a/backends/platform/gp2xwiz/build/config.sh +++ b/backends/platform/gp2xwiz/build/config.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh echo Quick script to make running configure all the time less painful echo and let all the build work be done from the backend/build folder. From 7b56f39985a62852478ccb8ad01a85e9f028097c Mon Sep 17 00:00:00 2001 From: John Willis Date: Sat, 5 Jun 2010 18:26:53 +0000 Subject: [PATCH 223/249] GP2X Wiz: Add missing "#include "graphics/scaler/aspect.h"". svn-id: r49442 --- backends/platform/gp2xwiz/build/clean.sh | 2 +- backends/platform/gp2xwiz/gp2xwiz-events.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/platform/gp2xwiz/build/clean.sh b/backends/platform/gp2xwiz/build/clean.sh index 2862887bb36..5ec1b9e62c4 100755 --- a/backends/platform/gp2xwiz/build/clean.sh +++ b/backends/platform/gp2xwiz/build/clean.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh echo Quick script to make building all the time less painful. diff --git a/backends/platform/gp2xwiz/gp2xwiz-events.cpp b/backends/platform/gp2xwiz/gp2xwiz-events.cpp index 2774efce1b1..a69aa42967b 100644 --- a/backends/platform/gp2xwiz/gp2xwiz-events.cpp +++ b/backends/platform/gp2xwiz/gp2xwiz-events.cpp @@ -30,6 +30,7 @@ #include "backends/platform/gp2xwiz/gp2xwiz-sdl.h" #include "backends/platform/gp2xwiz/gp2xwiz-hw.h" +#include "graphics/scaler/aspect.h" #include "common/util.h" #include "common/events.h" From abcd8e093a52745a5925993c74abfe901234df3a Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sat, 5 Jun 2010 19:55:03 +0000 Subject: [PATCH 224/249] Replaced a leftover Common::File::exists() call in the fallback detector svn-id: r49443 --- engines/sci/detection.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index adec23c95e2..1ccfc6bf021 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -490,7 +490,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl } } - delete resMan; // Fill in extras field if (!strcmp(s_fallbackDesc.gameid, "lsl1sci") || @@ -498,13 +497,15 @@ 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"; + delete resMan; + return (const ADGameDescription *)&s_fallbackDesc; } From 193d7df5940ada9c2ec7e3a233c2b26aa3b25e84 Mon Sep 17 00:00:00 2001 From: David Turner Date: Sun, 6 Jun 2010 00:27:56 +0000 Subject: [PATCH 225/249] Correction for SCI valgrind uninit memory error in MIDI sound which occurs during LSL6 intro. This may be "hiding" a bug in the use of sound/midiparser.cpp in SCI i.e. incorrect use of parseNextEvent(), so this should be reviewed, but this patch initialises _next_event at object construction, which corrects this, should not break anything else and is good practice. svn-id: r49445 --- sound/midiparser.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/midiparser.cpp b/sound/midiparser.cpp index 99319461e9c..8ae2bad71ad 100644 --- a/sound/midiparser.cpp +++ b/sound/midiparser.cpp @@ -47,6 +47,10 @@ _num_tracks(0), _active_track(255), _abort_parse(0) { memset(_active_notes, 0, sizeof(_active_notes)); + _next_event.start = NULL; + _next_event.delta = 0; + _next_event.event = 0; + _next_event.length = 0; } void MidiParser::property(int prop, int value) { From c253a57e471be34567c2a28f8ccb4f6e084d7e20 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 6 Jun 2010 01:12:41 +0000 Subject: [PATCH 226/249] Bugfix for #2974817 - Mad Drongo Animation Malfunction svn-id: r49447 --- engines/tinsel/saveload.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp index b90ace4613b..b010ad1fcb4 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); From 3efec5720de2c46355c323763dee96b719ed5aa1 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 6 Jun 2010 06:46:29 +0000 Subject: [PATCH 227/249] Bugfixes for correct positioning of opening animation svn-id: r49448 --- engines/m4/animation.cpp | 5 +++-- engines/m4/mads_views.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index a4e4ccbc0e6..b372222bd0a 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -34,6 +34,7 @@ namespace M4 { MadsAnimation::MadsAnimation(MadsM4Engine *vm, MadsView *view): Animation(vm), _view(view) { _font = NULL; + _resetFlag = false; _freeFlag = false; _skipLoad = false; _unkIndex = -1; @@ -159,7 +160,7 @@ void MadsAnimation::initialise(const Common::String &filename, uint16 flags, M4S rec.spriteSlot.xp = animStream->readUint16LE(); rec.spriteSlot.yp = animStream->readUint16LE(); rec.spriteSlot.depth = animStream->readByte(); - rec.spriteSlot.scale = animStream->readByte(); + rec.spriteSlot.scale = (int8)animStream->readByte(); _frameEntries.push_back(rec); } @@ -287,7 +288,7 @@ void MadsAnimation::update() { } // Validate the current frame - if (_currentFrame > (int)_miscEntries.size()) { + if (_currentFrame >= (int)_miscEntries.size()) { // Is the animation allowed to be repeated? if (_resetFlag) { _currentFrame = 0; diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp index bfd57c4add3..cfcb113dcd0 100644 --- a/engines/m4/mads_views.cpp +++ b/engines/m4/mads_views.cpp @@ -195,7 +195,7 @@ void MadsSpriteSlots::drawForeground(View *view) { if (slot.scale < 100) { // Minimalised drawing assert(slot.spriteListIndex < (int)_sprites.size()); - M4Sprite *spr = spriteSet.getFrame(slot.frameNumber - 1); + M4Sprite *spr = spriteSet.getFrame((slot.frameNumber & 0x7fff) - 1); spr->copyTo(view, slot.xp, slot.yp, slot.depth, _owner._depthSurface, slot.scale, 0); } else { int xp, yp; From 46155b2c3678784f6333eed1d65a35eefdcb2001 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 6 Jun 2010 09:34:36 +0000 Subject: [PATCH 228/249] Add Android backend from patch #2603856 svn-id: r49449 --- backends/platform/android/README.build | 84 + backends/platform/android/android.cpp | 1413 +++++++++++++++++ backends/platform/android/android.mk | 52 + backends/platform/android/asset-archive.cpp | 414 +++++ backends/platform/android/asset-archive.h | 53 + backends/platform/android/module.mk | 85 + .../gus/scummvm/EditableSurfaceView.java | 59 + .../android/org/inodes/gus/scummvm/Event.java | 330 ++++ .../inodes/gus/scummvm/PluginProvider.java | 52 + .../org/inodes/gus/scummvm/ScummVM.java | 317 ++++ .../inodes/gus/scummvm/ScummVMActivity.java | 446 ++++++ .../gus/scummvm/ScummVMApplication.java | 29 + .../org/inodes/gus/scummvm/Unpacker.java | 370 +++++ .../android/scummvm-android-themeengine.patch | 135 ++ base/commandLine.cpp | 4 +- common/textconsole.cpp | 12 +- configure | 43 +- dists/android/mkmanifest.pl | 169 ++ dists/android/res/drawable/gradient.xml | 7 + dists/android/res/layout/main.xml | 10 + dists/android/res/layout/splash.xml | 19 + dists/android/res/values/strings.xml | 22 + sound/decoders/vorbis.cpp | 2 +- tools/update-version.pl | 1 + 24 files changed, 4121 insertions(+), 7 deletions(-) create mode 100644 backends/platform/android/README.build create mode 100644 backends/platform/android/android.cpp create mode 100644 backends/platform/android/android.mk create mode 100644 backends/platform/android/asset-archive.cpp create mode 100644 backends/platform/android/asset-archive.h create mode 100644 backends/platform/android/module.mk create mode 100644 backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java create mode 100644 backends/platform/android/org/inodes/gus/scummvm/Event.java create mode 100644 backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java create mode 100644 backends/platform/android/org/inodes/gus/scummvm/ScummVM.java create mode 100644 backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java create mode 100644 backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java create mode 100644 backends/platform/android/org/inodes/gus/scummvm/Unpacker.java create mode 100644 backends/platform/android/scummvm-android-themeengine.patch create mode 100644 dists/android/mkmanifest.pl create mode 100644 dists/android/res/drawable/gradient.xml create mode 100644 dists/android/res/layout/main.xml create mode 100644 dists/android/res/layout/splash.xml create mode 100644 dists/android/res/values/strings.xml diff --git a/backends/platform/android/README.build b/backends/platform/android/README.build new file mode 100644 index 00000000000..fa56bfc1805 --- /dev/null +++ b/backends/platform/android/README.build @@ -0,0 +1,84 @@ +Building the ScummVM Android port +================================= + +You will need these things to build: +1. Android EGL headers and library +2. Android SDK +3. An arm-android-eabi GCC toolchain + +In the example commands, we are going to build against the Android 1.5 +native ABI (but using the Android 1.6 SDK tools). Other version +combinations might/should be possible with a bit of tweaking. + +In detail: + +1. Android EGL headers and library + +You can build these from the full Android source, but it is far easier +to just download the 3 Android EGL headers from here: + http://android.git.kernel.org/?p=platform/frameworks/base.git;a=tree;f=opengl/include/EGL;hb=HEAD + (copy them to a directory called "EGL" somewhere) + +... and grab libEGL.so off an existing phone/emulator: + adb pull /system/lib/libEGL.so /tmp + +2. Android SDK + +Download and install somewhere. + +3. arm-android-eabi GCC toolchain + +You have several choices for toolchains: + +- Use Google arm-eabi prebuilt toolchain. + +This is shipped with both the Android source release and Android NDK. +The problem is that "arm-eabi-gcc" can't actually link anything +successfully without extra command line flags. To use this with the +ScummVM configure/build environment you will need to create a family +of shell wrapper scripts that convert "arm-android-eabi-foo" to +"arm-eabi-foo -mandroid". + +For example, I use this script: + #!/bin/sh + exec arm-eabi-${0##*-} -mandroid -DANDROID "$@" + +... and create a family of symlinks/hardlinks pointing to it called +arm-android-eabi-gcc, arm-android-eabi-g++, etc. For tools that don't +take a "-mandroid" argument - like arm-eabi-strip - I bypass the shell +wrapper and just create an arm-android-eabi-strip symlink to the tool +directly. + +- Build your own arm-android-eabi toolchain from GCC source. + +This is lots of fun. I suggest my Android openembedded patches, see: + http://wiki.github.com/anguslees/openembedded-android/ +(You just need to have lots of disk space and type a few commands) +If you get stuck, ask + +Alternatively, do a websearch - there are several other cross-compile +toolchains around. + + +Building ScummVM +================ + + export ANDROID_SDK= + + PATH=$ANDROID_SDK/platforms/android-1.6/tools:$ANDROID_SDK/tools:$PATH + # You also want to ensure your arm-android-eabi toolchain is in your $PATH + + export ANDROID_TOP= + + EGL_INC="-I" + EGL_LIBS="-L" + + CPPFLAGS="$EGL_INC" \ + LDFLAGS="-g $EGL_LIBS" \ + ./configure --backend=android --host=android --enable-zlib #and any other flags + make scummvm.apk + +This will build a "monolithic" ScummVM package, with the engines +statically linked in. If you want to build separate engine packages, +like on the market, add "--enable-plugins --default-dynamic" to +configure and also make scummvm-engine-scumm.apk, etc. diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp new file mode 100644 index 00000000000..76590ec823f --- /dev/null +++ b/backends/platform/android/android.cpp @@ -0,0 +1,1413 @@ +/* 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 "backends/base-backend.h" +#include "base/main.h" +#include "graphics/surface.h" + +#include "backends/platform/android/video.h" + +#if defined(ANDROID_BACKEND) + +#define ANDROID_VERSION_GE(major,minor) \ + (ANDROID_MAJOR_VERSION > (major) || \ + (ANDROID_MAJOR_VERSION == (major) && ANDROID_MINOR_VERSION >= (minor))) + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "common/archive.h" +#include "common/util.h" +#include "common/rect.h" +#include "common/queue.h" +#include "common/mutex.h" +#include "common/events.h" +#include "common/config-manager.h" + +#include "backends/fs/posix/posix-fs-factory.h" +#include "backends/keymapper/keymapper.h" +#include "backends/saves/default/default-saves.h" +#include "backends/timer/default/default-timer.h" +#include "backends/plugins/posix/posix-provider.h" +#include "sound/mixer_intern.h" + +#include "backends/platform/android/asset-archive.h" + +#undef LOG_TAG +#define LOG_TAG "ScummVM" + +#if 0 +#define ENTER(args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, args) +#else +#define ENTER(args...) /**/ +#endif + +// Fix JNIEXPORT declaration to actually do something useful +#undef JNIEXPORT +#define JNIEXPORT __attribute__ ((visibility("default"))) + +static JavaVM *cached_jvm; +static jfieldID FID_Event_type; +static jfieldID FID_Event_synthetic; +static jfieldID FID_Event_kbd_keycode; +static jfieldID FID_Event_kbd_ascii; +static jfieldID FID_Event_kbd_flags; +static jfieldID FID_Event_mouse_x; +static jfieldID FID_Event_mouse_y; +static jfieldID FID_Event_mouse_relative; +static jfieldID FID_ScummVM_nativeScummVM; +static jmethodID MID_Object_wait; + +JNIEnv* JNU_GetEnv() { + JNIEnv* env; + bool version_unsupported = + cached_jvm->GetEnv((void**)&env, JNI_VERSION_1_2); + assert(! version_unsupported); + return env; +} + +static void JNU_ThrowByName(JNIEnv* env, const char* name, const char* msg) { + jclass cls = env->FindClass(name); + // if cls is NULL, an exception has already been thrown + if (cls != NULL) + env->ThrowNew(cls, msg); + env->DeleteLocalRef(cls); +} + +// floating point. use sparingly. +template +static inline T scalef(T in, float numerator, float denominator) { + return static_cast(in) * numerator / denominator; +} + +static inline GLfixed xdiv(int numerator, int denominator) { + assert(numerator < (1<<16)); + return (numerator << 16) / denominator; +} + +#ifdef DYNAMIC_MODULES +class AndroidPluginProvider : public POSIXPluginProvider { +protected: + virtual void addCustomDirectories(Common::FSList &dirs) const; +}; +#endif + + +#if 0 +#define CHECK_GL_ERROR() checkGlError(__FILE__, __LINE__) +static const char* getGlErrStr(GLenum error) { + switch (error) { + case GL_NO_ERROR: return "GL_NO_ERROR"; + case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; + case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; + case GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW"; + case GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW"; + case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; + } + + static char buf[40]; + snprintf(buf, sizeof(buf), "(Unknown GL error code 0x%x)", error); + return buf; +} +static void checkGlError(const char* file, int line) { + GLenum error = glGetError(); + if (error != GL_NO_ERROR) + warning("%s:%d: GL error: %s", file, line, getGlErrStr(error)); +} +#else +#define CHECK_GL_ERROR() do {} while (false) +#endif + +class OSystem_Android : public BaseBackend { +private: + jobject _back_ptr; // back pointer to (java) peer instance + jmethodID MID_displayMessageOnOSD; + jmethodID MID_setWindowCaption; + jmethodID MID_initBackend; + jmethodID MID_audioSampleRate; + jmethodID MID_showVirtualKeyboard; + jmethodID MID_getSysArchives; + jmethodID MID_getPluginDirectories; + jmethodID MID_setupScummVMSurface; + jmethodID MID_destroyScummVMSurface; + + int _screen_changeid; + EGLDisplay _egl_display; + EGLSurface _egl_surface; + EGLint _egl_surface_width; + EGLint _egl_surface_height; + + bool _force_redraw; + + // Game layer + GLESPaletteTexture* _game_texture; + int _shake_offset; + bool _full_screen_dirty; + Common::Array _dirty_rects; + + // Overlay layer + GLES4444Texture* _overlay_texture; + bool _show_overlay; + + // Mouse layer + GLESPaletteATexture* _mouse_texture; + Common::Point _mouse_hotspot; + int _mouse_targetscale; + bool _show_mouse; + bool _use_mouse_palette; + + Common::Queue _event_queue; + MutexRef _event_queue_lock; + + bool _timer_thread_exit; + pthread_t _timer_thread; + static void* timerThreadFunc(void* arg); + + bool _virtkeybd_on; + + Common::SaveFileManager *_savefile; + Audio::MixerImpl *_mixer; + Common::TimerManager *_timer; + FilesystemFactory *_fsFactory; + Common::Archive *_asset_archive; + timeval _startTime; + + void setupScummVMSurface(); + void destroyScummVMSurface(); + void setupKeymapper(); + void _setCursorPalette(const byte *colors, uint start, uint num); + +public: + OSystem_Android(jobject am); + virtual ~OSystem_Android(); + bool initJavaHooks(JNIEnv* env, jobject self); + + static OSystem_Android* fromJavaObject(JNIEnv* env, jobject obj); + virtual void initBackend(); + void addPluginDirectories(Common::FSList &dirs) const; + + virtual bool hasFeature(Feature f); + virtual void setFeatureState(Feature f, bool enable); + virtual bool getFeatureState(Feature f); + virtual const GraphicsMode *getSupportedGraphicsModes() const; + virtual int getDefaultGraphicsMode() const; + bool setGraphicsMode(const char *name); + virtual bool setGraphicsMode(int mode); + virtual int getGraphicsMode() const; + virtual void initSize(uint width, uint height, + const Graphics::PixelFormat *format); + virtual int getScreenChangeID() const { return _screen_changeid; } + virtual int16 getHeight(); + virtual int16 getWidth(); + virtual void setPalette(const byte *colors, uint start, uint num); + virtual void grabPalette(byte *colors, uint start, uint num); + virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); + virtual void updateScreen(); + virtual Graphics::Surface *lockScreen(); + virtual void unlockScreen(); + virtual void setShakePos(int shakeOffset); + virtual void fillScreen(uint32 col); + virtual void setFocusRectangle(const Common::Rect& rect); + virtual void clearFocusRectangle(); + + virtual void showOverlay(); + virtual void hideOverlay(); + virtual void clearOverlay(); + virtual void grabOverlay(OverlayColor *buf, int pitch); + virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); + virtual int16 getOverlayHeight(); + virtual int16 getOverlayWidth(); + virtual Graphics::PixelFormat getOverlayFormat() const { + // RGBA 4444 + Graphics::PixelFormat format; + format.bytesPerPixel = 2; + format.rLoss = 8 - 4; + format.gLoss = 8 - 4; + format.bLoss = 8 - 4; + format.aLoss = 8 - 4; + format.rShift = 3*4; + format.gShift = 2*4; + format.bShift = 1*4; + format.aShift = 0*4; + return format; + } + + virtual bool showMouse(bool visible); + + virtual void warpMouse(int x, int y); + virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format); + virtual void setCursorPalette(const byte *colors, uint start, uint num); + virtual void disableCursorPalette(bool disable); + + virtual bool pollEvent(Common::Event &event); + void pushEvent(const Common::Event& event); + virtual uint32 getMillis(); + virtual void delayMillis(uint msecs); + + virtual MutexRef createMutex(void); + virtual void lockMutex(MutexRef mutex); + virtual void unlockMutex(MutexRef mutex); + virtual void deleteMutex(MutexRef mutex); + + virtual void quit(); + + virtual void setWindowCaption(const char *caption); + virtual void displayMessageOnOSD(const char *msg); + virtual void showVirtualKeyboard(bool enable); + + virtual Common::SaveFileManager *getSavefileManager(); + virtual Audio::Mixer *getMixer(); + virtual void getTimeAndDate(TimeDate &t) const; + virtual Common::TimerManager *getTimerManager(); + virtual FilesystemFactory *getFilesystemFactory(); + virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); +}; + +OSystem_Android::OSystem_Android(jobject am) + : _back_ptr(0), + _egl_display(EGL_NO_DISPLAY), + _egl_surface(EGL_NO_SURFACE), + _screen_changeid(0), + _force_redraw(false), + _game_texture(NULL), + _overlay_texture(NULL), + _mouse_texture(NULL), + _use_mouse_palette(false), + _show_mouse(false), + _show_overlay(false), + _savefile(0), + _mixer(0), + _timer(0), + _fsFactory(new POSIXFilesystemFactory()), + _asset_archive(new AndroidAssetArchive(am)), + _shake_offset(0), + _full_screen_dirty(false), + _event_queue_lock(createMutex()) { +} + +OSystem_Android::~OSystem_Android() { + ENTER("~OSystem_Android()"); + delete _game_texture; + delete _overlay_texture; + delete _mouse_texture; + destroyScummVMSurface(); + JNIEnv* env = JNU_GetEnv(); + //env->DeleteWeakGlobalRef(_back_ptr); + env->DeleteGlobalRef(_back_ptr); + delete _savefile; + delete _mixer; + delete _timer; + delete _fsFactory; + delete _asset_archive; + deleteMutex(_event_queue_lock); +} + +OSystem_Android* OSystem_Android::fromJavaObject(JNIEnv* env, jobject obj) { + jlong peer = env->GetLongField(obj, FID_ScummVM_nativeScummVM); + return (OSystem_Android*)peer; +} + +bool OSystem_Android::initJavaHooks(JNIEnv* env, jobject self) { + // weak global ref to allow class to be unloaded + // ... except dalvik doesn't implement NewWeakGlobalRef (yet) + //_back_ptr = env->NewWeakGlobalRef(self); + _back_ptr = env->NewGlobalRef(self); + + jclass cls = env->GetObjectClass(_back_ptr); + +#define FIND_METHOD(name, signature) do { \ + MID_ ## name = env->GetMethodID(cls, #name, signature); \ + if (MID_ ## name == NULL) \ + return false; \ + } while (0) + + FIND_METHOD(setWindowCaption, "(Ljava/lang/String;)V"); + FIND_METHOD(displayMessageOnOSD, "(Ljava/lang/String;)V"); + FIND_METHOD(initBackend, "()V"); + FIND_METHOD(audioSampleRate, "()I"); + FIND_METHOD(showVirtualKeyboard, "(Z)V"); + FIND_METHOD(getSysArchives, "()[Ljava/lang/String;"); + FIND_METHOD(getPluginDirectories, "()[Ljava/lang/String;"); + FIND_METHOD(setupScummVMSurface, "()V"); + FIND_METHOD(destroyScummVMSurface, "()V"); + +#undef FIND_METHOD + + return true; +} + +static void ScummVM_create(JNIEnv* env, jobject self, jobject am) { + OSystem_Android* cpp_obj = new OSystem_Android(am); + if (!cpp_obj->initJavaHooks(env, self)) + // Exception already thrown by initJavaHooks + return; + + env->SetLongField(self, FID_ScummVM_nativeScummVM, (jlong)cpp_obj); + +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new AndroidPluginProvider()); +#endif +} + +static void ScummVM_nativeDestroy(JNIEnv* env, jobject self) { + OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); + delete cpp_obj; +} + +static void ScummVM_audioMixCallback(JNIEnv* env, jobject self, + jbyteArray jbuf) { + OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); + jsize len = env->GetArrayLength(jbuf); + jbyte* buf = env->GetByteArrayElements(jbuf, NULL); + if (buf == NULL) { + warning("Unable to get Java audio byte array. Skipping."); + return; + } + Audio::MixerImpl* mixer = + static_cast(cpp_obj->getMixer()); + assert(mixer); + mixer->mixCallback(reinterpret_cast(buf), len); + env->ReleaseByteArrayElements(jbuf, buf, 0); +} + +static void ScummVM_setConfManInt(JNIEnv* env, jclass cls, + jstring key_obj, jint value) { + ENTER("setConfManInt(%p, %d)", key_obj, (int)value); + const char* key = env->GetStringUTFChars(key_obj, NULL); + if (key == NULL) + return; + ConfMan.setInt(key, value); + env->ReleaseStringUTFChars(key_obj, key); +} + +static void ScummVM_setConfManString(JNIEnv* env, jclass cls, jstring key_obj, + jstring value_obj) { + ENTER("setConfManStr(%p, %p)", key_obj, value_obj); + const char* key = env->GetStringUTFChars(key_obj, NULL); + if (key == NULL) + return; + const char* value = env->GetStringUTFChars(value_obj, NULL); + if (value == NULL) { + env->ReleaseStringUTFChars(key_obj, key); + return; + } + ConfMan.set(key, value); + env->ReleaseStringUTFChars(value_obj, value); + env->ReleaseStringUTFChars(key_obj, key); +} + +void* OSystem_Android::timerThreadFunc(void* arg) { + OSystem_Android* system = (OSystem_Android*)arg; + DefaultTimerManager* timer = (DefaultTimerManager*)(system->_timer); + + struct timespec tv; + tv.tv_sec = 0; + tv.tv_nsec = 100 * 1000 * 1000; // 100ms + + while (!system->_timer_thread_exit) { + timer->handler(); + nanosleep(&tv, NULL); + } + + return NULL; +} + +void OSystem_Android::initBackend() { + ENTER("initBackend()"); + JNIEnv* env = JNU_GetEnv(); + + ConfMan.setInt("autosave_period", 0); + ConfMan.setInt("FM_medium_quality", true); + + // must happen before creating TimerManager to avoid race in + // creating EventManager + setupKeymapper(); + + // BUG: "transient" ConfMan settings get nuked by the options + // screen. Passing the savepath in this way makes it stick + // (via ConfMan.registerDefault) + _savefile = new DefaultSaveFileManager(ConfMan.get("savepath")); + _timer = new DefaultTimerManager(); + + gettimeofday(&_startTime, NULL); + + jint sample_rate = env->CallIntMethod(_back_ptr, MID_audioSampleRate); + if (env->ExceptionCheck()) { + warning("Error finding audio sample rate - assuming 11025HZ"); + env->ExceptionDescribe(); + env->ExceptionClear(); + sample_rate = 11025; + } + _mixer = new Audio::MixerImpl(this, sample_rate); + _mixer->setReady(true); + + env->CallVoidMethod(_back_ptr, MID_initBackend); + if (env->ExceptionCheck()) { + error("Error in Java initBackend"); + env->ExceptionDescribe(); + env->ExceptionClear(); + } + + _timer_thread_exit = false; + pthread_create(&_timer_thread, NULL, timerThreadFunc, this); + + OSystem::initBackend(); + + setupScummVMSurface(); +} + +void OSystem_Android::addPluginDirectories(Common::FSList &dirs) const { + ENTER("OSystem_Android::addPluginDirectories()"); + JNIEnv* env = JNU_GetEnv(); + + jobjectArray array = + (jobjectArray)env->CallObjectMethod(_back_ptr, MID_getPluginDirectories); + if (env->ExceptionCheck()) { + warning("Error finding plugin directories"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return; + } + + jsize size = env->GetArrayLength(array); + for (jsize i = 0; i < size; ++i) { + jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); + if (path_obj == NULL) + continue; + const char* path = env->GetStringUTFChars(path_obj, NULL); + if (path == NULL) { + warning("Error getting string characters from plugin directory"); + env->ExceptionClear(); + env->DeleteLocalRef(path_obj); + continue; + } + dirs.push_back(Common::FSNode(path)); + env->ReleaseStringUTFChars(path_obj, path); + env->DeleteLocalRef(path_obj); + } +} + +bool OSystem_Android::hasFeature(Feature f) { + return (f == kFeatureCursorHasPalette || + f == kFeatureVirtualKeyboard || + f == kFeatureOverlaySupportsAlpha); +} + +void OSystem_Android::setFeatureState(Feature f, bool enable) { + ENTER("setFeatureState(%d, %d)", f, enable); + switch (f) { + case kFeatureVirtualKeyboard: + _virtkeybd_on = enable; + showVirtualKeyboard(enable); + break; + default: + break; + } +} + +bool OSystem_Android::getFeatureState(Feature f) { + switch (f) { + case kFeatureVirtualKeyboard: + return _virtkeybd_on; + default: + return false; + } +} + +const OSystem::GraphicsMode* OSystem_Android::getSupportedGraphicsModes() const { + static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {"default", "Default", 1}, + {0, 0, 0}, + }; + return s_supportedGraphicsModes; +} + + +int OSystem_Android::getDefaultGraphicsMode() const { + return 1; +} + +bool OSystem_Android::setGraphicsMode(const char *mode) { + ENTER("setGraphicsMode(%s)", mode); + return true; +} + +bool OSystem_Android::setGraphicsMode(int mode) { + ENTER("setGraphicsMode(%d)", mode); + return true; +} + +int OSystem_Android::getGraphicsMode() const { + return 1; +} + +void OSystem_Android::setupScummVMSurface() { + JNIEnv* env = JNU_GetEnv(); + env->CallVoidMethod(_back_ptr, MID_setupScummVMSurface); + if (env->ExceptionCheck()) + return; + + // EGL set up with a new surface. Initialise OpenGLES context. + + _egl_display = eglGetCurrentDisplay(); + _egl_surface = eglGetCurrentSurface(EGL_DRAW); + + static bool log_version = true; + if (log_version) { + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, + "Using EGL %s (%s); GL %s/%s (%s)", + eglQueryString(_egl_display, EGL_VERSION), + eglQueryString(_egl_display, EGL_VENDOR), + glGetString(GL_VERSION), + glGetString(GL_RENDERER), + glGetString(GL_VENDOR)); + log_version = false; // only log this once + } + + GLESTexture::initGLExtensions(); + + if (!eglQuerySurface(_egl_display, _egl_surface, + EGL_WIDTH, &_egl_surface_width) || + !eglQuerySurface(_egl_display, _egl_surface, + EGL_HEIGHT, &_egl_surface_height)) { + JNU_ThrowByName(env, "java/lang/RuntimeException", + "Error fetching EGL surface width/height"); + return; + } + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, + "New surface is %dx%d", + _egl_surface_width, _egl_surface_height); + + CHECK_GL_ERROR(); + + // Turn off anything that looks like 3D ;) + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + glDisable(GL_DITHER); + glShadeModel(GL_FLAT); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glEnable(GL_TEXTURE_2D); + + if (!_game_texture) + _game_texture = new GLESPaletteTexture(); + else + _game_texture->reinitGL(); + + if (!_overlay_texture) + _overlay_texture = new GLES4444Texture(); + else + _overlay_texture->reinitGL(); + + if (!_mouse_texture) + _mouse_texture = new GLESPaletteATexture(); + else + _mouse_texture->reinitGL(); + + glViewport(0, 0, _egl_surface_width, _egl_surface_height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrthof(0, _egl_surface_width, _egl_surface_height, 0, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + CHECK_GL_ERROR(); + + _force_redraw = true; +} + +void OSystem_Android::destroyScummVMSurface() { + _egl_surface = EGL_NO_SURFACE; + JNIEnv* env = JNU_GetEnv(); + env->CallVoidMethod(_back_ptr, MID_destroyScummVMSurface); + // Can't use OpenGLES functions after this +} + +void OSystem_Android::initSize(uint width, uint height, + const Graphics::PixelFormat *format) { + ENTER("initSize(%d,%d,%p)", width, height, format); + + _game_texture->allocBuffer(width, height); + + // Cap at 320x200 or the ScummVM themes abort :/ + GLuint overlay_width = MIN(_egl_surface_width, 320); + GLuint overlay_height = MIN(_egl_surface_height, 200); + _overlay_texture->allocBuffer(overlay_width, overlay_height); + + // Don't know mouse size yet - it gets reallocated in + // setMouseCursor. We need the palette allocated before + // setMouseCursor however, so just take a guess at the desired + // size (it's small). + _mouse_texture->allocBuffer(20, 20); +} + +int16 OSystem_Android::getHeight() { + return _game_texture->height(); +} + +int16 OSystem_Android::getWidth() { + return _game_texture->width(); +} + +void OSystem_Android::setPalette(const byte* colors, uint start, uint num) { + ENTER("setPalette(%p, %u, %u)", colors, start, num); + + if (!_use_mouse_palette) + _setCursorPalette(colors, start, num); + + byte* palette = _game_texture->palette() + start*3; + do { + for (int i = 0; i < 3; ++i) + palette[i] = colors[i]; + palette += 3; + colors += 4; + } while (--num); +} + +void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { + ENTER("grabPalette(%p, %u, %u)", colors, start, num); + const byte* palette = _game_texture->palette_const() + start*3; + do { + for (int i = 0; i < 3; ++i) + colors[i] = palette[i]; + colors[3] = 0xff; // alpha + + palette += 3; + colors += 4; + } while (--num); +} + +void OSystem_Android::copyRectToScreen(const byte *buf, int pitch, + int x, int y, int w, int h) { + ENTER("copyRectToScreen(%p, %d, %d, %d, %d, %d)", + buf, pitch, x, y, w, h); + + _game_texture->updateBuffer(x, y, w, h, buf, pitch); +} + +void OSystem_Android::updateScreen() { + //ENTER("updateScreen()"); + + if (!_force_redraw && + !_game_texture->dirty() && + !_overlay_texture->dirty() && + !_mouse_texture->dirty()) + return; + + _force_redraw = false; + + glPushMatrix(); + + if (_shake_offset != 0) { + // This is the only case where _game_texture doesn't + // cover the entire screen. + glClearColorx(0, 0, 0, 1 << 16); + glClear(GL_COLOR_BUFFER_BIT); + + // Move everything up by _shake_offset (game) pixels + glTranslatex(0, -_shake_offset << 16, 0); + } + + _game_texture->drawTexture(0, 0, + _egl_surface_width, _egl_surface_height); + + CHECK_GL_ERROR(); + + if (_show_overlay) { + _overlay_texture->drawTexture(0, 0, + _egl_surface_width, + _egl_surface_height); + CHECK_GL_ERROR(); + } + + if (_show_mouse) { + glPushMatrix(); + + glTranslatex(-_mouse_hotspot.x << 16, + -_mouse_hotspot.y << 16, + 0); + + // Scale up ScummVM -> OpenGL (pixel) coordinates + int texwidth, texheight; + if (_show_overlay) { + texwidth = getOverlayWidth(); + texheight = getOverlayHeight(); + } else { + texwidth = getWidth(); + texheight = getHeight(); + } + glScalex(xdiv(_egl_surface_width, texwidth), + xdiv(_egl_surface_height, texheight), + 1 << 16); + + // Note the extra half texel to position the mouse in + // the middle of the x,y square: + const Common::Point& mouse = getEventManager()->getMousePos(); + glTranslatex((mouse.x << 16) | 1 << 15, + (mouse.y << 16) | 1 << 15, 0); + + // Mouse targetscale just seems to make the cursor way + // too big :/ + //glScalex(_mouse_targetscale << 16, _mouse_targetscale << 16, + // 1 << 16); + + _mouse_texture->drawTexture(); + + glPopMatrix(); + } + + glPopMatrix(); + + CHECK_GL_ERROR(); + + if (!eglSwapBuffers(_egl_display, _egl_surface)) { + EGLint error = eglGetError(); + warning("eglSwapBuffers exited with error 0x%x", error); + // Some errors mean we need to reinit GL + if (error == EGL_CONTEXT_LOST) { + destroyScummVMSurface(); + setupScummVMSurface(); + } + } +} + +Graphics::Surface *OSystem_Android::lockScreen() { + ENTER("lockScreen()"); + Graphics::Surface* surface = _game_texture->surface(); + assert(surface->pixels); + return surface; +} + +void OSystem_Android::unlockScreen() { + ENTER("unlockScreen()"); + assert(_game_texture->dirty()); +} + +void OSystem_Android::setShakePos(int shake_offset) { + ENTER("setShakePos(%d)", shake_offset); + if (_shake_offset != shake_offset) { + _shake_offset = shake_offset; + _force_redraw = true; + } +} + +void OSystem_Android::fillScreen(uint32 col) { + ENTER("fillScreen(%u)", col); + assert(col < 256); + _game_texture->fillBuffer(col); +} + +void OSystem_Android::setFocusRectangle(const Common::Rect& rect) { + ENTER("setFocusRectangle(%d,%d,%d,%d)", + rect.left, rect.top, rect.right, rect.bottom); +#if 0 + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrthof(rect.left, rect.right, rect.top, rect.bottom, 0, 1); + glMatrixMode(GL_MODELVIEW); + + _force_redraw = true; +#endif +} + +void OSystem_Android::clearFocusRectangle() { + ENTER("clearFocusRectangle()"); +#if 0 + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrthof(0, _egl_surface_width, _egl_surface_height, 0, -1, 1); + glMatrixMode(GL_MODELVIEW); + + _force_redraw = true; +#endif +} + +void OSystem_Android::showOverlay() { + ENTER("showOverlay()"); + _show_overlay = true; + _force_redraw = true; +} + +void OSystem_Android::hideOverlay() { + ENTER("hideOverlay()"); + _show_overlay = false; + _force_redraw = true; +} + +void OSystem_Android::clearOverlay() { + ENTER("clearOverlay()"); + _overlay_texture->fillBuffer(0); +} + +void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { + ENTER("grabOverlay(%p, %d)", buf, pitch); + // We support overlay alpha blending, so the pixel data here + // shouldn't actually be used. Let's fill it with zeros, I'm sure + // it will be fine... + const Graphics::Surface* surface = _overlay_texture->surface_const(); + assert(surface->bytesPerPixel == sizeof(buf[0])); + int h = surface->h; + do { + memset(buf, 0, surface->w * sizeof(buf[0])); + buf += pitch; // This 'pitch' is pixels not bytes + } while (--h); +} + +void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch, + int x, int y, int w, int h) { + ENTER("copyRectToOverlay(%p, %d, %d, %d, %d, %d)", + buf, pitch, x, y, w, h); + const Graphics::Surface* surface = _overlay_texture->surface_const(); + assert(surface->bytesPerPixel == sizeof(buf[0])); + + // This 'pitch' is pixels not bytes + _overlay_texture->updateBuffer(x, y, w, h, buf, pitch * sizeof(buf[0])); +} + +int16 OSystem_Android::getOverlayHeight() { + return _overlay_texture->height(); +} + +int16 OSystem_Android::getOverlayWidth() { + return _overlay_texture->width(); +} + +bool OSystem_Android::showMouse(bool visible) { + ENTER("showMouse(%d)", visible); + _show_mouse = visible; + return true; +} + +void OSystem_Android::warpMouse(int x, int y) { + ENTER("warpMouse(%d, %d)", x, y); + // We use only the eventmanager's idea of the current mouse + // position, so there is nothing extra to do here. +} + +void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, + int hotspotX, int hotspotY, + uint32 keycolor, int cursorTargetScale, + const Graphics::PixelFormat *format) { + ENTER("setMouseCursor(%p, %u, %u, %d, %d, %d, %d, %p)", + buf, w, h, hotspotX, hotspotY, (int)keycolor, cursorTargetScale, + format); + + assert(keycolor < 256); + + _mouse_texture->allocBuffer(w, h); + + // Update palette alpha based on keycolor + byte* palette = _mouse_texture->palette(); + int i = 256; + do { + palette[3] = 0xff; + palette += 4; + } while (--i); + palette = _mouse_texture->palette(); + palette[keycolor*4 + 3] = 0x00; + _mouse_texture->updateBuffer(0, 0, w, h, buf, w); + + _mouse_hotspot = Common::Point(hotspotX, hotspotY); + _mouse_targetscale = cursorTargetScale; +} + +void OSystem_Android::_setCursorPalette(const byte *colors, + uint start, uint num) { + byte* palette = _mouse_texture->palette() + start*4; + do { + for (int i = 0; i < 3; ++i) + palette[i] = colors[i]; + // Leave alpha untouched to preserve keycolor + + palette += 4; + colors += 4; + } while (--num); +} + +void OSystem_Android::setCursorPalette(const byte *colors, + uint start, uint num) { + ENTER("setCursorPalette(%p, %u, %u)", colors, start, num); + _setCursorPalette(colors, start, num); + _use_mouse_palette = true; +} + +void OSystem_Android::disableCursorPalette(bool disable) { + ENTER("disableCursorPalette(%d)", disable); + _use_mouse_palette = !disable; +} + +void OSystem_Android::setupKeymapper() { +#ifdef ENABLE_KEYMAPPER + using namespace Common; + + Keymapper *mapper = getEventManager()->getKeymapper(); + + HardwareKeySet *keySet = new HardwareKeySet(); + keySet->addHardwareKey( + new HardwareKey("n", KeyState(KEYCODE_n), "n (vk)", + kTriggerLeftKeyType, + kVirtualKeyboardActionType)); + mapper->registerHardwareKeySet(keySet); + + Keymap *globalMap = new Keymap("global"); + Action *act; + + act = new Action(globalMap, "VIRT", "Display keyboard", + kVirtualKeyboardActionType); + act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0)); + + mapper->addGlobalKeymap(globalMap); + + mapper->pushKeymap("global"); +#endif +} + +bool OSystem_Android::pollEvent(Common::Event &event) { + //ENTER("pollEvent()"); + lockMutex(_event_queue_lock); + if (_event_queue.empty()) { + unlockMutex(_event_queue_lock); + return false; + } + event = _event_queue.pop(); + unlockMutex(_event_queue_lock); + + switch (event.type) { + case Common::EVENT_MOUSEMOVE: + // TODO: only dirty/redraw move bounds + _force_redraw = true; + // fallthrough + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + case Common::EVENT_WHEELUP: + case Common::EVENT_WHEELDOWN: + case Common::EVENT_MBUTTONDOWN: + case Common::EVENT_MBUTTONUP: { + if (event.kbd.flags == 1) { // relative mouse hack + // Relative (trackball) mouse hack. + const Common::Point& mouse_pos = + getEventManager()->getMousePos(); + event.mouse.x += mouse_pos.x; + event.mouse.y += mouse_pos.y; + event.mouse.x = CLIP(event.mouse.x, (int16)0, _show_overlay ? + getOverlayWidth() : getWidth()); + event.mouse.y = CLIP(event.mouse.y, (int16)0, _show_overlay ? + getOverlayHeight() : getHeight()); + } else { + // Touchscreen events need to be converted + // from device to game coords first. + const GLESTexture* tex = _show_overlay + ? static_cast(_overlay_texture) + : static_cast(_game_texture); + event.mouse.x = scalef(event.mouse.x, tex->width(), + _egl_surface_width); + event.mouse.y = scalef(event.mouse.y, tex->height(), + _egl_surface_height); + event.mouse.x -= _shake_offset; + } + break; + } + case Common::EVENT_SCREEN_CHANGED: + debug("EVENT_SCREEN_CHANGED"); + _screen_changeid++; + destroyScummVMSurface(); + setupScummVMSurface(); + break; + default: + break; + } + + return true; +} + +void OSystem_Android::pushEvent(const Common::Event& event) { + lockMutex(_event_queue_lock); + + // Try to combine multiple queued mouse move events + if (event.type == Common::EVENT_MOUSEMOVE && + !_event_queue.empty() && + _event_queue.back().type == Common::EVENT_MOUSEMOVE) { + Common::Event tail = _event_queue.back(); + if (event.kbd.flags) { + // relative movement hack + tail.mouse.x += event.mouse.x; + tail.mouse.y += event.mouse.y; + } else { + // absolute position + tail.kbd.flags = 0; // clear relative flag + tail.mouse.x = event.mouse.x; + tail.mouse.y = event.mouse.y; + } + } + else + _event_queue.push(event); + + unlockMutex(_event_queue_lock); +} + +static void ScummVM_pushEvent(JNIEnv* env, jobject self, jobject java_event) { + OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); + + Common::Event event; + event.type = (Common::EventType)env->GetIntField(java_event, + FID_Event_type); + event.synthetic = + env->GetBooleanField(java_event, FID_Event_synthetic); + + switch (event.type) { + case Common::EVENT_KEYDOWN: + case Common::EVENT_KEYUP: + event.kbd.keycode = (Common::KeyCode)env->GetIntField( + java_event, FID_Event_kbd_keycode); + event.kbd.ascii = static_cast(env->GetIntField( + java_event, FID_Event_kbd_ascii)); + event.kbd.flags = static_cast(env->GetIntField( + java_event, FID_Event_kbd_flags)); + break; + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + case Common::EVENT_WHEELUP: + case Common::EVENT_WHEELDOWN: + case Common::EVENT_MBUTTONDOWN: + case Common::EVENT_MBUTTONUP: + event.mouse.x = + env->GetIntField(java_event, FID_Event_mouse_x); + event.mouse.y = + env->GetIntField(java_event, FID_Event_mouse_y); + // This is a terrible hack. We stash "relativeness" + // in the kbd.flags field until pollEvent() can work + // it out. + event.kbd.flags = env->GetBooleanField( + java_event, FID_Event_mouse_relative) ? 1 : 0; + break; + default: + break; + } + + cpp_obj->pushEvent(event); +} + +uint32 OSystem_Android::getMillis() { + timeval curTime; + gettimeofday(&curTime, NULL); + return (uint32)(((curTime.tv_sec - _startTime.tv_sec) * 1000) + \ + ((curTime.tv_usec - _startTime.tv_usec) / 1000)); +} + +void OSystem_Android::delayMillis(uint msecs) { + usleep(msecs * 1000); +} + +OSystem::MutexRef OSystem_Android::createMutex() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + pthread_mutex_t *mutex = new pthread_mutex_t; + if (pthread_mutex_init(mutex, &attr) != 0) { + warning("pthread_mutex_init() failed!"); + delete mutex; + return NULL; + } + return (MutexRef)mutex; +} + +void OSystem_Android::lockMutex(MutexRef mutex) { + if (pthread_mutex_lock((pthread_mutex_t*)mutex) != 0) + warning("pthread_mutex_lock() failed!"); +} + +void OSystem_Android::unlockMutex(MutexRef mutex) { + if (pthread_mutex_unlock((pthread_mutex_t*)mutex) != 0) + warning("pthread_mutex_unlock() failed!"); +} + +void OSystem_Android::deleteMutex(MutexRef mutex) { + pthread_mutex_t* m = (pthread_mutex_t*)mutex; + if (pthread_mutex_destroy(m) != 0) + warning("pthread_mutex_destroy() failed!"); + else + delete m; +} + +void OSystem_Android::quit() { + ENTER("quit()"); + + _timer_thread_exit = true; + pthread_join(_timer_thread, NULL); +} + +void OSystem_Android::setWindowCaption(const char *caption) { + ENTER("setWindowCaption(%s)", caption); + JNIEnv* env = JNU_GetEnv(); + jstring java_caption = env->NewStringUTF(caption); + env->CallVoidMethod(_back_ptr, MID_setWindowCaption, java_caption); + if (env->ExceptionCheck()) { + warning("Failed to set window caption"); + env->ExceptionDescribe(); + env->ExceptionClear(); + } + env->DeleteLocalRef(java_caption); +} + +void OSystem_Android::displayMessageOnOSD(const char *msg) { + ENTER("displayMessageOnOSD(%s)", msg); + JNIEnv* env = JNU_GetEnv(); + jstring java_msg = env->NewStringUTF(msg); + env->CallVoidMethod(_back_ptr, MID_displayMessageOnOSD, java_msg); + if (env->ExceptionCheck()) { + warning("Failed to display OSD message"); + env->ExceptionDescribe(); + env->ExceptionClear(); + } + env->DeleteLocalRef(java_msg); +} + +void OSystem_Android::showVirtualKeyboard(bool enable) { + ENTER("showVirtualKeyboard(%d)", enable); + JNIEnv* env = JNU_GetEnv(); + env->CallVoidMethod(_back_ptr, MID_showVirtualKeyboard, enable); + if (env->ExceptionCheck()) { + error("Error trying to show virtual keyboard"); + env->ExceptionDescribe(); + env->ExceptionClear(); + } +} + +Common::SaveFileManager *OSystem_Android::getSavefileManager() { + assert(_savefile); + return _savefile; +} + +Audio::Mixer *OSystem_Android::getMixer() { + assert(_mixer); + return _mixer; +} + +Common::TimerManager *OSystem_Android::getTimerManager() { + assert(_timer); + return _timer; +} + +void OSystem_Android::getTimeAndDate(TimeDate &td) const { + struct tm tm; + const time_t curTime = time(NULL); + localtime_r(&curTime, &tm); + td.tm_sec = tm.tm_sec; + td.tm_min = tm.tm_min; + td.tm_hour = tm.tm_hour; + td.tm_mday = tm.tm_mday; + td.tm_mon = tm.tm_mon; + td.tm_year = tm.tm_year; +} + +FilesystemFactory *OSystem_Android::getFilesystemFactory() { + return _fsFactory; +} + +void OSystem_Android::addSysArchivesToSearchSet(Common::SearchSet &s, + int priority) { + s.add("ASSET", _asset_archive, priority, false); + + JNIEnv* env = JNU_GetEnv(); + + jobjectArray array = + (jobjectArray)env->CallObjectMethod(_back_ptr, MID_getSysArchives); + if (env->ExceptionCheck()) { + warning("Error finding system archive path"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return; + } + + jsize size = env->GetArrayLength(array); + for (jsize i = 0; i < size; ++i) { + jstring path_obj = (jstring)env->GetObjectArrayElement(array, i); + const char* path = env->GetStringUTFChars(path_obj, NULL); + if (path != NULL) { + s.addDirectory(path, path, priority); + env->ReleaseStringUTFChars(path_obj, path); + } + env->DeleteLocalRef(path_obj); + } +} + + +static jint ScummVM_scummVMMain(JNIEnv* env, jobject self, jobjectArray args) { + OSystem_Android* cpp_obj = OSystem_Android::fromJavaObject(env, self); + + const int MAX_NARGS = 32; + int res = -1; + + int argc = env->GetArrayLength(args); + if (argc > MAX_NARGS) { + JNU_ThrowByName(env, "java/lang/IllegalArgumentException", + "too many arguments"); + return 0; + } + + char* argv[MAX_NARGS]; + int nargs; // note use in cleanup loop below + for (nargs = 0; nargs < argc; ++nargs) { + jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); + if (arg == NULL) { + argv[nargs] = NULL; + } else { + const char* cstr = env->GetStringUTFChars(arg, NULL); + argv[nargs] = const_cast(cstr); + if (cstr == NULL) + goto cleanup; // exception already thrown + } + env->DeleteLocalRef(arg); + } + + g_system = cpp_obj; + assert(g_system); + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, + "Entering scummvm_main with %d args", argc); + res = scummvm_main(argc, argv); + __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "Exiting scummvm_main"); + g_system->quit(); + +cleanup: + nargs--; + for (int i = 0; i < nargs; ++i) { + if (argv[i] == NULL) + continue; + jstring arg = (jstring)env->GetObjectArrayElement(args, nargs); + if (arg == NULL) + // Exception already thrown + return res; + env->ReleaseStringUTFChars(arg, argv[i]); + env->DeleteLocalRef(arg); + } + + return res; +} + +#ifdef DYNAMIC_MODULES +void AndroidPluginProvider::addCustomDirectories(Common::FSList &dirs) const { + OSystem_Android* g_system_android = (OSystem_Android*)g_system; + g_system_android->addPluginDirectories(dirs); +} +#endif + +const static JNINativeMethod gMethods[] = { + { "create", "(Landroid/content/res/AssetManager;)V", + (void*)ScummVM_create }, + { "nativeDestroy", "()V", (void*)ScummVM_nativeDestroy }, + { "scummVMMain", "([Ljava/lang/String;)I", + (void*)ScummVM_scummVMMain }, + { "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V", + (void*)ScummVM_pushEvent }, + { "audioMixCallback", "([B)V", + (void*)ScummVM_audioMixCallback }, + { "setConfMan", "(Ljava/lang/String;I)V", + (void*)ScummVM_setConfManInt }, + { "setConfMan", "(Ljava/lang/String;Ljava/lang/String;)V", + (void*)ScummVM_setConfManString }, +}; + +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM* jvm, void* reserved) { + cached_jvm = jvm; + + JNIEnv* env; + if (jvm->GetEnv((void**)&env, JNI_VERSION_1_2)) + return JNI_ERR; + + jclass cls = env->FindClass("org/inodes/gus/scummvm/ScummVM"); + if (cls == NULL) + return JNI_ERR; + if (env->RegisterNatives(cls, gMethods, ARRAYSIZE(gMethods)) < 0) + return JNI_ERR; + + FID_ScummVM_nativeScummVM = env->GetFieldID(cls, "nativeScummVM", "J"); + if (FID_ScummVM_nativeScummVM == NULL) + return JNI_ERR; + + jclass event = env->FindClass("org/inodes/gus/scummvm/Event"); + if (event == NULL) + return JNI_ERR; + FID_Event_type = env->GetFieldID(event, "type", "I"); + if (FID_Event_type == NULL) + return JNI_ERR; + FID_Event_synthetic = env->GetFieldID(event, "synthetic", "Z"); + if (FID_Event_synthetic == NULL) + return JNI_ERR; + FID_Event_kbd_keycode = env->GetFieldID(event, "kbd_keycode", "I"); + if (FID_Event_kbd_keycode == NULL) + return JNI_ERR; + FID_Event_kbd_ascii = env->GetFieldID(event, "kbd_ascii", "I"); + if (FID_Event_kbd_ascii == NULL) + return JNI_ERR; + FID_Event_kbd_flags = env->GetFieldID(event, "kbd_flags", "I"); + if (FID_Event_kbd_flags == NULL) + return JNI_ERR; + FID_Event_mouse_x = env->GetFieldID(event, "mouse_x", "I"); + if (FID_Event_mouse_x == NULL) + return JNI_ERR; + FID_Event_mouse_y = env->GetFieldID(event, "mouse_y", "I"); + if (FID_Event_mouse_y == NULL) + return JNI_ERR; + FID_Event_mouse_relative = env->GetFieldID(event, "mouse_relative", "Z"); + if (FID_Event_mouse_relative == NULL) + return JNI_ERR; + + cls = env->FindClass("java/lang/Object"); + if (cls == NULL) + return JNI_ERR; + MID_Object_wait = env->GetMethodID(cls, "wait", "()V"); + if (MID_Object_wait == NULL) + return JNI_ERR; + + return JNI_VERSION_1_2; +} + +#endif diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk new file mode 100644 index 00000000000..0bc8fa265ee --- /dev/null +++ b/backends/platform/android/android.mk @@ -0,0 +1,52 @@ +# Android specific build targets + +AAPT = aapt +DX = dx +APKBUILDER = apkbuilder +ADB = adb -e +ANDROID_JAR = $(ANDROID_SDK)/platforms/android-1.6/android.jar +JAVAC ?= javac +JAVACFLAGS = -source 1.5 -target 1.5 + +# FIXME: find/mark plugin entry points and add all this back again: +#LDFLAGS += -Wl,--gc-sections +#CXXFLAGS += -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden + +scummvm.apk: build.tmp/libscummvm.so resources.ap_ classes.dex + # Package installer won't delete old libscummvm.so on upgrade so + # replace it with a zero size file + $(INSTALL) -d build.stage/common/lib/armeabi + touch build.stage/common/lib/armeabi/libscummvm.so + # We now handle the library unpacking ourselves from mylib/ + $(INSTALL) -d build.stage/common/mylib/armeabi + $(INSTALL) -c -m 644 build.tmp/libscummvm.so build.stage/common/mylib/armeabi/ + $(STRIP) build.stage/common/mylib/armeabi/libscummvm.so + # "-nf lib/armeabi/libscummvm.so" builds bogus paths? + $(APKBUILDER) $@ -z resources.ap_ -f classes.dex -rf build.stage/common || { $(RM) $@; exit 1; } + +scummvm-engine-%.apk: plugins/lib%.so build.tmp/%/resources.ap_ build.tmp/plugins/classes.dex + $(INSTALL) -d build.stage/$*/apk/mylib/armeabi/ + $(INSTALL) -c -m 644 plugins/lib$*.so build.stage/$*/apk/mylib/armeabi/ + $(STRIP) build.stage/$*/apk/mylib/armeabi/lib$*.so + $(APKBUILDER) $@ -z build.tmp/$*/resources.ap_ -f build.tmp/plugins/classes.dex -rf build.stage/$*/apk || { $(RM) $@; exit 1; } + +release/%.apk: %.apk + @$(MKDIR) -p $(@D) + @$(RM) $@ + $(CP) $< $@.tmp + # remove debugging signature + zip -d $@.tmp META-INF/\* + jarsigner $(JARSIGNER_FLAGS) $@.tmp release + zipalign 4 $@.tmp $@ + $(RM) $@.tmp + +androidrelease: release/scummvm.apk $(patsubst plugins/lib%.so,release/scummvm-engine-%.apk,$(PLUGINS)) + +androidtest: scummvm.apk scummvm-engine-scumm.apk scummvm-engine-kyra.apk + @set -e; for apk in $^; do \ + echo $(ADB) install -r $$apk; \ + $(ADB) install -r $$apk; \ + done + $(ADB) shell am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n org.inodes.gus.scummvm/.Unpacker + +.PHONY: androidrelease androidtest diff --git a/backends/platform/android/asset-archive.cpp b/backends/platform/android/asset-archive.cpp new file mode 100644 index 00000000000..20c6a653c01 --- /dev/null +++ b/backends/platform/android/asset-archive.cpp @@ -0,0 +1,414 @@ +/* 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$ + * + */ + +#if defined(ANDROID) + +#include + +#include +#include + +#include "common/str.h" +#include "common/stream.h" +#include "common/util.h" +#include "common/archive.h" +#include "common/debug.h" + +#include "backends/platform/android/asset-archive.h" + +extern JNIEnv* JNU_GetEnv(); + +// Must match android.content.res.AssetManager.ACCESS_* +const jint ACCESS_UNKNOWN = 0; +const jint ACCESS_RANDOM = 1; + +// This might be useful to someone else. Assumes markSupported() == true. +class JavaInputStream : public Common::SeekableReadStream { +public: + JavaInputStream(JNIEnv* env, jobject is); + virtual ~JavaInputStream(); + virtual bool eos() const { return _eos; } + virtual bool err() const { return _err; } + virtual void clearErr() { _eos = _err = false; } + virtual uint32 read(void *dataPtr, uint32 dataSize); + virtual int32 pos() const { return _pos; } + virtual int32 size() const { return _len; } + virtual bool seek(int32 offset, int whence = SEEK_SET); +private: + void close(JNIEnv* env); + jmethodID MID_mark; + jmethodID MID_available; + jmethodID MID_close; + jmethodID MID_read; + jmethodID MID_reset; + jmethodID MID_skip; + jobject _input_stream; + jsize _buflen; + jbyteArray _buf; + uint32 _pos; + jint _len; + bool _eos; + bool _err; +}; + +JavaInputStream::JavaInputStream(JNIEnv* env, jobject is) : + _eos(false), _err(false), _pos(0) +{ + _input_stream = env->NewGlobalRef(is); + _buflen = 8192; + _buf = static_cast(env->NewGlobalRef(env->NewByteArray(_buflen))); + + jclass cls = env->GetObjectClass(_input_stream); + MID_mark = env->GetMethodID(cls, "mark", "(I)V"); + assert(MID_mark); + MID_available = env->GetMethodID(cls, "available", "()I"); + assert(MID_mark); + MID_close = env->GetMethodID(cls, "close", "()V"); + assert(MID_close); + MID_read = env->GetMethodID(cls, "read", "([BII)I"); + assert(MID_read); + MID_reset = env->GetMethodID(cls, "reset", "()V"); + assert(MID_reset); + MID_skip = env->GetMethodID(cls, "skip", "(J)J"); + assert(MID_skip); + + // Mark start of stream, so we can reset back to it. + // readlimit is set to something bigger than anything we might + // want to seek within. + env->CallVoidMethod(_input_stream, MID_mark, 10*1024*1024); + _len = env->CallIntMethod(_input_stream, MID_available); +} + +JavaInputStream::~JavaInputStream() { + JNIEnv* env = JNU_GetEnv(); + close(env); + env->DeleteGlobalRef(_buf); + env->DeleteGlobalRef(_input_stream); +} + +void JavaInputStream::close(JNIEnv* env) { + env->CallVoidMethod(_input_stream, MID_close); + if (env->ExceptionCheck()) + env->ExceptionClear(); +} + +uint32 JavaInputStream::read(void *dataPtr, uint32 dataSize) { + JNIEnv* env = JNU_GetEnv(); + + if (_buflen < dataSize) { + _buflen = dataSize; + env->DeleteGlobalRef(_buf); + _buf = static_cast(env->NewGlobalRef(env->NewByteArray(_buflen))); + } + + jint ret = env->CallIntMethod(_input_stream, MID_read, _buf, 0, dataSize); + if (env->ExceptionCheck()) { + warning("Exception during JavaInputStream::read(%p, %d)", + dataPtr, dataSize); + env->ExceptionDescribe(); + env->ExceptionClear(); + _err = true; + ret = -1; + } else if (ret == -1) { + _eos = true; + ret = 0; + } else { + env->GetByteArrayRegion(_buf, 0, ret, static_cast(dataPtr)); + _pos += ret; + } + return ret; +} + +bool JavaInputStream::seek(int32 offset, int whence) { + JNIEnv* env = JNU_GetEnv(); + uint32 newpos; + switch (whence) { + case SEEK_SET: + newpos = offset; + break; + case SEEK_CUR: + newpos = _pos + offset; + break; + case SEEK_END: + newpos = _len + offset; + break; + default: + debug("Unknown 'whence' arg %d", whence); + return false; + } + + jlong skip_bytes; + if (newpos > _pos) { + skip_bytes = newpos - _pos; + } else { + // Can't skip backwards, so jump back to start and skip from there. + env->CallVoidMethod(_input_stream, MID_reset); + if (env->ExceptionCheck()) { + warning("Failed to rewind to start of asset stream"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return false; + } + _pos = 0; + skip_bytes = newpos; + } + + while (skip_bytes > 0) { + jlong ret = env->CallLongMethod(_input_stream, MID_skip, skip_bytes); + if (env->ExceptionCheck()) { + warning("Failed to skip %ld bytes into asset stream", + static_cast(skip_bytes)); + env->ExceptionDescribe(); + env->ExceptionClear(); + return false; + } else if (ret == 0) { + warning("InputStream->skip(%ld) didn't skip any bytes. Aborting seek.", + static_cast(skip_bytes)); + return false; // No point looping forever... + } + _pos += ret; + skip_bytes -= ret; + } + _eos = false; + return true; +} + + +// Must match android.content.res.AssetFileDescriptor.UNKNOWN_LENGTH +const jlong UNKNOWN_LENGTH = -1; + +// Reading directly from a fd is so much more efficient, that it is +// worth optimising for. +class AssetFdReadStream : public Common::SeekableReadStream { +public: + AssetFdReadStream(JNIEnv* env, jobject assetfd); + virtual ~AssetFdReadStream(); + virtual bool eos() const { return _eos; } + virtual bool err() const { return _err; } + virtual void clearErr() { _eos = _err = false; } + virtual uint32 read(void *dataPtr, uint32 dataSize); + virtual int32 pos() const { return _pos; } + virtual int32 size() const { return _declared_len; } + virtual bool seek(int32 offset, int whence = SEEK_SET); +private: + void close(JNIEnv* env); + int _fd; + jmethodID MID_close; + jobject _assetfd; + jlong _start_off; + jlong _declared_len; + uint32 _pos; + bool _eos; + bool _err; +}; + +AssetFdReadStream::AssetFdReadStream(JNIEnv* env, jobject assetfd) : + _eos(false), _err(false), _pos(0) +{ + _assetfd = env->NewGlobalRef(assetfd); + + jclass cls = env->GetObjectClass(_assetfd); + MID_close = env->GetMethodID(cls, "close", "()V"); + assert(MID_close); + + jmethodID MID_getStartOffset = + env->GetMethodID(cls, "getStartOffset", "()J"); + assert(MID_getStartOffset); + _start_off = env->CallLongMethod(_assetfd, MID_getStartOffset); + + jmethodID MID_getDeclaredLength = + env->GetMethodID(cls, "getDeclaredLength", "()J"); + assert(MID_getDeclaredLength); + _declared_len = env->CallLongMethod(_assetfd, MID_getDeclaredLength); + + jmethodID MID_getFileDescriptor = + env->GetMethodID(cls, "getFileDescriptor", "()Ljava/io/FileDescriptor;"); + assert(MID_getFileDescriptor); + jobject javafd = env->CallObjectMethod(_assetfd, MID_getFileDescriptor); + assert(javafd); + jclass fd_cls = env->GetObjectClass(javafd); + jfieldID FID_descriptor = env->GetFieldID(fd_cls, "descriptor", "I"); + assert(FID_descriptor); + _fd = env->GetIntField(javafd, FID_descriptor); +} + +AssetFdReadStream::~AssetFdReadStream() { + JNIEnv* env = JNU_GetEnv(); + env->CallVoidMethod(_assetfd, MID_close); + if (env->ExceptionCheck()) + env->ExceptionClear(); + env->DeleteGlobalRef(_assetfd); +} + +uint32 AssetFdReadStream::read(void *dataPtr, uint32 dataSize) { + if (_declared_len != UNKNOWN_LENGTH) { + jlong cap = _declared_len - _pos; + if (dataSize > cap) + dataSize = cap; + } + int ret = ::read(_fd, dataPtr, dataSize); + if (ret == 0) + _eos = true; + else if (ret == -1) + _err = true; + else + _pos += ret; + return ret; +} + +bool AssetFdReadStream::seek(int32 offset, int whence) { + if (whence == SEEK_SET) { + if (_declared_len != UNKNOWN_LENGTH && offset > _declared_len) + offset = _declared_len; + offset += _start_off; + } else if (whence == SEEK_END && _declared_len != UNKNOWN_LENGTH) { + whence = SEEK_SET; + offset = _start_off + _declared_len + offset; + } + int ret = lseek(_fd, offset, whence); + if (ret == -1) + return false; + _pos = ret - _start_off; + _eos = false; + return true; +} + +AndroidAssetArchive::AndroidAssetArchive(jobject am) { + JNIEnv* env = JNU_GetEnv(); + _am = env->NewGlobalRef(am); + + jclass cls = env->GetObjectClass(_am); + MID_open = env->GetMethodID(cls, "open", + "(Ljava/lang/String;I)Ljava/io/InputStream;"); + assert(MID_open); + MID_openFd = env->GetMethodID(cls, "openFd", + "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); + assert(MID_openFd); + MID_list = env->GetMethodID(cls, "list", + "(Ljava/lang/String;)[Ljava/lang/String;"); + assert(MID_list); +} + +AndroidAssetArchive::~AndroidAssetArchive() { + JNIEnv* env = JNU_GetEnv(); + env->DeleteGlobalRef(_am); +} + +bool AndroidAssetArchive::hasFile(const Common::String &name) { + JNIEnv* env = JNU_GetEnv(); + jstring path = env->NewStringUTF(name.c_str()); + jobject result = env->CallObjectMethod(_am, MID_open, path, ACCESS_UNKNOWN); + if (env->ExceptionCheck()) { + // Assume FileNotFoundException + //warning("Error while calling AssetManager->open(%s)", name.c_str()); + //env->ExceptionDescribe(); + env->ExceptionClear(); + env->DeleteLocalRef(path); + return false; + } + env->DeleteLocalRef(result); + env->DeleteLocalRef(path); + return true; +} + +int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) { + JNIEnv* env = JNU_GetEnv(); + Common::List dirlist; + dirlist.push_back(""); + + int count = 0; + while (!dirlist.empty()) { + const Common::String dir = dirlist.back(); + dirlist.pop_back(); + + jstring jpath = env->NewStringUTF(dir.c_str()); + jobjectArray jpathlist = static_cast(env->CallObjectMethod(_am, MID_list, jpath)); + if (env->ExceptionCheck()) { + warning("Error while calling AssetManager->list(%s). Ignoring.", + dir.c_str()); + env->ExceptionDescribe(); + env->ExceptionClear(); + continue; // May as well keep going ... + } + env->DeleteLocalRef(jpath); + + for (jsize i = 0; i < env->GetArrayLength(jpathlist); ++i) { + jstring elem = (jstring)env->GetObjectArrayElement(jpathlist, i); + const char* p = env->GetStringUTFChars(elem, NULL); + Common::String thispath = dir; + if (!thispath.empty()) + thispath += "/"; + thispath += p; + + // Assume files have a . in them, and directories don't + if (strchr(p, '.')) { + member_list.push_back(getMember(thispath)); + ++count; + } else + dirlist.push_back(thispath); + + env->ReleaseStringUTFChars(elem, p); + env->DeleteLocalRef(elem); + } + + env->DeleteLocalRef(jpathlist); + } + + return count; +} + +Common::ArchiveMemberPtr AndroidAssetArchive::getMember(const Common::String &name) { + return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this)); +} + +Common::SeekableReadStream *AndroidAssetArchive::createReadStreamForMember(const Common::String &path) const { + JNIEnv* env = JNU_GetEnv(); + jstring jpath = env->NewStringUTF(path.c_str()); + + // Try openFd() first ... + jobject afd = env->CallObjectMethod(_am, MID_openFd, jpath); + if (env->ExceptionCheck()) + env->ExceptionClear(); + else if (afd != NULL) { + // success :) + env->DeleteLocalRef(jpath); + return new AssetFdReadStream(env, afd); + } + + // ... and fallback to normal open() if that doesn't work + jobject is = env->CallObjectMethod(_am, MID_open, jpath, ACCESS_RANDOM); + if (env->ExceptionCheck()) { + // Assume FileNotFoundException + //warning("Error opening %s", path.c_str()); + //env->ExceptionDescribe(); + env->ExceptionClear(); + env->DeleteLocalRef(jpath); + return NULL; + } + + return new JavaInputStream(env, is); +} + +#endif diff --git a/backends/platform/android/asset-archive.h b/backends/platform/android/asset-archive.h new file mode 100644 index 00000000000..b3f6993c50f --- /dev/null +++ b/backends/platform/android/asset-archive.h @@ -0,0 +1,53 @@ +/* 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$ + * + */ + +#if defined(ANDROID) + +#include + +#include "common/str.h" +#include "common/stream.h" +#include "common/util.h" +#include "common/archive.h" + +class AndroidAssetArchive : public Common::Archive { +public: + AndroidAssetArchive(jobject am); + virtual ~AndroidAssetArchive(); + + virtual bool hasFile(const Common::String &name); + virtual int listMembers(Common::ArchiveMemberList &list); + virtual Common::ArchiveMemberPtr getMember(const Common::String &name); + virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; + +private: + jmethodID MID_open; + jmethodID MID_openFd; + jmethodID MID_list; + + jobject _am; +}; + +#endif diff --git a/backends/platform/android/module.mk b/backends/platform/android/module.mk new file mode 100644 index 00000000000..fdb0ed2ac42 --- /dev/null +++ b/backends/platform/android/module.mk @@ -0,0 +1,85 @@ +MODULE := backends/platform/android + +MODULE_OBJS := \ + android.o asset-archive.o video.o + +MODULE_DIRS += \ + backends/platform/android/ + +# We don't use the rules.mk here on purpose +OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) + +JAVA_SRC = \ + $(MODULE)/org/inodes/gus/scummvm/ScummVM.java \ + $(MODULE)/org/inodes/gus/scummvm/ScummVMApplication.java \ + $(MODULE)/org/inodes/gus/scummvm/ScummVMActivity.java \ + $(MODULE)/org/inodes/gus/scummvm/EditableSurfaceView.java \ + $(MODULE)/org/inodes/gus/scummvm/Unpacker.java \ + $(MODULE)/org/inodes/gus/scummvm/Manifest.java \ + $(MODULE)/org/inodes/gus/scummvm/R.java + +JAVA_PLUGIN_SRC = \ + $(MODULE)/org/inodes/gus/scummvm/PluginProvider.java + +RESOURCES = \ + $(srcdir)/dists/android/res/values/strings.xml \ + $(srcdir)/dists/android/res/layout/main.xml \ + $(srcdir)/dists/android/res/layout/splash.xml \ + $(srcdir)/dists/android/res/drawable/gradient.xml \ + $(srcdir)/dists/android/res/drawable/scummvm.png \ + $(srcdir)/dists/android/res/drawable/scummvm_big.png + +ASSETS = $(DIST_FILES_ENGINEDATA) $(DIST_FILES_THEMES) + +PLUGIN_RESOURCES = \ + $(srcdir)/dists/android/res/values/strings.xml \ + $(srcdir)/dists/android/res/drawable/scummvm.png + +# These must be incremented for each market upload +#ANDROID_VERSIONCODE = 6 Specified in dists/android/AndroidManifest.xml.in +ANDROID_PLUGIN_VERSIONCODE = 6 + +# This library contains scummvm proper +build.tmp/libscummvm.so: $(OBJS) + @$(MKDIR) -p $(@D) + $(CXX) $(PLUGIN_LDFLAGS) -shared $(LDFLAGS) -Wl,-soname,$(@F) -Wl,--no-undefined -o $@ $(PRE_OBJS_FLAGS) $(OBJS) $(POST_OBJS_FLAGS) $(LIBS) + + +backends/platform/android/org/inodes/gus/scummvm/R.java backends/platform/android/org/inodes/gus/scummvm/Manifest.java: $(srcdir)/dists/android/AndroidManifest.xml $(filter %.xml,$(RESOURCES)) $(ANDROID_JAR) + $(AAPT) package -m -J backends/platform/android -M $< -S $(srcdir)/dists/android/res -I $(ANDROID_JAR) + +build.tmp/classes/%.class: $(srcdir)/backends/platform/android/%.java $(srcdir)/backends/platform/android/org/inodes/gus/scummvm/R.java + @$(MKDIR) -p $(@D) + $(JAVAC) $(JAVACFLAGS) -cp $(srcdir)/backends/platform/android -d build.tmp/classes -bootclasspath $(ANDROID_JAR) $< + +build.tmp/classes.plugin/%.class: $(srcdir)/backends/platform/android/%.java + @$(MKDIR) -p $(@D) + $(JAVAC) $(JAVACFLAGS) -cp $(srcdir)/backends/platform/android -d build.tmp/classes.plugin -bootclasspath $(ANDROID_JAR) $< + +classes.dex: $(JAVA_SRC:backends/platform/android/%.java=build.tmp/classes/%.class) + $(DX) --dex --output=$@ build.tmp/classes + +build.tmp/plugins/classes.dex: $(JAVA_PLUGIN_SRC:backends/platform/android/%.java=build.tmp/classes.plugin/%.class) + @$(MKDIR) -p $(@D) + $(DX) --dex --output=$@ build.tmp/classes.plugin + +resources.ap_: $(srcdir)/dists/android/AndroidManifest.xml $(RESOURCES) $(ASSETS) $(ANDROID_JAR) $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) + $(INSTALL) -d build.tmp/assets/ + $(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) build.tmp/assets/ + $(AAPT) package -f -M $< -S $(srcdir)/dists/android/res -A build.tmp/assets -I $(ANDROID_JAR) -F $@ + +build.tmp/%/resources.ap_: build.tmp/%/AndroidManifest.xml build.stage/%/res/values/strings.xml build.stage/%/res/drawable/scummvm.png $(ANDROID_JAR) + $(AAPT) package -f -M $< -S build.stage/$*/res -I $(ANDROID_JAR) -F $@ + +build.tmp/%/AndroidManifest.xml build.stage/%/res/values/strings.xml: dists/android/mkmanifest.pl configure dists/android/AndroidManifest.xml + dists/android/mkmanifest.pl --id=$* --configure=configure \ + --version-name=$(VERSION) \ + --version-code=$(ANDROID_PLUGIN_VERSIONCODE) \ + --stringres=build.stage/$*/res/values/strings.xml \ + --manifest=build.tmp/$*/AndroidManifest.xml \ + --master-manifest=dists/android/AndroidManifest.xml \ + --unpacklib=mylib/armeabi/lib$*.so + +build.stage/%/res/drawable/scummvm.png: dists/android/res/drawable/scummvm.png + @$(MKDIR) -p $(@D) + $(CP) $< $@ diff --git a/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java b/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java new file mode 100644 index 00000000000..5b71d4a3a5b --- /dev/null +++ b/backends/platform/android/org/inodes/gus/scummvm/EditableSurfaceView.java @@ -0,0 +1,59 @@ +package org.inodes.gus.scummvm; + +import android.content.Context; +import android.text.InputType; +import android.util.AttributeSet; +import android.view.SurfaceView; +import android.view.inputmethod.BaseInputConnection; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethodManager; + +public class EditableSurfaceView extends SurfaceView { + public EditableSurfaceView(Context context) { + super(context); + } + + public EditableSurfaceView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public EditableSurfaceView(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public boolean onCheckIsTextEditor() { + return true; + } + + private class MyInputConnection extends BaseInputConnection { + public MyInputConnection() { + super(EditableSurfaceView.this, false); + } + + @Override + public boolean performEditorAction(int actionCode) { + if (actionCode == EditorInfo.IME_ACTION_DONE) { + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getWindowToken(), 0); + } + return super.performEditorAction(actionCode); // Sends enter key + } + } + + @Override + public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + outAttrs.initialCapsMode = 0; + outAttrs.initialSelEnd = outAttrs.initialSelStart = -1; + outAttrs.inputType = (InputType.TYPE_CLASS_TEXT | + InputType.TYPE_TEXT_VARIATION_NORMAL | + InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); + outAttrs.imeOptions = (EditorInfo.IME_ACTION_DONE | + EditorInfo.IME_FLAG_NO_EXTRACT_UI); + + return new MyInputConnection(); + } +} diff --git a/backends/platform/android/org/inodes/gus/scummvm/Event.java b/backends/platform/android/org/inodes/gus/scummvm/Event.java new file mode 100644 index 00000000000..f9c7aba93b0 --- /dev/null +++ b/backends/platform/android/org/inodes/gus/scummvm/Event.java @@ -0,0 +1,330 @@ +package org.inodes.gus.scummvm; + +import android.view.KeyEvent; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class Event { + // Common::EventType enum. + // Must be kept in sync with common/events.h + public final static int EVENT_INVALID = 0; + public final static int EVENT_KEYDOWN = 1; + public final static int EVENT_KEYUP = 2; + public final static int EVENT_MOUSEMOVE = 3; + public final static int EVENT_LBUTTONDOWN = 4; + public final static int EVENT_LBUTTONUP = 5; + public final static int EVENT_RBUTTONDOWN = 6; + public final static int EVENT_RBUTTONUP = 7; + public final static int EVENT_WHEELUP = 8; + public final static int EVENT_WHEELDOWN = 9; + public final static int EVENT_QUIT = 10; + public final static int EVENT_SCREEN_CHANGED = 11; + public final static int EVENT_PREDICTIVE_DIALOG = 12; + public final static int EVENT_MBUTTONDOWN = 13; + public final static int EVENT_MBUTTONUP = 14; + public final static int EVENT_MAINMENU = 15; + public final static int EVENT_RTL = 16; + + // common/keyboard.h + public final static int ASCII_F1 = 315; + public final static int ASCII_F2 = 316; + public final static int ASCII_F3 = 317; + public final static int ASCII_F4 = 318; + public final static int ASCII_F5 = 319; + public final static int ASCII_F6 = 320; + public final static int ASCII_F7 = 321; + public final static int ASCII_F8 = 322; + public final static int ASCII_F9 = 323; + public final static int ASCII_F10 = 324; + public final static int ASCII_F11 = 325; + public final static int ASCII_F12 = 326; + public final static int KBD_CTRL = 1 << 0; + public final static int KBD_ALT = 1 << 1; + public final static int KBD_SHIFT = 1 << 2; + + public final static int KEYCODE_INVALID = 0; + public final static int KEYCODE_BACKSPACE = 8; + public final static int KEYCODE_TAB = 9; + public final static int KEYCODE_CLEAR = 12; + public final static int KEYCODE_RETURN = 13; + public final static int KEYCODE_PAUSE = 19; + public final static int KEYCODE_ESCAPE = 27; + public final static int KEYCODE_SPACE = 32; + public final static int KEYCODE_EXCLAIM = 33; + public final static int KEYCODE_QUOTEDBL = 34; + public final static int KEYCODE_HASH = 35; + public final static int KEYCODE_DOLLAR = 36; + public final static int KEYCODE_AMPERSAND = 38; + public final static int KEYCODE_QUOTE = 39; + public final static int KEYCODE_LEFTPAREN = 40; + public final static int KEYCODE_RIGHTPAREN = 41; + public final static int KEYCODE_ASTERISK = 42; + public final static int KEYCODE_PLUS = 43; + public final static int KEYCODE_COMMA = 44; + public final static int KEYCODE_MINUS = 45; + public final static int KEYCODE_PERIOD = 46; + public final static int KEYCODE_SLASH = 47; + public final static int KEYCODE_0 = 48; + public final static int KEYCODE_1 = 49; + public final static int KEYCODE_2 = 50; + public final static int KEYCODE_3 = 51; + public final static int KEYCODE_4 = 52; + public final static int KEYCODE_5 = 53; + public final static int KEYCODE_6 = 54; + public final static int KEYCODE_7 = 55; + public final static int KEYCODE_8 = 56; + public final static int KEYCODE_9 = 57; + public final static int KEYCODE_COLON = 58; + public final static int KEYCODE_SEMICOLON = 59; + public final static int KEYCODE_LESS = 60; + public final static int KEYCODE_EQUALS = 61; + public final static int KEYCODE_GREATER = 62; + public final static int KEYCODE_QUESTION = 63; + public final static int KEYCODE_AT = 64; + public final static int KEYCODE_LEFTBRACKET = 91; + public final static int KEYCODE_BACKSLASH = 92; + public final static int KEYCODE_RIGHTBRACKET = 93; + public final static int KEYCODE_CARET = 94; + public final static int KEYCODE_UNDERSCORE = 95; + public final static int KEYCODE_BACKQUOTE = 96; + public final static int KEYCODE_a = 97; + public final static int KEYCODE_b = 98; + public final static int KEYCODE_c = 99; + public final static int KEYCODE_d = 100; + public final static int KEYCODE_e = 101; + public final static int KEYCODE_f = 102; + public final static int KEYCODE_g = 103; + public final static int KEYCODE_h = 104; + public final static int KEYCODE_i = 105; + public final static int KEYCODE_j = 106; + public final static int KEYCODE_k = 107; + public final static int KEYCODE_l = 108; + public final static int KEYCODE_m = 109; + public final static int KEYCODE_n = 110; + public final static int KEYCODE_o = 111; + public final static int KEYCODE_p = 112; + public final static int KEYCODE_q = 113; + public final static int KEYCODE_r = 114; + public final static int KEYCODE_s = 115; + public final static int KEYCODE_t = 116; + public final static int KEYCODE_u = 117; + public final static int KEYCODE_v = 118; + public final static int KEYCODE_w = 119; + public final static int KEYCODE_x = 120; + public final static int KEYCODE_y = 121; + public final static int KEYCODE_z = 122; + public final static int KEYCODE_DELETE = 127; + // Numeric keypad + public final static int KEYCODE_KP0 = 256; + public final static int KEYCODE_KP1 = 257; + public final static int KEYCODE_KP2 = 258; + public final static int KEYCODE_KP3 = 259; + public final static int KEYCODE_KP4 = 260; + public final static int KEYCODE_KP5 = 261; + public final static int KEYCODE_KP6 = 262; + public final static int KEYCODE_KP7 = 263; + public final static int KEYCODE_KP8 = 264; + public final static int KEYCODE_KP9 = 265; + public final static int KEYCODE_KP_PERIOD = 266; + public final static int KEYCODE_KP_DIVIDE = 267; + public final static int KEYCODE_KP_MULTIPLY = 268; + public final static int KEYCODE_KP_MINUS = 269; + public final static int KEYCODE_KP_PLUS = 270; + public final static int KEYCODE_KP_ENTER = 271; + public final static int KEYCODE_KP_EQUALS = 272; + // Arrows + Home/End pad + public final static int KEYCODE_UP = 273; + public final static int KEYCODE_DOWN = 274; + public final static int KEYCODE_RIGHT = 275; + public final static int KEYCODE_LEFT = 276; + public final static int KEYCODE_INSERT = 277; + public final static int KEYCODE_HOME = 278; + public final static int KEYCODE_END = 279; + public final static int KEYCODE_PAGEUP = 280; + public final static int KEYCODE_PAGEDOWN = 281; + // Function keys + public final static int KEYCODE_F1 = 282; + public final static int KEYCODE_F2 = 283; + public final static int KEYCODE_F3 = 284; + public final static int KEYCODE_F4 = 285; + public final static int KEYCODE_F5 = 286; + public final static int KEYCODE_F6 = 287; + public final static int KEYCODE_F7 = 288; + public final static int KEYCODE_F8 = 289; + public final static int KEYCODE_F9 = 290; + public final static int KEYCODE_F10 = 291; + public final static int KEYCODE_F11 = 292; + public final static int KEYCODE_F12 = 293; + public final static int KEYCODE_F13 = 294; + public final static int KEYCODE_F14 = 295; + public final static int KEYCODE_F15 = 296; + // Key state modifier keys + public final static int KEYCODE_NUMLOCK = 300; + public final static int KEYCODE_CAPSLOCK = 301; + public final static int KEYCODE_SCROLLOCK = 302; + public final static int KEYCODE_RSHIFT = 303; + public final static int KEYCODE_LSHIFT = 304; + public final static int KEYCODE_RCTRL = 305; + public final static int KEYCODE_LCTRL = 306; + public final static int KEYCODE_RALT = 307; + public final static int KEYCODE_LALT = 308; + public final static int KEYCODE_RMETA = 309; + public final static int KEYCODE_LMETA = 310; + public final static int KEYCODE_LSUPER = 311; // Left "Windows" key + public final static int KEYCODE_RSUPER = 312; // Right "Windows" key + public final static int KEYCODE_MODE = 313; // "Alt Gr" key + public final static int KEYCODE_COMPOSE = 314; // Multi-key compose key + // Miscellaneous function keys + public final static int KEYCODE_HELP = 315; + public final static int KEYCODE_PRINT = 316; + public final static int KEYCODE_SYSREQ = 317; + public final static int KEYCODE_BREAK = 318; + public final static int KEYCODE_MENU = 319; + public final static int KEYCODE_POWER = 320; // Power Macintosh power key + public final static int KEYCODE_EURO = 321; // Some european keyboards + public final static int KEYCODE_UNDO = 322; // Atari keyboard has Undo + + // Android KeyEvent keycode -> ScummVM keycode + public final static Map androidKeyMap; + static { + Map map = new HashMap(); + + map.put(KeyEvent.KEYCODE_DEL, KEYCODE_BACKSPACE); + map.put(KeyEvent.KEYCODE_TAB, KEYCODE_TAB); + map.put(KeyEvent.KEYCODE_CLEAR, KEYCODE_CLEAR); + map.put(KeyEvent.KEYCODE_ENTER, KEYCODE_RETURN); + //map.put(??, KEYCODE_PAUSE); + map.put(KeyEvent.KEYCODE_BACK, KEYCODE_ESCAPE); + map.put(KeyEvent.KEYCODE_SPACE, KEYCODE_SPACE); + //map.put(??, KEYCODE_EXCLAIM); + //map.put(??, KEYCODE_QUOTEDBL); + map.put(KeyEvent.KEYCODE_POUND, KEYCODE_HASH); + //map.put(??, KEYCODE_DOLLAR); + //map.put(??, KEYCODE_AMPERSAND); + map.put(KeyEvent.KEYCODE_APOSTROPHE, KEYCODE_QUOTE); + //map.put(??, KEYCODE_LEFTPAREN); + //map.put(??, KEYCODE_RIGHTPAREN); + //map.put(??, KEYCODE_ASTERISK); + map.put(KeyEvent.KEYCODE_PLUS, KEYCODE_PLUS); + map.put(KeyEvent.KEYCODE_COMMA, KEYCODE_COMMA); + map.put(KeyEvent.KEYCODE_MINUS, KEYCODE_MINUS); + map.put(KeyEvent.KEYCODE_PERIOD, KEYCODE_PERIOD); + map.put(KeyEvent.KEYCODE_SLASH, KEYCODE_SLASH); + map.put(KeyEvent.KEYCODE_0, KEYCODE_0); + map.put(KeyEvent.KEYCODE_1, KEYCODE_1); + map.put(KeyEvent.KEYCODE_2, KEYCODE_2); + map.put(KeyEvent.KEYCODE_3, KEYCODE_3); + map.put(KeyEvent.KEYCODE_4, KEYCODE_4); + map.put(KeyEvent.KEYCODE_5, KEYCODE_5); + map.put(KeyEvent.KEYCODE_6, KEYCODE_6); + map.put(KeyEvent.KEYCODE_7, KEYCODE_7); + map.put(KeyEvent.KEYCODE_8, KEYCODE_8); + map.put(KeyEvent.KEYCODE_9, KEYCODE_9); + //map.put(??, KEYCODE_COLON); + map.put(KeyEvent.KEYCODE_SEMICOLON, KEYCODE_SEMICOLON); + //map.put(??, KEYCODE_LESS); + map.put(KeyEvent.KEYCODE_EQUALS, KEYCODE_EQUALS); + //map.put(??, KEYCODE_GREATER); + //map.put(??, KEYCODE_QUESTION); + map.put(KeyEvent.KEYCODE_AT, KEYCODE_AT); + map.put(KeyEvent.KEYCODE_LEFT_BRACKET, KEYCODE_LEFTBRACKET); + map.put(KeyEvent.KEYCODE_BACKSLASH, KEYCODE_BACKSLASH); + map.put(KeyEvent.KEYCODE_RIGHT_BRACKET, KEYCODE_RIGHTBRACKET); + //map.put(??, KEYCODE_CARET); + //map.put(??, KEYCODE_UNDERSCORE); + //map.put(??, KEYCODE_BACKQUOTE); + map.put(KeyEvent.KEYCODE_A, KEYCODE_a); + map.put(KeyEvent.KEYCODE_B, KEYCODE_b); + map.put(KeyEvent.KEYCODE_C, KEYCODE_c); + map.put(KeyEvent.KEYCODE_D, KEYCODE_d); + map.put(KeyEvent.KEYCODE_E, KEYCODE_e); + map.put(KeyEvent.KEYCODE_F, KEYCODE_f); + map.put(KeyEvent.KEYCODE_G, KEYCODE_g); + map.put(KeyEvent.KEYCODE_H, KEYCODE_h); + map.put(KeyEvent.KEYCODE_I, KEYCODE_i); + map.put(KeyEvent.KEYCODE_J, KEYCODE_j); + map.put(KeyEvent.KEYCODE_K, KEYCODE_k); + map.put(KeyEvent.KEYCODE_L, KEYCODE_l); + map.put(KeyEvent.KEYCODE_M, KEYCODE_m); + map.put(KeyEvent.KEYCODE_N, KEYCODE_n); + map.put(KeyEvent.KEYCODE_O, KEYCODE_o); + map.put(KeyEvent.KEYCODE_P, KEYCODE_p); + map.put(KeyEvent.KEYCODE_Q, KEYCODE_q); + map.put(KeyEvent.KEYCODE_R, KEYCODE_r); + map.put(KeyEvent.KEYCODE_S, KEYCODE_s); + map.put(KeyEvent.KEYCODE_T, KEYCODE_t); + map.put(KeyEvent.KEYCODE_U, KEYCODE_u); + map.put(KeyEvent.KEYCODE_V, KEYCODE_v); + map.put(KeyEvent.KEYCODE_W, KEYCODE_w); + map.put(KeyEvent.KEYCODE_X, KEYCODE_x); + map.put(KeyEvent.KEYCODE_Y, KEYCODE_y); + map.put(KeyEvent.KEYCODE_Z, KEYCODE_z); + //map.put(KeyEvent.KEYCODE_DEL, KEYCODE_DELETE); use BACKSPACE instead + //map.put(??, KEYCODE_KP_*); + map.put(KeyEvent.KEYCODE_DPAD_UP, KEYCODE_UP); + map.put(KeyEvent.KEYCODE_DPAD_DOWN, KEYCODE_DOWN); + map.put(KeyEvent.KEYCODE_DPAD_RIGHT, KEYCODE_RIGHT); + map.put(KeyEvent.KEYCODE_DPAD_LEFT, KEYCODE_LEFT); + //map.put(??, KEYCODE_INSERT); + //map.put(??, KEYCODE_HOME); + //map.put(??, KEYCODE_END); + //map.put(??, KEYCODE_PAGEUP); + //map.put(??, KEYCODE_PAGEDOWN); + //map.put(??, KEYCODE_F{1-15}); + map.put(KeyEvent.KEYCODE_NUM, KEYCODE_NUMLOCK); + //map.put(??, KEYCODE_CAPSLOCK); + //map.put(??, KEYCODE_SCROLLLOCK); + map.put(KeyEvent.KEYCODE_SHIFT_RIGHT, KEYCODE_RSHIFT); + map.put(KeyEvent.KEYCODE_SHIFT_LEFT, KEYCODE_LSHIFT); + //map.put(??, KEYCODE_RCTRL); + //map.put(??, KEYCODE_LCTRL); + map.put(KeyEvent.KEYCODE_ALT_RIGHT, KEYCODE_RALT); + map.put(KeyEvent.KEYCODE_ALT_LEFT, KEYCODE_LALT); + // ?? META, SUPER + // ?? MODE, COMPOSE + // ?? HELP, PRINT, SYSREQ, BREAK, EURO, UNDO + map.put(KeyEvent.KEYCODE_MENU, KEYCODE_MENU); + map.put(KeyEvent.KEYCODE_POWER, KEYCODE_POWER); + + androidKeyMap = Collections.unmodifiableMap(map); + } + + public int type; + public boolean synthetic; + public int kbd_keycode; + public int kbd_ascii; + public int kbd_flags; + public int mouse_x; + public int mouse_y; + public boolean mouse_relative; // Used for trackball events + + public Event() { + type = EVENT_INVALID; + synthetic = false; + } + + public Event(int type) { + this.type = type; + synthetic = false; + } + + public static Event KeyboardEvent(int type, int keycode, int ascii, + int flags) { + Event e = new Event(); + e.type = type; + e.kbd_keycode = keycode; + e.kbd_ascii = ascii; + e.kbd_flags = flags; + return e; + } + + public static Event MouseEvent(int type, int x, int y) { + Event e = new Event(); + e.type = type; + e.mouse_x = x; + e.mouse_y = y; + return e; + } +} diff --git a/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java b/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java new file mode 100644 index 00000000000..b4035a296b1 --- /dev/null +++ b/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java @@ -0,0 +1,52 @@ +package org.inodes.gus.scummvm; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; + +import java.util.ArrayList; + +public class PluginProvider extends BroadcastReceiver { + public final static String META_UNPACK_LIB = + "org.inodes.gus.scummvm.meta.UNPACK_LIB"; + + public void onReceive(Context context, Intent intent) { + if (!intent.getAction().equals(ScummVMApplication.ACTION_PLUGIN_QUERY)) + return; + + Bundle extras = getResultExtras(true); + + final ActivityInfo info; + try { + info = context.getPackageManager() + .getReceiverInfo(new ComponentName(context, this.getClass()), + PackageManager.GET_META_DATA); + } catch (PackageManager.NameNotFoundException e) { + Log.e(this.toString(), "Error finding my own info?", e); + return; + } + + String mylib = info.metaData.getString(META_UNPACK_LIB); + if (mylib != null) { + ArrayList all_libs = + extras.getStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS); + + all_libs.add(new Uri.Builder() + .scheme("plugin") + .authority(context.getPackageName()) + .path(mylib) + .toString()); + + extras.putStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS, + all_libs); + } + + setResultExtras(extras); + } +} diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java new file mode 100644 index 00000000000..bc0c5ef408f --- /dev/null +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -0,0 +1,317 @@ +package org.inodes.gus.scummvm; + +import android.content.Context; +import android.content.res.AssetManager; +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioTrack; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Process; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; + +import java.io.File; +import java.util.concurrent.Semaphore; + + +// At least in Android 2.1, eglCreateWindowSurface() requires an +// EGLNativeWindowSurface object, which is hidden deep in the bowels +// of libui. Until EGL is properly exposed, it's probably safer to +// use the Java versions of most EGL functions :( + +public class ScummVM implements SurfaceHolder.Callback { + private final static String LOG_TAG = "ScummVM.java"; + + private final int AUDIO_FRAME_SIZE = 2 * 2; // bytes. 16bit audio * stereo + public static class AudioSetupException extends Exception {} + + private long nativeScummVM; // native code hangs itself here + boolean scummVMRunning = false; + + private native void create(AssetManager am); + + public ScummVM(Context context) { + create(context.getAssets()); // Init C++ code, set nativeScummVM + } + + private native void nativeDestroy(); + + public synchronized void destroy() { + if (nativeScummVM != 0) { + nativeDestroy(); + nativeScummVM = 0; + } + } + protected void finalize() { + destroy(); + } + + // Surface creation: + // GUI thread: create surface, release lock + // ScummVM thread: acquire lock (block), read surface + // + // Surface deletion: + // GUI thread: post event, acquire lock (block), return + // ScummVM thread: read event, free surface, release lock + // + // In other words, ScummVM thread does this: + // acquire lock + // setup surface + // when SCREEN_CHANGED arrives: + // destroy surface + // release lock + // back to acquire lock + static final int configSpec[] = { + EGL10.EGL_RED_SIZE, 5, + EGL10.EGL_GREEN_SIZE, 5, + EGL10.EGL_BLUE_SIZE, 5, + EGL10.EGL_DEPTH_SIZE, 0, + EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT, + EGL10.EGL_NONE, + }; + EGL10 egl; + EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY; + EGLConfig eglConfig; + EGLContext eglContext = EGL10.EGL_NO_CONTEXT; + EGLSurface eglSurface = EGL10.EGL_NO_SURFACE; + Semaphore surfaceLock = new Semaphore(0, true); + SurfaceHolder nativeSurface; + + public void surfaceCreated(SurfaceHolder holder) { + nativeSurface = holder; + surfaceLock.release(); + } + + public void surfaceChanged(SurfaceHolder holder, int format, + int width, int height) { + // Disabled while I debug GL problems + //pushEvent(new Event(Event.EVENT_SCREEN_CHANGED)); + } + + public void surfaceDestroyed(SurfaceHolder holder) { + pushEvent(new Event(Event.EVENT_SCREEN_CHANGED)); + try { + surfaceLock.acquire(); + } catch (InterruptedException e) { + Log.e(this.toString(), + "Interrupted while waiting for surface lock", e); + } + } + + // Called by ScummVM thread (from initBackend) + private void createScummVMGLContext() { + egl = (EGL10)EGLContext.getEGL(); + eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + int[] version = new int[2]; + egl.eglInitialize(eglDisplay, version); + int[] num_config = new int[1]; + egl.eglChooseConfig(eglDisplay, configSpec, null, 0, num_config); + + final int numConfigs = num_config[0]; + if (numConfigs <= 0) + throw new IllegalArgumentException("No configs match configSpec"); + + EGLConfig[] configs = new EGLConfig[numConfigs]; + egl.eglChooseConfig(eglDisplay, configSpec, configs, numConfigs, + num_config); + eglConfig = configs[0]; + + eglContext = egl.eglCreateContext(eglDisplay, eglConfig, + EGL10.EGL_NO_CONTEXT, null); + } + + // Called by ScummVM thread + protected void setupScummVMSurface() { + try { + surfaceLock.acquire(); + } catch (InterruptedException e) { + Log.e(this.toString(), + "Interrupted while waiting for surface lock", e); + return; + } + eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, + nativeSurface, null); + egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); + } + + // Called by ScummVM thread + protected void destroyScummVMSurface() { + if (eglSurface != null) { + egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, + EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + egl.eglDestroySurface(eglDisplay, eglSurface); + eglSurface = EGL10.EGL_NO_SURFACE; + } + + surfaceLock.release(); + } + + public void setSurface(SurfaceHolder holder) { + holder.addCallback(this); + } + + // Set scummvm config options + final public native static void loadConfigFile(String path); + final public native static void setConfMan(String key, int value); + final public native static void setConfMan(String key, String value); + + // Feed an event to ScummVM. Safe to call from other threads. + final public native void pushEvent(Event e); + + final private native void audioMixCallback(byte[] buf); + + // Runs the actual ScummVM program and returns when it does. + // This should not be called from multiple threads simultaneously... + final public native int scummVMMain(String[] argv); + + // Callbacks from C++ peer instance + //protected GraphicsMode[] getSupportedGraphicsModes() {} + protected void displayMessageOnOSD(String msg) {} + protected void setWindowCaption(String caption) {} + protected void showVirtualKeyboard(boolean enable) {} + protected String[] getSysArchives() { return new String[0]; } + protected String[] getPluginDirectories() { return new String[0]; } + protected void initBackend() throws AudioSetupException { + createScummVMGLContext(); + initAudio(); + } + + private static class AudioThread extends Thread { + final private int buf_size; + private boolean is_paused = false; + final private ScummVM scummvm; + final private AudioTrack audio_track; + + AudioThread(ScummVM scummvm, AudioTrack audio_track, int buf_size) { + super("AudioThread"); + this.scummvm = scummvm; + this.audio_track = audio_track; + this.buf_size = buf_size; + setPriority(Thread.MAX_PRIORITY); + setDaemon(true); + } + + public void pauseAudio() { + synchronized (this) { + is_paused = true; + } + audio_track.pause(); + } + + public void resumeAudio() { + synchronized (this) { + is_paused = false; + notifyAll(); + } + audio_track.play(); + } + + public void run() { + byte[] buf = new byte[buf_size]; + audio_track.play(); + int offset = 0; + try { + while (true) { + synchronized (this) { + while (is_paused) + wait(); + } + + if (offset == buf.length) { + // Grab new audio data + scummvm.audioMixCallback(buf); + offset = 0; + } + int len = buf.length - offset; + int ret = audio_track.write(buf, offset, len); + if (ret < 0) { + Log.w(LOG_TAG, String.format( + "AudioTrack.write(%dB) returned error %d", + buf.length, ret)); + break; + } else if (ret != len) { + Log.w(LOG_TAG, String.format( + "Short audio write. Wrote %dB, not %dB", + ret, buf.length)); + // Buffer is full, so yield cpu for a while + Thread.sleep(100); + } + offset += ret; + } + } catch (InterruptedException e) { + Log.e(this.toString(), "Audio thread interrupted", e); + } + } + } + private AudioThread audio_thread; + + final public int audioSampleRate() { + return AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC); + } + + private void initAudio() throws AudioSetupException { + int sample_rate = audioSampleRate(); + int buf_size = + AudioTrack.getMinBufferSize(sample_rate, + AudioFormat.CHANNEL_CONFIGURATION_STEREO, + AudioFormat.ENCODING_PCM_16BIT); + if (buf_size < 0) { + int guess = AUDIO_FRAME_SIZE * sample_rate / 100; // 10ms of audio + Log.w(LOG_TAG, String.format( + "Unable to get min audio buffer size (error %d). Guessing %dB.", + buf_size, guess)); + buf_size = guess; + } + Log.d(LOG_TAG, String.format("Using %dB buffer for %dHZ audio", + buf_size, sample_rate)); + AudioTrack audio_track = + new AudioTrack(AudioManager.STREAM_MUSIC, + sample_rate, + AudioFormat.CHANNEL_CONFIGURATION_STEREO, + AudioFormat.ENCODING_PCM_16BIT, + buf_size, + AudioTrack.MODE_STREAM); + if (audio_track.getState() != AudioTrack.STATE_INITIALIZED) { + Log.e(LOG_TAG, "Error initialising Android audio system."); + throw new AudioSetupException(); + } + + audio_thread = new AudioThread(this, audio_track, buf_size); + audio_thread.start(); + } + + public void pause() { + audio_thread.pauseAudio(); + // TODO: need to pause engine too + } + + public void resume() { + // TODO: need to resume engine too + audio_thread.resumeAudio(); + } + + static { + // For grabbing with gdb... + final boolean sleep_for_debugger = false; + if (sleep_for_debugger) { + try { + Thread.sleep(20*1000); + } catch (InterruptedException e) { + } + } + + //System.loadLibrary("scummvm"); + File cache_dir = ScummVMApplication.getLastCacheDir(); + String libname = System.mapLibraryName("scummvm"); + File libpath = new File(cache_dir, libname); + System.load(libpath.getPath()); + } +} diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java new file mode 100644 index 00000000000..29e1eba3d39 --- /dev/null +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -0,0 +1,446 @@ +package org.inodes.gus.scummvm; + +import android.app.AlertDialog; +import android.app.Activity; +import android.content.DialogInterface; +import android.content.res.Configuration; +import android.media.AudioManager; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.view.inputmethod.InputMethodManager; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.Toast; + +import java.io.IOException; + +public class ScummVMActivity extends Activity { + private boolean _do_right_click; + private boolean _last_click_was_right; + + // game pixels to move per trackball/dpad event. + // FIXME: replace this with proper mouse acceleration + private final static int TRACKBALL_SCALE = 2; + + private class MyScummVM extends ScummVM { + private boolean scummvmRunning = false; + + public MyScummVM() { + super(ScummVMActivity.this); + } + + @Override + protected void initBackend() throws ScummVM.AudioSetupException { + synchronized (this) { + scummvmRunning = true; + notifyAll(); + } + super.initBackend(); + } + + public void waitUntilRunning() throws InterruptedException { + synchronized (this) { + while (!scummvmRunning) + wait(); + } + } + + @Override + protected void displayMessageOnOSD(String msg) { + Log.i(this.toString(), "OSD: " + msg); + Toast.makeText(ScummVMActivity.this, msg, Toast.LENGTH_LONG).show(); + } + + @Override + protected void setWindowCaption(final String caption) { + runOnUiThread(new Runnable() { + public void run() { + setTitle(caption); + } + }); + } + + @Override + protected String[] getPluginDirectories() { + String[] dirs = new String[1]; + dirs[0] = ScummVMApplication.getLastCacheDir().getPath(); + return dirs; + } + + @Override + protected void showVirtualKeyboard(final boolean enable) { + if (getResources().getConfiguration().keyboard == + Configuration.KEYBOARD_NOKEYS) { + runOnUiThread(new Runnable() { + public void run() { + showKeyboard(enable); + } + }); + } + } + } + private MyScummVM scummvm; + private Thread scummvm_thread; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + _do_right_click = false; + setVolumeControlStream(AudioManager.STREAM_MUSIC); + + setContentView(R.layout.main); + takeKeyEvents(true); + + // This is a common enough error that we should warn about it + // explicitly. + if (!Environment.getExternalStorageDirectory().canRead()) { + new AlertDialog.Builder(this) + .setTitle(R.string.no_sdcard_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(R.string.no_sdcard) + .setNegativeButton(R.string.quit, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + finish(); + } + }) + .show(); + return; + } + + SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface); + main_surface.setOnTouchListener(new View.OnTouchListener() { + public boolean onTouch(View v, MotionEvent event) { + return onTouchEvent(event); + } + }); + main_surface.setOnKeyListener(new View.OnKeyListener() { + public boolean onKey(View v, int code, KeyEvent ev) { + return onKeyDown(code, ev); + } + }); + main_surface.requestFocus(); + + // Start ScummVM + scummvm = new MyScummVM(); + scummvm_thread = new Thread(new Runnable() { + public void run() { + try { + runScummVM(); + } catch (Exception e) { + Log.e("ScummVM", "Fatal error in ScummVM thread", e); + new AlertDialog.Builder(ScummVMActivity.this) + .setTitle("Error") + .setMessage(e.toString()) + .setIcon(android.R.drawable.ic_dialog_alert) + .show(); + finish(); + } + } + }, "ScummVM"); + scummvm_thread.start(); + + // Block UI thread until ScummVM has started. In particular, + // this means that surface and event callbacks should be safe + // after this point. + try { + scummvm.waitUntilRunning(); + } catch (InterruptedException e) { + Log.e(this.toString(), + "Interrupted while waiting for ScummVM.initBackend", e); + finish(); + } + + scummvm.setSurface(main_surface.getHolder()); + } + + // Runs in another thread + private void runScummVM() throws IOException { + getFilesDir().mkdirs(); + String[] args = { + "ScummVM-lib", + "--config=" + getFileStreamPath("scummvmrc").getPath(), + "--path=" + Environment.getExternalStorageDirectory().getPath(), + "--gui-theme=scummmodern", + "--savepath=" + getDir("saves", 0).getPath(), + }; + + int ret = scummvm.scummVMMain(args); + + // On exit, tear everything down for a fresh + // restart next time. + System.exit(ret); + } + + private boolean was_paused = false; + + @Override + public void onPause() { + if (scummvm != null) { + was_paused = true; + scummvm.pause(); + } + super.onPause(); + } + + @Override + public void onResume() { + super.onResume(); + if (scummvm != null && was_paused) + scummvm.resume(); + was_paused = false; + } + + @Override + public void onStop() { + if (scummvm != null) { + scummvm.pushEvent(new Event(Event.EVENT_QUIT)); + try { + scummvm_thread.join(1000); // 1s timeout + } catch (InterruptedException e) { + Log.i(this.toString(), + "Error while joining ScummVM thread", e); + } + } + super.onStop(); + } + + static final int MSG_MENU_LONG_PRESS = 1; + private final Handler keycodeMenuTimeoutHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_MENU_LONG_PRESS) { + InputMethodManager imm = (InputMethodManager) + getSystemService(INPUT_METHOD_SERVICE); + if (imm != null) + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + } + }; + + @Override + public boolean onKeyUp(int keyCode, KeyEvent kevent) { + return onKeyDown(keyCode, kevent); + } + + @Override + public boolean onKeyMultiple(int keyCode, int repeatCount, + KeyEvent kevent) { + return onKeyDown(keyCode, kevent); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent kevent) { + // Filter out "special" keys + switch (keyCode) { + case KeyEvent.KEYCODE_MENU: + // Have to reimplement hold-down-menu-brings-up-softkeybd + // ourselves, since we are otherwise hijacking the menu + // key :( + // See com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel() + // for the usual Android implementation of this feature. + if (kevent.getRepeatCount() > 0) + // Ignore keyrepeat for menu + return false; + boolean timeout_fired = false; + if (getResources().getConfiguration().keyboard == + Configuration.KEYBOARD_NOKEYS) { + timeout_fired = !keycodeMenuTimeoutHandler.hasMessages(MSG_MENU_LONG_PRESS); + keycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS); + if (kevent.getAction() == KeyEvent.ACTION_DOWN) { + keycodeMenuTimeoutHandler.sendMessageDelayed( + keycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS), + ViewConfiguration.getLongPressTimeout()); + return true; + } + } + if (kevent.getAction() == KeyEvent.ACTION_UP) { + if (!timeout_fired) + scummvm.pushEvent(new Event(Event.EVENT_MAINMENU)); + return true; + } + return false; + case KeyEvent.KEYCODE_CAMERA: + case KeyEvent.KEYCODE_SEARCH: + _do_right_click = (kevent.getAction() == KeyEvent.ACTION_DOWN); + return true; + case KeyEvent.KEYCODE_DPAD_CENTER: + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: { + // HTC Hero doesn't seem to generate + // MotionEvent.ACTION_DOWN events on trackball press :( + // We'll have to just fake one here. + // Some other handsets lack a trackball, so the DPAD is + // the only way of moving the cursor. + int motion_action; + // FIXME: this logic is a mess. + if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { + switch (kevent.getAction()) { + case KeyEvent.ACTION_DOWN: + motion_action = MotionEvent.ACTION_DOWN; + break; + case KeyEvent.ACTION_UP: + motion_action = MotionEvent.ACTION_UP; + break; + default: // ACTION_MULTIPLE + return false; + } + } else + motion_action = MotionEvent.ACTION_MOVE; + + Event e = new Event(getEventType(motion_action)); + e.mouse_x = 0; + e.mouse_y = 0; + e.mouse_relative = true; + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_UP: + e.mouse_y = -TRACKBALL_SCALE; + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + e.mouse_y = TRACKBALL_SCALE; + break; + case KeyEvent.KEYCODE_DPAD_LEFT: + e.mouse_x = -TRACKBALL_SCALE; + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + e.mouse_x = TRACKBALL_SCALE; + break; + } + scummvm.pushEvent(e); + return true; + } + case KeyEvent.KEYCODE_BACK: + // skip isSystem() check and fall through to main code + break; + default: + if (kevent.isSystem()) + return false; + } + + // FIXME: what do I need to do for composed characters? + + Event e = new Event(); + + switch (kevent.getAction()) { + case KeyEvent.ACTION_DOWN: + e.type = Event.EVENT_KEYDOWN; + e.synthetic = false; + break; + case KeyEvent.ACTION_UP: + e.type = Event.EVENT_KEYUP; + e.synthetic = false; + break; + case KeyEvent.ACTION_MULTIPLE: + // e.type is handled below + e.synthetic = true; + break; + default: + return false; + } + + e.kbd_keycode = Event.androidKeyMap.containsKey(keyCode) ? + Event.androidKeyMap.get(keyCode) : Event.KEYCODE_INVALID; + e.kbd_ascii = kevent.getUnicodeChar(); + if (e.kbd_ascii == 0) + e.kbd_ascii = e.kbd_keycode; // scummvm keycodes are mostly ascii + + + e.kbd_flags = 0; + if (kevent.isAltPressed()) + e.kbd_flags |= Event.KBD_ALT; + if (kevent.isSymPressed()) // no ctrl key in android, so use sym (?) + e.kbd_flags |= Event.KBD_CTRL; + if (kevent.isShiftPressed()) { + if (keyCode >= KeyEvent.KEYCODE_0 && + keyCode <= KeyEvent.KEYCODE_9) { + // Shift+number -> convert to F* key + int offset = keyCode == KeyEvent.KEYCODE_0 ? + 10 : keyCode - KeyEvent.KEYCODE_1; // turn 0 into 10 + e.kbd_keycode = Event.KEYCODE_F1 + offset; + e.kbd_ascii = Event.ASCII_F1 + offset; + } else + e.kbd_flags |= Event.KBD_SHIFT; + } + + if (kevent.getAction() == KeyEvent.ACTION_MULTIPLE) { + for (int i = 0; i <= kevent.getRepeatCount(); i++) { + e.type = Event.EVENT_KEYDOWN; + scummvm.pushEvent(e); + e.type = Event.EVENT_KEYUP; + scummvm.pushEvent(e); + } + } else + scummvm.pushEvent(e); + + return true; + } + + private int getEventType(int action) { + switch (action) { + case MotionEvent.ACTION_DOWN: + _last_click_was_right = _do_right_click; + return _last_click_was_right ? + Event.EVENT_RBUTTONDOWN : Event.EVENT_LBUTTONDOWN; + case MotionEvent.ACTION_UP: + return _last_click_was_right ? + Event.EVENT_RBUTTONUP : Event.EVENT_LBUTTONUP; + case MotionEvent.ACTION_MOVE: + return Event.EVENT_MOUSEMOVE; + default: + return Event.EVENT_INVALID; + } + } + + @Override + public boolean onTrackballEvent(MotionEvent event) { + int type = getEventType(event.getAction()); + if (type == Event.EVENT_INVALID) + return false; + + Event e = new Event(type); + e.mouse_x = + (int)(event.getX() * event.getXPrecision()) * TRACKBALL_SCALE; + e.mouse_y = + (int)(event.getY() * event.getYPrecision()) * TRACKBALL_SCALE; + e.mouse_relative = true; + scummvm.pushEvent(e); + + return true; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + int type = getEventType(event.getAction()); + if (type == Event.EVENT_INVALID) + return false; + + Event e = new Event(type); + e.mouse_x = (int)event.getX(); + e.mouse_y = (int)event.getY(); + e.mouse_relative = false; + scummvm.pushEvent(e); + + return true; + } + + private void showKeyboard(boolean show) { + SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface); + InputMethodManager imm = (InputMethodManager) + getSystemService(INPUT_METHOD_SERVICE); + if (show) + imm.showSoftInput(main_surface, InputMethodManager.SHOW_IMPLICIT); + else + imm.hideSoftInputFromWindow(main_surface.getWindowToken(), + InputMethodManager.HIDE_IMPLICIT_ONLY); + } +} diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java new file mode 100644 index 00000000000..37a9d09e1a4 --- /dev/null +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMApplication.java @@ -0,0 +1,29 @@ +package org.inodes.gus.scummvm; + +import android.app.Application; + +import java.io.File; + +public class ScummVMApplication extends Application { + public final static String ACTION_PLUGIN_QUERY = "org.inodes.gus.scummvm.action.PLUGIN_QUERY"; + public final static String EXTRA_UNPACK_LIBS = "org.inodes.gus.scummvm.extra.UNPACK_LIBS"; + + private static File cache_dir; + + @Override + public void onCreate() { + super.onCreate(); + // This is still on /data :( + cache_dir = getCacheDir(); + // This is mounted noexec :( + //cache_dir = new File(Environment.getExternalStorageDirectory(), + // "/.ScummVM.tmp"); + // This is owned by download manager and requires special + // permissions to access :( + //cache_dir = Environment.getDownloadCacheDirectory(); + } + + public static File getLastCacheDir() { + return cache_dir; + } +} diff --git a/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java b/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java new file mode 100644 index 00000000000..efa3e1d2ef4 --- /dev/null +++ b/backends/platform/android/org/inodes/gus/scummvm/Unpacker.java @@ -0,0 +1,370 @@ +package org.inodes.gus.scummvm; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.widget.ProgressBar; + +import java.io.IOException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.zip.ZipFile; +import java.util.zip.ZipEntry; + +public class Unpacker extends Activity { + private final static String META_NEXT_ACTIVITY = + "org.inodes.gus.unpacker.nextActivity"; + private ProgressBar mProgress; + private File mUnpackDest; // location to unpack into + private AsyncTask mUnpacker; + private final static int REQUEST_MARKET = 1; + + private static class UnpackJob { + public ZipFile zipfile; + public Set paths; + + public UnpackJob(ZipFile zipfile, Set paths) { + this.zipfile = zipfile; + this.paths = paths; + } + + public long UnpackSize() { + long size = 0; + for (String path: paths) { + ZipEntry entry = zipfile.getEntry(path); + if (entry != null) size += entry.getSize(); + } + return size; + } + } + + private class UnpackTask extends AsyncTask { + @Override + protected void onProgressUpdate(Integer... progress) { + mProgress.setIndeterminate(false); + mProgress.setMax(progress[1]); + mProgress.setProgress(progress[0]); + mProgress.postInvalidate(); + } + + @Override + protected void onPostExecute(Void result) { + Bundle md = getMetaData(); + String nextActivity = md.getString(META_NEXT_ACTIVITY); + if (nextActivity != null) { + final ComponentName cn = + ComponentName.unflattenFromString(nextActivity); + if (cn != null) { + final Intent origIntent = getIntent(); + Intent intent = new Intent(); + intent.setPackage(origIntent.getPackage()); + intent.setComponent(cn); + if (origIntent.getExtras() != null) + intent.putExtras(origIntent.getExtras()); + intent.putExtra(Intent.EXTRA_INTENT, origIntent); + intent.setDataAndType(origIntent.getData(), + origIntent.getType()); + //intent.fillIn(getIntent(), 0); + intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); + Log.i(this.toString(), + "Starting next activity with intent " + intent); + startActivity(intent); + } else { + Log.w(this.toString(), + "Unable to extract a component name from " + nextActivity); + } + } + + finish(); + } + + @Override + protected Void doInBackground(String... all_libs) { + // This will contain all unpack jobs + Map unpack_jobs = + new HashMap(all_libs.length); + + // This will contain all unpack filenames (so we can + // detect stale files in the unpack directory) + Set all_files = new HashSet(all_libs.length); + + for (String lib: all_libs) { + final Uri uri = Uri.parse(lib); + final String pkg = uri.getAuthority(); + final String path = uri.getPath().substring(1); // skip first / + + all_files.add(new File(path).getName()); + + UnpackJob job = unpack_jobs.get(pkg); + if (job == null) { + try { + // getPackageResourcePath is hidden in Context, + // but exposed in ContextWrapper... + ContextWrapper context = + new ContextWrapper(createPackageContext(pkg, 0)); + ZipFile zipfile = + new ZipFile(context.getPackageResourcePath()); + job = new UnpackJob(zipfile, new HashSet(1)); + } catch (PackageManager.NameNotFoundException e) { + Log.e(this.toString(), "Package " + pkg + + " not found", e); + continue; + } catch (IOException e) { + // FIXME: show some sort of GUI error dialog + Log.e(this.toString(), + "Error opening ZIP for package " + pkg, e); + continue; + } + unpack_jobs.put(pkg, job); + } + job.paths.add(path); + } + + // Delete stale filenames from mUnpackDest + for (File file: mUnpackDest.listFiles()) { + if (!all_files.contains(file.getName())) { + Log.i(this.toString(), + "Deleting stale cached file " + file); + file.delete(); + } + } + + int total_size = 0; + for (UnpackJob job: unpack_jobs.values()) + total_size += job.UnpackSize(); + + publishProgress(0, total_size); + + mUnpackDest.mkdirs(); + + int progress = 0; + + for (UnpackJob job: unpack_jobs.values()) { + try { + ZipFile zipfile = job.zipfile; + for (String path: job.paths) { + ZipEntry zipentry = zipfile.getEntry(path); + if (zipentry == null) + throw new FileNotFoundException( + "Couldn't find " + path + " in zip"); + File dest = new File(mUnpackDest, new File(path).getName()); + if (dest.exists() && + dest.lastModified() == zipentry.getTime() && + dest.length() == zipentry.getSize()) { + // Already unpacked + progress += zipentry.getSize(); + } else { + if (dest.exists()) + Log.d(this.toString(), + "Replacing " + dest.getPath() + + " old.mtime=" + dest.lastModified() + + " new.mtime=" + zipentry.getTime() + + " old.size=" + dest.length() + + " new.size=" + zipentry.getSize()); + else + Log.i(this.toString(), + "Extracting " + zipentry.getName() + + " from " + zipfile.getName() + + " to " + dest.getPath()); + + long next_update = progress; + + InputStream in = zipfile.getInputStream(zipentry); + OutputStream out = new FileOutputStream(dest); + int len; + byte[] buffer = new byte[4096]; + while ((len = in.read(buffer)) != -1) { + out.write(buffer, 0, len); + progress += len; + if (progress >= next_update) { + publishProgress(progress, total_size); + // Arbitrary limit of 2% update steps + next_update += total_size / 50; + } + } + + in.close(); + out.close(); + dest.setLastModified(zipentry.getTime()); + } + publishProgress(progress, total_size); + } + + zipfile.close(); + } catch (IOException e) { + // FIXME: show some sort of GUI error dialog + Log.e(this.toString(), "Error unpacking plugin", e); + } + } + + if (progress != total_size) + Log.d(this.toString(), "Ended with progress " + progress + + " != total size " + total_size); + + setResult(RESULT_OK); + + return null; + } + } + + private class PluginBroadcastReciever extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (!intent.getAction() + .equals(ScummVMApplication.ACTION_PLUGIN_QUERY)) { + Log.e(this.toString(), + "Received unexpected action " + intent.getAction()); + return; + } + + Bundle extras = getResultExtras(false); + if (extras == null) { + // Nothing for us to do. + Unpacker.this.setResult(RESULT_OK); + finish(); + } + + ArrayList unpack_libs = + extras.getStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS); + + if (unpack_libs != null && !unpack_libs.isEmpty()) { + final String[] libs = + unpack_libs.toArray(new String[unpack_libs.size()]); + mUnpacker = new UnpackTask().execute(libs); + } + } + } + + private void initPlugins() { + Bundle extras = new Bundle(1); + + ArrayList unpack_libs = new ArrayList(1); + // This is the common ScummVM code (not really a "plugin" as such) + unpack_libs.add(new Uri.Builder() + .scheme("plugin") + .authority(getPackageName()) + .path("mylib/armeabi/libscummvm.so") + .toString()); + extras.putStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS, + unpack_libs); + + Intent intent = new Intent(ScummVMApplication.ACTION_PLUGIN_QUERY); + sendOrderedBroadcast(intent, Manifest.permission.SCUMMVM_PLUGIN, + new PluginBroadcastReciever(), + null, RESULT_OK, null, extras); + } + + @Override + public void onCreate(Bundle b) { + super.onCreate(b); + + mUnpackDest = ScummVMApplication.getLastCacheDir(); + + setContentView(R.layout.splash); + mProgress = (ProgressBar)findViewById(R.id.progress); + + setResult(RESULT_CANCELED); + + tryUnpack(); + } + + private void tryUnpack() { + Intent intent = new Intent(ScummVMApplication.ACTION_PLUGIN_QUERY); + List plugins = getPackageManager() + .queryBroadcastReceivers(intent, 0); + if (plugins.isEmpty()) { + // No plugins installed + AlertDialog.Builder alert = new AlertDialog.Builder(this) + .setTitle(R.string.no_plugins_title) + .setMessage(R.string.no_plugins_found) + .setIcon(android.R.drawable.ic_dialog_alert) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + finish(); + } + }) + .setNegativeButton(R.string.quit, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + final Uri uri = Uri.parse("market://search?q=ScummVM plugin"); + final Intent market_intent = new Intent(Intent.ACTION_VIEW, uri); + if (getPackageManager().resolveActivity(market_intent, 0) != null) { + alert.setPositiveButton(R.string.to_market, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + try { + startActivityForResult(market_intent, + REQUEST_MARKET); + } catch (ActivityNotFoundException e) { + Log.e(this.toString(), + "Error starting market", e); + } + } + }); + } + + alert.show(); + + } else { + // Already have at least one plugin installed + initPlugins(); + } + } + + @Override + public void onStop() { + if (mUnpacker != null) + mUnpacker.cancel(true); + super.onStop(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, + Intent data) { + switch (requestCode) { + case REQUEST_MARKET: + if (resultCode != RESULT_OK) + Log.w(this.toString(), "Market returned " + resultCode); + tryUnpack(); + break; + } + } + + private Bundle getMetaData() { + try { + ActivityInfo ai = getPackageManager() + .getActivityInfo(getComponentName(), PackageManager.GET_META_DATA); + return ai.metaData; + } catch (PackageManager.NameNotFoundException e) { + Log.w(this.toString(), "Unable to find my own meta-data", e); + return new Bundle(); + } + } +} diff --git a/backends/platform/android/scummvm-android-themeengine.patch b/backends/platform/android/scummvm-android-themeengine.patch new file mode 100644 index 00000000000..1eafe7fb625 --- /dev/null +++ b/backends/platform/android/scummvm-android-themeengine.patch @@ -0,0 +1,135 @@ +diff -r 884e66fd1b9c gui/ThemeEngine.cpp +--- a/gui/ThemeEngine.cpp Tue Apr 13 09:30:52 2010 +1000 ++++ b/gui/ThemeEngine.cpp Fri May 28 23:24:43 2010 +1000 +@@ -390,21 +390,19 @@ + + // Try to create a Common::Archive with the files of the theme. + if (!_themeArchive && !_themeFile.empty()) { +- Common::FSNode node(_themeFile); +- if (node.getName().hasSuffix(".zip") && !node.isDirectory()) { ++ Common::ArchiveMemberPtr member = SearchMan.getMember(_themeFile); ++ if (member && member->getName().hasSuffix(".zip")) { + #ifdef USE_ZLIB +- Common::Archive *zipArchive = Common::makeZipArchive(node); ++ Common::Archive *zipArchive = Common::makeZipArchive(member->createReadStream()); + + if (!zipArchive) { +- warning("Failed to open Zip archive '%s'.", node.getPath().c_str()); ++ warning("Failed to open Zip archive '%s'.", member->getDisplayName().c_str()); + } + _themeArchive = zipArchive; + #else + warning("Trying to load theme '%s' in a Zip archive without zLib support", _themeFile.c_str()); + return false; + #endif +- } else if (node.isDirectory()) { +- _themeArchive = new Common::FSDirectory(node); + } + } + +@@ -1436,6 +1434,30 @@ + return tok.empty(); + } + ++bool ThemeEngine::themeConfigUsable(const Common::ArchiveMember &member, Common::String &themeName) { ++ Common::File stream; ++ bool foundHeader = false; ++ ++ if (member.getName().hasSuffix(".zip")) { ++#ifdef USE_ZLIB ++ Common::Archive *zipArchive = Common::makeZipArchive(member.createReadStream()); ++ ++ if (zipArchive && zipArchive->hasFile("THEMERC")) { ++ stream.open("THEMERC", *zipArchive); ++ } ++ ++ delete zipArchive; ++#endif ++ } ++ ++ if (stream.isOpen()) { ++ Common::String stxHeader = stream.readLine(); ++ foundHeader = themeConfigParseHeader(stxHeader, themeName); ++ } ++ ++ return foundHeader; ++} ++ + bool ThemeEngine::themeConfigUsable(const Common::FSNode &node, Common::String &themeName) { + Common::File stream; + bool foundHeader = false; +@@ -1493,10 +1515,6 @@ + if (ConfMan.hasKey("themepath")) + listUsableThemes(Common::FSNode(ConfMan.get("themepath")), list); + +-#ifdef DATA_PATH +- listUsableThemes(Common::FSNode(DATA_PATH), list); +-#endif +- + #if defined(MACOSX) || defined(IPHONE) + CFURLRef resourceUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (resourceUrl) { +@@ -1509,10 +1527,7 @@ + } + #endif + +- if (ConfMan.hasKey("extrapath")) +- listUsableThemes(Common::FSNode(ConfMan.get("extrapath")), list); +- +- listUsableThemes(Common::FSNode("."), list, 1); ++ listUsableThemes(SearchMan, list); + + // Now we need to strip all duplicates + // TODO: It might not be the best idea to strip duplicates. The user might +@@ -1531,6 +1546,34 @@ + output.clear(); + } + ++void ThemeEngine::listUsableThemes(Common::Archive &archive, Common::List &list) { ++ ThemeDescriptor td; ++ ++#ifdef USE_ZLIB ++ Common::ArchiveMemberList fileList; ++ archive.listMatchingMembers(fileList, "*.zip"); ++ for (Common::ArchiveMemberList::iterator i = fileList.begin(); ++ i != fileList.end(); ++i) { ++ td.name.clear(); ++ if (themeConfigUsable(**i, td.name)) { ++ td.filename = (*i)->getName(); ++ td.id = (*i)->getDisplayName(); ++ ++ // If the name of the node object also contains ++ // the ".zip" suffix, we will strip it. ++ if (td.id.hasSuffix(".zip")) { ++ for (int j = 0; j < 4; ++j) ++ td.id.deleteLastChar(); ++ } ++ ++ list.push_back(td); ++ } ++ } ++ ++ fileList.clear(); ++#endif ++} ++ + void ThemeEngine::listUsableThemes(const Common::FSNode &node, Common::List &list, int depth) { + if (!node.exists() || !node.isReadable() || !node.isDirectory()) + return; +diff -r 884e66fd1b9c gui/ThemeEngine.h +--- a/gui/ThemeEngine.h Tue Apr 13 09:30:52 2010 +1000 ++++ b/gui/ThemeEngine.h Fri May 28 23:24:43 2010 +1000 +@@ -560,11 +560,13 @@ + static void listUsableThemes(Common::List &list); + private: + static bool themeConfigUsable(const Common::FSNode &node, Common::String &themeName); ++ static bool themeConfigUsable(const Common::ArchiveMember &member, Common::String &themeName); + static bool themeConfigParseHeader(Common::String header, Common::String &themeName); + + static Common::String getThemeFile(const Common::String &id); + static Common::String getThemeId(const Common::String &filename); + static void listUsableThemes(const Common::FSNode &node, Common::List &list, int depth = -1); ++ static void listUsableThemes(Common::Archive &archive, Common::List &list); + + protected: + OSystem *_system; /** Global system object. */ diff --git a/base/commandLine.cpp b/base/commandLine.cpp index 207ff79c4cb..1c548d3f504 100644 --- a/base/commandLine.cpp +++ b/base/commandLine.cpp @@ -51,7 +51,7 @@ static const char USAGE_STRING[] = ; // DONT FIXME: DO NOT ORDER ALPHABETICALLY, THIS IS ORDERED BY IMPORTANCE/CATEGORY! :) -#if defined(PALMOS_MODE) || defined(__SYMBIAN32__) || defined(__GP32__) +#if defined(PALMOS_MODE) || defined(__SYMBIAN32__) || defined(__GP32__) || defined(ANDROID) static const char HELP_STRING[] = "NoUsageString"; // save more data segment space #else static const char HELP_STRING[] = @@ -948,7 +948,7 @@ Common::Error processSettings(Common::String &command, Common::StringMap &settin // environment variable. This is weaker than a --savepath on the // command line, but overrides the default savepath, hence it is // handled here, just before the command line gets parsed. -#if !defined(MACOS_CARBON) && !defined(_WIN32_WCE) && !defined(PALMOS_MODE) && !defined(__GP32__) +#if !defined(MACOS_CARBON) && !defined(_WIN32_WCE) && !defined(PALMOS_MODE) && !defined(__GP32__) && !defined(ANDROID) if (!settings.contains("savepath")) { const char *dir = getenv("SCUMMVM_SAVEPATH"); if (dir && *dir && strlen(dir) < MAXPATHLEN) { diff --git a/common/textconsole.cpp b/common/textconsole.cpp index eef58fa39c6..87ba55ebf12 100644 --- a/common/textconsole.cpp +++ b/common/textconsole.cpp @@ -43,6 +43,10 @@ extern bool isSmartphone(); #define fputs(str, file) DS::std_fwrite(str, strlen(str), 1, file) #endif +#ifdef ANDROID + #include +#endif + namespace Common { static OutputFormatter s_errorOutputFormatter = 0; @@ -71,7 +75,9 @@ void warning(const char *s, ...) { vsnprintf(buf, STRINGBUFLEN, s, va); va_end(va); -#if !defined (__SYMBIAN32__) +#if defined( ANDROID ) + __android_log_write(ANDROID_LOG_WARN, "ScummVM", buf); +#elif !defined (__SYMBIAN32__) fputs("WARNING: ", stderr); fputs(buf, stderr); fputs("!\n", stderr); @@ -141,6 +147,10 @@ void NORETURN_PRE error(const char *s, ...) { #endif #endif +#ifdef ANDROID + __android_log_assert("Fatal error", "ScummVM", "%s", buf_output); +#endif + #ifdef PALMOS_MODE extern void PalmFatalError(const char *err); PalmFatalError(buf_output); diff --git a/configure b/configure index 17da22fb8f6..0c06be13ea3 100755 --- a/configure +++ b/configure @@ -999,6 +999,11 @@ wince) _host_cpu=arm _host_alias=arm-wince-mingw32ce ;; +android) + _host_os=android + _host_cpu=arm + _host_alias=arm-android-eabi + ;; *) if test -n "$_host"; then guessed_host=`$_srcdir/config.sub $_host` @@ -1077,6 +1082,12 @@ psp) exit 1 fi ;; +android) + if test -z "$ANDROID_SDK"; then + echo "Please set ANDROID_SDK in your environment. export ANDROID_SDK=" + exit 1 + fi + ;; *) ;; esac @@ -1399,6 +1410,11 @@ case $_host_os in DEFINES="$DEFINES -D_WIN32_WCE=300 -D__ARM__ -D_ARM_ -DUNICODE -DFPM_DEFAULT -DNONSTANDARD_PORT" DEFINES="$DEFINES -DWIN32 -Dcdecl= -D__cdecl__=" ;; + android) + DEFINES="$DEFINES -DUNIX" + CXXFLAGS="$CXXFLAGS -Os -msoft-float -mtune=xscale -march=armv5te -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5TE__" + add_line_to_config_mk "ANDROID_SDK = $ANDROID_SDK" + ;; # given this is a shell script assume some type of unix *) echo "WARNING: could not establish system type, assuming unix like" @@ -1647,6 +1663,19 @@ if test -n "$_host"; then _mt32emu="no" _port_mk="backends/platform/wince/wince.mk" ;; + android) + DEFINES="$DEFINES -DANDROID -DUNIX -DUSE_ARM_SMUSH_ASM" + _endian=little + _need_memalign=yes + add_line_to_config_mk 'USE_ARM_SOUND_ASM = 1' + add_line_to_config_mk 'USE_ARM_SMUSH_ASM = 1' + add_line_to_config_mk 'USE_ARM_GFX_ASM = 1' + add_line_to_config_mk 'USE_ARM_SCALER_ASM = 1' + add_line_to_config_mk 'USE_ARM_COSTUME_ASM = 1' + _backend="android" + _port_mk="backends/platform/android/android.mk" + _build_hq_scalers="no" + ;; *) echo "WARNING: Unknown target, continuing with auto-detected values" ;; @@ -1825,7 +1854,7 @@ POST_OBJS_FLAGS := -Wl,-no-whole-archive LIBS += -ldl ' ;; - linux*) + linux*|android) _def_plugin=' #define PLUGIN_PREFIX "lib" #define PLUGIN_SUFFIX ".so" @@ -2432,6 +2461,14 @@ case $_backend in INCLUDES="$INCLUDES "'-I$(srcdir) -I$(srcdir)/backends/platform/wince -I$(srcdir)/engines -I$(srcdir)/backends/platform/wince/missing/gcc -I$(srcdir)/backends/platform/wince/CEgui -I$(srcdir)/backends/platform/wince/CEkeys' LIBS="$LIBS -static -lSDL" ;; + android) + # -lgcc is carefully placed here - we want to catch + # all toolchain symbols in *our* libraries rather + # than pick up anything unhygenic from the Android libs. + LIBS="$LIBS -lgcc -lstdc++ -llog -lGLESv1_CM -lEGL" + DEFINES="$DEFINES -D__ANDROID__ -DANDROID_BACKEND -DREDUCE_MEMORY_USAGE" + add_line_to_config_mk 'PLUGIN_LDFLAGS += $(LDFLAGS) -Wl,-shared,-Bsymbolic' + ;; *) echo "support for $_backend backend not implemented in configure script yet" exit 1 @@ -2447,7 +2484,7 @@ if test "$have_gcc" = yes ; then case $_host_os in # newlib-based system include files suppress non-C89 function # declarations under __STRICT_ANSI__ - mingw* | dreamcast | wii | gamecube | psp | wince | amigaos*) + mingw* | dreamcast | wii | gamecube | psp | wince | amigaos* | android) CXXFLAGS="$CXXFLAGS -W -Wno-unused-parameter" ;; *) @@ -2468,7 +2505,7 @@ fi; # Some platforms use certain GNU extensions in header files case $_host_os in -gamecube | psp | wii) +gamecube | psp | wii | android) ;; *) CXXFLAGS="$CXXFLAGS -pedantic" diff --git a/dists/android/mkmanifest.pl b/dists/android/mkmanifest.pl new file mode 100644 index 00000000000..00d15f561ec --- /dev/null +++ b/dists/android/mkmanifest.pl @@ -0,0 +1,169 @@ +#!/usr/bin/perl + +use File::Basename qw(dirname); +use File::Path qw(mkpath); +use IO::File; +use XML::Writer; +use XML::Parser; +use Getopt::Long; + +use warnings; +use strict; + +use constant ANDROID => 'http://schemas.android.com/apk/res/android'; + +my $id; +my $package_versionName; +my $package_versionCode; +my $configure = 'configure'; +my $stringres = 'res/string/values.xml'; +my $manifest = 'AndroidManifest.xml'; +my $master_manifest; +my @unpack_libs; +GetOptions('id=s' => \$id, + 'version-name=s' => \$package_versionName, + 'version-code=i' => \$package_versionCode, + 'configure=s' => \$configure, + 'stringres=s' => \$stringres, + 'manifest=s' => \$manifest, + 'master-manifest=s' => \$master_manifest, + 'unpacklib=s' => \@unpack_libs, + ) or die; +die "Missing required arg" + unless $id and $package_versionName and $package_versionCode; + + +sub grope_engine_info { + my $configure = shift; + my @ret; + while (<$configure>) { + m/^add_engine \s+ (\w+) \s+ "(.*?)" \s+ \w+ (?:\s+ "([\w\s]*)")?/x + or next; + my $subengines = $3 || ''; + my %info = (id => $1, name => $2, + subengines => [split / /, $subengines]); + push @ret, \%info; + } + return @ret; +} + +sub read_constraints { + my $manifest = shift; + my @constraints; + my $parser = new XML::Parser Handlers => { + Start => sub { + my $expat = shift; + my $elem = shift; + return if $elem !~ + /^(uses-configuration|supports-screens|uses-sdk)$/; + my @constraint = ($elem); + while (@_) { + my $attr = shift; + my $value = shift; + $attr = [ANDROID, $attr] if $attr =~ s/^android://; + push @constraint, $attr, $value; + } + push @constraints, \@constraint; + }, + }; + $parser->parse($manifest); + return @constraints; +} + +sub print_stringres { + my $output = shift; + my $info = shift; + + my $writer = new XML::Writer(OUTPUT => $output, ENCODING => 'utf-8', + DATA_MODE => 1, DATA_INDENT => 2); + + $writer->xmlDecl(); + $writer->startTag('resources'); + + while (my ($k,$v) = each %$info) { + $writer->dataElement('string', $v, name => $k); + } + + $writer->endTag('resources'); + $writer->end(); +} + +sub print_manifest { + my $output = shift; + my $info = shift; + my $constraints = shift; + + my $writer = new XML::Writer(OUTPUT => $output, ENCODING => 'utf-8', + DATA_MODE => 1, DATA_INDENT => 2, + NAMESPACES => 1, + PREFIX_MAP => {ANDROID, 'android'}); + + $writer->xmlDecl(); + + $writer->startTag( + 'manifest', + 'package' => "org.inodes.gus.scummvm.plugin.$info->{name}", + [ANDROID, 'versionCode'] => $package_versionCode, + [ANDROID, 'versionName'] => $package_versionName, + ); + + $writer->startTag( + 'application', + [ANDROID, 'label'] => '@string/app_name', + [ANDROID, 'description'] => '@string/app_desc', + [ANDROID, 'icon'] => '@drawable/scummvm', + ); + + $writer->startTag( + 'receiver', + [ANDROID, 'name'] => 'org.inodes.gus.scummvm.PluginProvider', + [ANDROID, 'process'] => 'org.inodes.gus.scummvm'); + + $writer->startTag('intent-filter'); + $writer->emptyTag('action', [ANDROID, 'name'] => + 'org.inodes.gus.scummvm.action.PLUGIN_QUERY'); + $writer->emptyTag('category', [ANDROID, 'name'] => + 'android.intent.category.INFO'); + $writer->endTag('intent-filter'); + $writer->emptyTag( + 'meta-data', + [ANDROID, 'name'] => 'org.inodes.gus.scummvm.meta.UNPACK_LIB', + [ANDROID, 'value'] => $_) + for @{$info->{unpack_libs}}; + + $writer->endTag('receiver'); + $writer->endTag('application'); + + $writer->emptyTag('uses-permission', [ANDROID, 'name'] => + 'org.inodes.gus.scummvm.permission.SCUMMVM_PLUGIN'); + + $writer->emptyTag(@$_) foreach @$constraints; + + $writer->endTag('manifest'); + $writer->end(); +} + + +my %engines; +for my $engine (grope_engine_info(new IO::File $configure, 'r')) { + $engines{$engine->{id}} = $engine; +} + +my @games = ($id, @{$engines{$id}{subengines}}); +my $games_desc = join('; ', map $engines{$_}{name}, @games); + +my @constraints = read_constraints(new IO::File $master_manifest, 'r'); + +print "Writing $stringres ...\n"; +mkpath(dirname($stringres)); +print_stringres(IO::File->new($stringres, 'w'), + {app_name => qq{ScummVM plugin: "$id"}, + app_desc => "Game engine for: $games_desc", + }); + +print "Writing $manifest ...\n"; +mkpath(dirname($manifest)); +print_manifest(IO::File->new($manifest, 'w'), + {name => $id, unpack_libs => \@unpack_libs}, \@constraints); + +exit 0; diff --git a/dists/android/res/drawable/gradient.xml b/dists/android/res/drawable/gradient.xml new file mode 100644 index 00000000000..dbfd9b5b341 --- /dev/null +++ b/dists/android/res/drawable/gradient.xml @@ -0,0 +1,7 @@ + + + + diff --git a/dists/android/res/layout/main.xml b/dists/android/res/layout/main.xml new file mode 100644 index 00000000000..f5276ce41b1 --- /dev/null +++ b/dists/android/res/layout/main.xml @@ -0,0 +1,10 @@ + + diff --git a/dists/android/res/layout/splash.xml b/dists/android/res/layout/splash.xml new file mode 100644 index 00000000000..e9fd5f70e7b --- /dev/null +++ b/dists/android/res/layout/splash.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/dists/android/res/values/strings.xml b/dists/android/res/values/strings.xml new file mode 100644 index 00000000000..e06509d3ed8 --- /dev/null +++ b/dists/android/res/values/strings.xml @@ -0,0 +1,22 @@ + + + ScummVM + Graphic adventure game engine + Quit + ScummVM plugin + Allows the application to + provide a ScummVM loadable plugin: code that will be executed in the + ScummVM application. Malicious plugins may do anything ScummVM + itself could do: write to your SD card, delete your savegames, + change the ScummVM background to puce, replace menu labels with rude + words, etc. + No SD card? + Unable to read your SD card. This usually + means you still have it mounted on your PC. Unmount, reinsert, + whatever and then try again. + No plugins found + ScummVM requires at least one game + engine to be useful. Engines are available as separate plugin + packages, from wherever you found ScummVM. + To Market + diff --git a/sound/decoders/vorbis.cpp b/sound/decoders/vorbis.cpp index 39068603de9..64869d7843a 100644 --- a/sound/decoders/vorbis.cpp +++ b/sound/decoders/vorbis.cpp @@ -35,7 +35,7 @@ #include "sound/audiocd.h" #ifdef USE_TREMOR -#ifdef __GP32__ // GP32 uses custom libtremor +#if defined(ANDROID) || defined(__GP32__) // custom libtremor locations #include #else #include diff --git a/tools/update-version.pl b/tools/update-version.pl index f151ae75146..81aa5c27f97 100755 --- a/tools/update-version.pl +++ b/tools/update-version.pl @@ -40,6 +40,7 @@ my @subs_files = qw( dists/iphone/Info.plist dists/irix/scummvm.spec dists/wii/meta.xml + dists/android/AndroidManifest.xml backends/platform/psp/README.PSP ); From b90ca013a814fd1023254543217c554382a3bd67 Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Sun, 6 Jun 2010 12:37:43 +0000 Subject: [PATCH 229/249] PSP: added news item about switch to media engine for MP3 playback svn-id: r49450 --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index 9ab98dc4e51..e46bb302b46 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ For a more comprehensive changelog for the latest experimental SVN code, see: PSP port: - Switched to new backend design which fixes minor graphical issues, speeds things up, and provides 16-bit support. + - Enabled playback of MP3 files using the hardware decoder (ME). This means that + the port is now optimized for MP3 playback (as opposed to OGG). General: - Switched to the "fast" DOSBox OPL emulator. From 43c353d9308515e0ce4d73773e50810f9e89ae47 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 6 Jun 2010 13:04:24 +0000 Subject: [PATCH 230/249] Now opening all files via getVolumeFile() svn-id: r49451 --- engines/sci/resource.cpp | 20 ++++++++------------ engines/sci/resource.h | 2 +- engines/sci/resource_audio.cpp | 7 +------ 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index b17117a1cdc..f22c4d75fe8 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -299,10 +299,15 @@ bool ResourceManager::loadFromPatchFile(Resource *res) { return loadPatch(res, &file); } -Common::File *ResourceManager::getVolumeFile(const char *filename) { +Common::SeekableReadStream *ResourceManager::getVolumeFile(ResourceSource *source) { Common::List::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; @@ -353,13 +358,7 @@ void ResourceManager::loadResource(Resource *res) { return; } - Common::SeekableReadStream *fileStream; - - // Either loading from volume or patch loading failed - if (res->_source->resourceFile) - fileStream = res->_source->resourceFile->createReadStream(); - else - fileStream = getVolumeFile(res->_source->location_name.c_str()); + Common::SeekableReadStream *fileStream = getVolumeFile(res->_source); if (!fileStream) { warning("Failed to open %s", res->_source->location_name.c_str()); @@ -1604,10 +1603,7 @@ ResourceCompression ResourceManager::getViewCompression() { if (res->_source->source_type != kSourceVolume) continue; - if (res->_source->resourceFile) - fileStream = res->_source->resourceFile->createReadStream(); - else - fileStream = getVolumeFile(res->_source->location_name.c_str()); + fileStream = getVolumeFile(res->_source); if (!fileStream) continue; diff --git a/engines/sci/resource.h b/engines/sci/resource.h index bc08154fedc..4c7068c5806 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -393,7 +393,7 @@ 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::SeekableReadStream *file); bool loadFromPatchFile(Resource *res); diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index ebc549c7722..57efbdcb388 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -33,12 +33,7 @@ namespace Sci { void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) { - Common::SeekableReadStream *fileStream; - - if (source->resourceFile) - fileStream = source->resourceFile->createReadStream(); - else - fileStream = getVolumeFile(source->location_name.c_str()); + Common::SeekableReadStream *fileStream = getVolumeFile(source); if (!fileStream) { warning("Failed to open %s", source->location_name.c_str()); From 8e6cc1201a43dbba52daa528c07622f02d121c3d Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Sun, 6 Jun 2010 13:31:19 +0000 Subject: [PATCH 231/249] use palette image during sequence 3 scrolling svn-id: r49452 --- engines/tucker/sequences.cpp | 30 +++++++++++++++++++----------- engines/tucker/tucker.h | 3 ++- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp index 68f5301a802..e8e81bde2df 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; } @@ -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); } diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h index d9810c79296..d33b9d1e079 100644 --- a/engines/tucker/tucker.h +++ b/engines/tucker/tucker.h @@ -975,7 +975,8 @@ private: uint8 *_offscreenBuffer; int _updateScreenWidth; int _updateScreenPicture; - int _updateScreenOffset; + int _updateScreenCounter; + int _updateScreenIndex; int _frameCounter; int _frameTime; uint32 _lastFrameTime; From 4667907b5cf9da3336352053b16b84484adf0393 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 6 Jun 2010 13:35:08 +0000 Subject: [PATCH 232/249] whitespace corrections svn-id: r49453 --- backends/platform/android/android.cpp | 6 +++--- .../android/org/inodes/gus/scummvm/PluginProvider.java | 2 +- .../platform/android/org/inodes/gus/scummvm/ScummVM.java | 2 +- .../android/org/inodes/gus/scummvm/ScummVMActivity.java | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 76590ec823f..a6258df5541 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -703,10 +703,10 @@ void OSystem_Android::setPalette(const byte* colors, uint start, uint num) { palette += 3; colors += 4; } while (--num); -} - +} + void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { - ENTER("grabPalette(%p, %u, %u)", colors, start, num); + ENTER("grabPalette(%p, %u, %u)", colors, start, num); const byte* palette = _game_texture->palette_const() + start*3; do { for (int i = 0; i < 3; ++i) diff --git a/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java b/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java index b4035a296b1..840f3440d52 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java +++ b/backends/platform/android/org/inodes/gus/scummvm/PluginProvider.java @@ -42,7 +42,7 @@ public class PluginProvider extends BroadcastReceiver { .authority(context.getPackageName()) .path(mylib) .toString()); - + extras.putStringArrayList(ScummVMApplication.EXTRA_UNPACK_LIBS, all_libs); } diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java index bc0c5ef408f..f4dca0e7e58 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java @@ -42,7 +42,7 @@ public class ScummVM implements SurfaceHolder.Callback { create(context.getAssets()); // Init C++ code, set nativeScummVM } - private native void nativeDestroy(); + private native void nativeDestroy(); public synchronized void destroy() { if (nativeScummVM != 0) { diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java index 29e1eba3d39..fb3cd6348fb 100644 --- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java +++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java @@ -83,7 +83,7 @@ public class ScummVMActivity extends Activity { } }); } - } + } } private MyScummVM scummvm; private Thread scummvm_thread; @@ -353,7 +353,7 @@ public class ScummVMActivity extends Activity { e.kbd_ascii = kevent.getUnicodeChar(); if (e.kbd_ascii == 0) e.kbd_ascii = e.kbd_keycode; // scummvm keycodes are mostly ascii - + e.kbd_flags = 0; if (kevent.isAltPressed()) From 48cfc944216c863ea59160a54739799af21d1768 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 6 Jun 2010 13:36:55 +0000 Subject: [PATCH 233/249] Add Gus to credits, update README & NEWS svn-id: r49454 --- AUTHORS | 3 +++ COPYRIGHT | 1 + NEWS | 5 ++++- README | 21 ++++++++++++++------- gui/credits.h | 3 +++ tools/credits.pl | 4 ++++ 6 files changed, 29 insertions(+), 8 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7a8490ddf78..28d71b36987 100644 --- a/AUTHORS +++ b/AUTHORS @@ -166,6 +166,9 @@ ScummVM Team Backend Teams ------------- + Android: + Angus Lees + Dreamcast: Marcus Comstedt diff --git a/COPYRIGHT b/COPYRIGHT index 980ca32463f..cc522d2215f 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -48,6 +48,7 @@ Martin Kiewitz Pawel Kolodziejski Mutwin Kraus Andrew Kurushin +Angus Lees Claudio Matsuoka Thomas Mayer Neil Millstone diff --git a/NEWS b/NEWS index e46bb302b46..32fe9a81c67 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ For a more comprehensive changelog for the latest experimental SVN code, see: http://scummvm.svn.sourceforge.net/viewvc/scummvm/?view=log 1.2.0 (????-??-??) + New Ports: + - Added Android port. + PSP port: - Switched to new backend design which fixes minor graphical issues, speeds things up, and provides 16-bit support. @@ -20,7 +23,7 @@ For a more comprehensive changelog for the latest experimental SVN code, see: 1.1.1 (2010-05-02) New Ports: - - Added Nintendo 64 Port. (Actually added in 1.1.0, but forgot to mention it. oops) + - Added Nintendo 64 port. (Actually added in 1.1.0, but forgot to mention it. oops) General: - Fixed several minor bugs here and there. diff --git a/README b/README index 043a087fab3..3c97bbbbd70 100644 --- a/README +++ b/README @@ -81,9 +81,10 @@ You can find a thorough list with details on which games are supported and how well on the compatibility page. ScummVM is continually improving, so check back often. -Among the systems on which you can play those games are Windows, Linux, -Mac OS X, Dreamcast, PocketPC, PalmOS, AmigaOS, BeOS, OS/2, PSP, PS2, -SymbianOS/EPOC, iPhone and many more. +Among the systems on which you can play those games are regular desktop +computers (running Windows, Linux, Mac OS X, ...), game consoles +(Dreamcast, Nintendo DS & Wii, PS2, PSP, ...), smartphones (Android, +iPhone, PocketPC, Symbian ...) and more. At this time ScummVM should be considered beta software, and is still under heavy development. Be aware that whilst we attempt to make sure @@ -843,21 +844,25 @@ contact us! Supported platforms include (but are not limited to): - UNIX (Linux, Solaris, IRIX, *BSD) + UNIX (Linux, Solaris, IRIX, *BSD, ...) Windows Windows CE and Windows Mobile (including Smartphones and PocketPCs) Mac OS X AmigaOS + Android BeOS Dreamcast - iPhone (also includes the iPod Touch) + GP2x + iPhone (also includes iPod Touch and iPad) + Maemo (Nokia Internet tablets 770, N800, N810, N900) + Nintendo 64 Nintendo DS + Nintendo Wii + OS/2 PalmOS PlayStation 2 PlayStation Portable - RISC OS Symbian - Maemo (Nokia Internet tablets 770, N800, N810, N900) The Dreamcast port does not support The Curse of Monkey Island, nor The Dig. The PalmOS port does not support The Curse of Monkey Island, @@ -865,6 +870,8 @@ Beneath a Steel Sky, nor either Simon the Sorcerer 1 or 2. The Dig will only work on some Palm devices (those with a large dynamic heap). The Nintendo DS port does not support Full Throttle, The Dig, or The Curse of Monkey Island. +For more platform specific limitations, please refer to our Wiki: + http://wiki.scummvm.org/index.php/Platforms In the Macintosh port, the right mouse button is emulated via Cmd-Click (that is, you click the mouse button while holding the diff --git a/gui/credits.h b/gui/credits.h index 4bf3e429b0c..0df894a6428 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -189,6 +189,9 @@ static const char *credits[] = { "", "", "C1""Backend Teams", +"C1""Android", +"C0""Angus Lees", +"", "C1""Dreamcast", "C0""Marcus Comstedt", "", diff --git a/tools/credits.pl b/tools/credits.pl index 165834b9b9d..bff1251f7a2 100755 --- a/tools/credits.pl +++ b/tools/credits.pl @@ -666,6 +666,10 @@ begin_credits("Credits"); begin_section("Backend Teams"); + begin_section("Android"); + add_person("Angus Lees", "Gus", ""); + end_section(); + begin_section("Dreamcast"); add_person("Marcus Comstedt", "", ""); end_section(); From 536e6a9bc308153f36d3eaf509bc0e66bcefc5e7 Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Sun, 6 Jun 2010 13:40:15 +0000 Subject: [PATCH 234/249] fix sequence frame numbering (decrement if getCurFrame now returns the last decoded frame number) svn-id: r49455 --- engines/tucker/sequences.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp index e8e81bde2df..8b0d965987c 100644 --- a/engines/tucker/sequences.cpp +++ b/engines/tucker/sequences.cpp @@ -536,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))(); @@ -806,7 +806,7 @@ 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(); @@ -883,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) { @@ -951,13 +951,13 @@ void AnimationSequencePlayer::loadIntroSeq9_10() { } void AnimationSequencePlayer::playIntroSeq9_10() { - if (_flicPlayer[0].getCurFrame() >= 265 && _flicPlayer[0].getCurFrame() <= 296) { + if (_flicPlayer[0].getCurFrame() >= 263 && _flicPlayer[0].getCurFrame() <= 294) { drawPic1Part10(); _updateScreenWidth += 6; - } else if (_flicPlayer[0].getCurFrame() == 985) { + } else if (_flicPlayer[0].getCurFrame() == 983) { decodeNextAnimationFrame(0); drawPic2Part10(); - } else if (_flicPlayer[0].getCurFrame() >= 989 && _flicPlayer[0].getCurFrame() <= 997) { + } else if (_flicPlayer[0].getCurFrame() >= 987 && _flicPlayer[0].getCurFrame() <= 995) { drawPic1Part10(); _updateScreenWidth -= 25; if (_updateScreenWidth < 0) { From 857f3ab550e015f9560bafa6bf080619216140fa Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Sun, 6 Jun 2010 14:17:37 +0000 Subject: [PATCH 235/249] PSP: faster way of getting file size svn-id: r49457 --- backends/fs/psp/psp-stream.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/backends/fs/psp/psp-stream.cpp b/backends/fs/psp/psp-stream.cpp index 9bcbe9d7cf8..83ff095aa8a 100644 --- a/backends/fs/psp/psp-stream.cpp +++ b/backends/fs/psp/psp-stream.cpp @@ -24,6 +24,8 @@ */ #ifdef __PSP__ +#include +#include #include #include @@ -106,10 +108,11 @@ void *PSPIoStream::open() { _handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb"); // open if (_handle) { - // Get the file size - fseek((FILE *)_handle, 0, SEEK_END); // go to the end - _fileSize = ftell((FILE *)_handle); - fseek((FILE *)_handle, 0, SEEK_SET); // back to the beginning + // Get the file size. This way is much faster than going to the end of the file and back + SceIoStat stat; + sceIoGetstat(_path.c_str(), &stat); + _fileSize = *((uint32 *)(void *)&stat.st_size); // 4GB file is big enough for us + PSP_DEBUG_PRINT("%s filesize = %d\n", _path.c_str(), _fileSize); // Allocate the cache _cache = (char *)memalign(64, CACHE_SIZE); From 548015ac10c89da839343b12274123898c113df1 Mon Sep 17 00:00:00 2001 From: Gregory Montoir Date: Sun, 6 Jun 2010 14:18:16 +0000 Subject: [PATCH 236/249] add missing decodeNextAnimationFrame in default case for sequence 9 svn-id: r49458 --- engines/tucker/sequences.cpp | 29 ++++++++++++----------------- engines/tucker/tucker.h | 2 +- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp index 8b0d965987c..633ed2790d8 100644 --- a/engines/tucker/sequences.cpp +++ b/engines/tucker/sequences.cpp @@ -764,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 { @@ -812,7 +812,7 @@ void AnimationSequencePlayer::playIntroSeq19_20() { _flicPlayer[1].reset(); } - bool framesLeft = decodeNextAnimationFrame(0); + bool framesLeft = decodeNextAnimationFrame(0, false); if (surface) for (int i = 0; i < kScreenWidth * kScreenHeight; ++i) @@ -922,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]; @@ -951,22 +944,24 @@ void AnimationSequencePlayer::loadIntroSeq9_10() { } void AnimationSequencePlayer::playIntroSeq9_10() { - if (_flicPlayer[0].getCurFrame() >= 263 && _flicPlayer[0].getCurFrame() <= 294) { + const int nextFrame = _flicPlayer[0].getCurFrame() + 1; + if (nextFrame >= 263 && nextFrame <= 294) { + decodeNextAnimationFrame(0, false); drawPic1Part10(); _updateScreenWidth += 6; - } else if (_flicPlayer[0].getCurFrame() == 983) { + } else if (nextFrame == 983) { decodeNextAnimationFrame(0); drawPic2Part10(); - } else if (_flicPlayer[0].getCurFrame() >= 987 && _flicPlayer[0].getCurFrame() <= 995) { + } 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 d33b9d1e079..86f5843e772 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(); From 51a897845532cc1fe587352726051e5f420d5d68 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 6 Jun 2010 22:44:14 +0000 Subject: [PATCH 237/249] Throw a warning in kString(At) if the index is out-of-bounds instead of having it assert out. svn-id: r49464 --- engines/sci/engine/kernel32.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/engines/sci/engine/kernel32.cpp b/engines/sci/engine/kernel32.cpp index b1325432069..e093fa6fdff 100644 --- a/engines/sci/engine/kernel32.cpp +++ b/engines/sci/engine/kernel32.cpp @@ -524,8 +524,16 @@ 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) - return make_reg(0, s->_segMan->getString(argv[1])[argv[2].toUint16()]); + case 2: { // At (return value at an index) + Common::String string = s->_segMan->getString(argv[1]); + + if (argv[2].toUint16() >= string.size()) { + warning("kString(At): Out of bounds: %d/%d\n", argv[2].toUint16(), string.size()); + return NULL_REG; + } + + return make_reg(0, string[argv[2].toUint16()]); + } case 3: { // Atput (put value at an index) SciString *string = s->_segMan->lookupString(argv[1]); From 3c82b6578fa3bd4b3d91c1933dd390581dbe08d1 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 6 Jun 2010 23:00:33 +0000 Subject: [PATCH 238/249] Now that EngineState is not deleted when loading games, we can move some more state-related variables to it, and remove several FIXME's about non-const global variables. Also, the entries in the data stack are now deleted when loading (fixes a memory leak - thanks to digitall for this). svn-id: r49465 --- engines/sci/console.cpp | 38 ++-- engines/sci/engine/kevent.cpp | 2 +- engines/sci/engine/kmisc.cpp | 2 +- engines/sci/engine/savegame.cpp | 4 +- engines/sci/engine/scriptdebug.cpp | 44 ++--- engines/sci/engine/state.cpp | 4 + engines/sci/engine/state.h | 18 ++ engines/sci/engine/vm.cpp | 289 ++++++++++++++--------------- engines/sci/engine/vm.h | 32 +--- engines/sci/sci.cpp | 6 +- 10 files changed, 212 insertions(+), 227 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index bad39d30653..2549be9403f 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -75,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)); @@ -595,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("\n"); @@ -958,7 +958,7 @@ bool Console::cmdRestoreGame(int argc, const char **argv) { bool Console::cmdRestartGame(int argc, const char **argv) { _engine->_gamestate->restarting_flags |= SCI_GAME_IS_RESTARTING_NOW; - script_abort_flag = 1; + _engine->_gamestate->script_abort_flag = 1; return false; } @@ -1766,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"); } @@ -1791,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]); @@ -1829,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"); @@ -2072,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; } @@ -2085,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; } @@ -2729,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; diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index 3e096074e67..fd7711f1961 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -79,7 +79,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) { switch (curEvent.type) { case SCI_EVENT_QUIT: - quit_vm(); + quit_vm(s); break; case SCI_EVENT_KEYBOARD: diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 68dc2fbba45..f91ba0fd820 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -41,7 +41,7 @@ reg_t kRestartGame(EngineState *s, int argc, reg_t *argv) { s->shrinkStackToBase(); - script_abort_flag = 1; // Force vm to abort ASAP + s->script_abort_flag = 1; // Force vm to abort ASAP return NULL_REG; } diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 798f8894600..9bf23dedf5d 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -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)); } } @@ -915,7 +915,7 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { s->restoring = true; - script_abort_flag = 2; // Abort current game with replay + s->script_abort_flag = 2; // Abort current game with replay s->shrinkStackToBase(); } diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 103a0169725..159c278e8cb 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -190,12 +190,12 @@ 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)) { - const Object *obj = s->_segMan->getObject(scriptState.xs->objp); + const Object *obj = s->_segMan->getObject(s->xs->objp); if (!obj) - warning("Attempted to reference on non-object at %04x:%04x", PRINT_REG(scriptState.xs->objp)); + 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]))); } @@ -203,39 +203,39 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod 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; @@ -285,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 @@ -298,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->getBufSize(); - int opcode = scriptState.xs->addr.pc.offset >= code_buf_size ? 0 : code_buf[scriptState.xs->addr.pc.offset]; + 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: @@ -351,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/state.cpp b/engines/sci/engine/state.cpp index b642cd8dc9b..b4a04f88266 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -114,6 +114,10 @@ void EngineState::reset(bool isRestoring) { _throttleLastTime = 0; _throttleTrigger = false; + script_abort_flag = 0; + script_step_counter = 0; + script_gc_interval = GC_INTERVAL; + restoring = false; } diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index 431aac884ea..68e6a5516a3 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -148,8 +148,26 @@ 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); diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 36f5ec6893d..b04cc473b57 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) /** @@ -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); @@ -575,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. @@ -594,7 +587,7 @@ static void callKernelFunc(EngineState *s, int kernelFuncNum, int argc) { //warning("callk %s", kernelFunc.orig_name.c_str()); // TODO: SCI2.1 equivalent - if (g_loadFromLauncher >= 0 && ( + 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 @@ -605,8 +598,8 @@ static void callKernelFunc(EngineState *s, int kernelFuncNum, int argc) { // 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 = g_loadFromLauncher; - g_loadFromLauncher = -1; // invalidate slot, so that we don't load again + 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 @@ -637,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); } } @@ -725,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) @@ -746,20 +739,20 @@ void run_vm(EngineState *s, bool restoring) { #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 @@ -767,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->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: @@ -838,20 +831,20 @@ void run_vm(EngineState *s, bool restoring) { } #ifndef DISABLE_VALIDATIONS - if (scriptState.xs->sp < scriptState.xs->fp) + if (s->xs->sp < s->xs->fp) error("run_vm(): stack underflow, sp: %04x:%04x, fp: %04x:%04x", - PRINT_REG(*scriptState.xs->sp), PRINT_REG(*scriptState.xs->fp)); + 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) + if (s->xs->addr.pc.offset >= code_buf_size) error("run_vm(): program counter gone astray, addr: %d, code buffer size: %d", - scriptState.xs->addr.pc.offset, code_buf_size); + 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) { @@ -1082,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) @@ -1107,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; + + 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(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; + 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; @@ -1143,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 @@ -1170,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; + temp = ((opparams[1] >> 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, 0, opparams[0], 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, 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; @@ -1198,8 +1191,8 @@ 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? @@ -1208,7 +1201,7 @@ void run_vm(EngineState *s, bool restoring) { s->_executionStack.pop_back(); s->_executionStackPosChanged = true; - s->restAdjust = scriptState.restAdjust; // Update &rest + s->restAdjust = s->restAdjust; // Update &rest return; // "Hard" return } @@ -1224,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; @@ -1261,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) @@ -1269,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(scriptState.xs->argc - temp + 1, 0); // +1 because temp counts the paramcount while argc doesn't + s->restAdjust = MAX(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; @@ -1319,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); @@ -1333,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) @@ -1401,7 +1394,7 @@ 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: @@ -1411,7 +1404,7 @@ void run_vm(EngineState *s, bool restoring) { 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 @@ -1423,7 +1416,7 @@ 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: @@ -1433,7 +1426,7 @@ void run_vm(EngineState *s, bool restoring) { 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 @@ -1459,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; @@ -1676,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; } } @@ -1718,7 +1711,7 @@ 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; s->restarting_flags = SCI_GAME_WAS_RESTARTED; } else { @@ -1726,7 +1719,7 @@ static EngineState *_game_run(EngineState *&s) { if (restoring) { game_exit(s); s->restoring = false; - if (script_abort_flag == 2) { + if (s->script_abort_flag == 2) { debugC(2, kDebugLevelVM, "Restarting with replay()"); s->_executionStack.clear(); // Restart with replay @@ -1735,7 +1728,7 @@ 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 break; // exit loop @@ -1766,8 +1759,8 @@ 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; } diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 42ee55cd06a..67a6bd0dc38 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -224,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. @@ -430,7 +400,7 @@ int game_exit(EngineState *s); /** * Instructs the virtual machine to abort */ -void quit_vm(); +void quit_vm(EngineState *s); /** * Read a PMachine instruction from a memory buffer and return its length. diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 1de42ab1157..929bdf3307d 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -56,8 +56,6 @@ namespace Sci { -extern int g_loadFromLauncher; - SciEngine *g_sci = 0; @@ -259,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 From 1e56ea9ac9ec21490d2ee626d4c49cdf6794e2b0 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 7 Jun 2010 01:43:35 +0000 Subject: [PATCH 239/249] Change some kString subops to use the raw string directly instead of through a Common::String. Fixes usage with strings from kGetSaveFiles(). svn-id: r49468 --- engines/sci/engine/kernel32.cpp | 54 ++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/engines/sci/engine/kernel32.cpp b/engines/sci/engine/kernel32.cpp index e093fa6fdff..d2a3362acae 100644 --- a/engines/sci/engine/kernel32.cpp +++ b/engines/sci/engine/kernel32.cpp @@ -525,14 +525,10 @@ 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) - Common::String string = s->_segMan->getString(argv[1]); + if (argv[1].segment == s->_segMan->getStringSegmentId()) + return make_reg(0, s->_segMan->lookupString(argv[1])->getRawData()[argv[2].toUint16()]); - if (argv[2].toUint16() >= string.size()) { - warning("kString(At): Out of bounds: %d/%d\n", argv[2].toUint16(), string.size()); - return NULL_REG; - } - - return make_reg(0, string[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]); @@ -571,16 +567,28 @@ 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->_segMan->getSysStringsSegment()) { @@ -592,7 +600,7 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { s->_segMan->sysStrings->_strings[sysStringId]._value = (char *)calloc(index1 + count, sizeof(char)); } - strncpy(s->_segMan->sysStrings->_strings[sysStringId]._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]); @@ -602,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]; @@ -616,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; } From b04535d487dd292b16768b036a0b24fc6965ed36 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 7 Jun 2010 02:11:01 +0000 Subject: [PATCH 240/249] SCI: Adjust kGetSaveFiles for SCI32. svn-id: r49469 --- engines/sci/engine/kfile.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index c48fb4035f9..3e0ecd1a280 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -460,29 +460,37 @@ reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) { 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 *slot = s->_segMan->derefRegPtr(argv[2], 0); debug(3, "kGetSaveFiles(%s)", game_id.c_str()); Common::Array saves; listSavegames(saves); - s->r_acc = NULL_REG; + uint totalSaves = MIN(saves.size(), MAX_SAVEGAME_NR); - for (uint i = 0; i < MIN(saves.size(), MAX_SAVEGAME_NR); i++) { - *slot++ = s->r_acc; // Store savegame ID - ++s->r_acc.offset; // Increase number of files found + reg_t *slot = s->_segMan->derefRegPtr(argv[2], totalSaves); - s->_segMan->strcpy(nametarget, saves[i].name); - - // Increase name offset pointer accordingly - nametarget.offset += SCI_MAX_SAVENAME_LENGTH; + if (!slot) { + warning("kGetSaveFiles: %04X:%04X invalid or too small to hold slot data", PRINT_REG(argv[2])); + totalSaves = 0; } - s->_segMan->strcpy(nametarget, ""); // Terminate list + const uint bufSize = (totalSaves * SCI_MAX_SAVENAME_LENGTH) + 1; + char *saveNames = new char[bufSize]; + char *saveNamePtr = saveNames; - return s->r_acc; + for (uint i = 0; i < totalSaves; i++) { + *slot++ = make_reg(0, i); // Store slot + strcpy(saveNamePtr, saves[i].name); + saveNamePtr += SCI_MAX_SAVENAME_LENGTH; + } + + *saveNamePtr = 0; // Terminate list + + 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) { From d30d57b923ddad194071d3fc07d79385c1ce4a37 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 7 Jun 2010 02:11:19 +0000 Subject: [PATCH 241/249] SCI: Relax signature of kCreateTextBitmap. svn-id: r49470 --- engines/sci/engine/kernel.cpp | 2 +- engines/sci/engine/kernel32.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 0b7198d1bc0..6ebee2dfbd3 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -363,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, ".*"), diff --git a/engines/sci/engine/kernel32.cpp b/engines/sci/engine/kernel32.cpp index d2a3362acae..0afdc3f2eb4 100644 --- a/engines/sci/engine/kernel32.cpp +++ b/engines/sci/engine/kernel32.cpp @@ -804,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(readSelector(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; } From 1572524b645b9a40e097a99773cb40e7f954100c Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 7 Jun 2010 09:06:06 +0000 Subject: [PATCH 242/249] Moved destruction of globals and resource manager to common M4 engine base class - this fixes a bug where resources were still being tossed after the resource manager was destroyed svn-id: r49476 --- engines/m4/m4.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp index da271b10c97..a5db6660d8a 100644 --- a/engines/m4/m4.cpp +++ b/engines/m4/m4.cpp @@ -146,6 +146,8 @@ MadsM4Engine::~MadsM4Engine() { delete _ws; delete _random; delete _palette; + delete _globals; + delete _resourceManager; } Common::Error MadsM4Engine::run() { @@ -303,8 +305,6 @@ M4Engine::M4Engine(OSystem *syst, const M4GameDescription *gameDesc): MadsM4Engi } M4Engine::~M4Engine() { - delete _resourceManager; - delete _globals; delete _converse; } @@ -500,8 +500,6 @@ MadsEngine::MadsEngine(OSystem *syst, const M4GameDescription *gameDesc): MadsM4 } MadsEngine::~MadsEngine() { - delete _globals; - delete _resourceManager; } Common::Error MadsEngine::run() { From 43ec405ffe08cef3168c9618be6169e6d81290f8 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 7 Jun 2010 09:10:22 +0000 Subject: [PATCH 243/249] Some initial code for audio36 and sync36 patch support svn-id: r49477 --- engines/sci/resource.cpp | 77 +++++++++++++++++++++++++++++++--------- engines/sci/resource.h | 5 ++- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index f22c4d75fe8..5d60438f7f8 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -620,6 +620,9 @@ void ResourceManager::scanNewSources() { switch (source->source_type) { case kSourceDirectory: readResourcePatches(source); +#ifdef ENABLE_SCI32 + readResourcePatchesBase36(source); +#endif readWaveAudioPatches(); break; case kSourceExtMap: @@ -1063,10 +1066,10 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() { } // version-agnostic patch application -void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, int resnumber) { +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; @@ -1137,32 +1140,73 @@ 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 + // 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 "#" + + Common::String mask, name, inputName; + Common::ArchiveMemberList files; + //ResourceSource *psrcPatch; + + for (int i = kResourceTypeAudio36; i <= kResourceTypeSync36; ++i) { + // audio36 resources start with a @ + // sync36 resources start with a # + mask = (i == kResourceTypeAudio36) ? "@*.*" : "#*.*"; + SearchMan.listMatchingMembers(files, mask); + + 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 that audio36 and sync36 use a different naming scheme, because they cannot be described - // with a single resource number, but are a result of a 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 - Common::String mask, name; Common::ArchiveMemberList files; int number = -1; const char *szResType; ResourceSource *psrcPatch; - for (int i = kResourceTypeView; i <= kResourceTypeRobot; ++i) { - // TODO: add support for audio36 and sync36 files - // Such patches were introduced in SCI2, and didn't exist in SCI0-SCI1.1 - if (i == kResourceTypeAudio36 || i == kResourceTypeSync36) - continue; - + for (int i = kResourceTypeView; i <= kResourceTypeHeap; ++i) { files.clear(); szResType = getResourceTypeName((ResourceType)i); // SCI0 naming - type.nnn @@ -1173,6 +1217,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(); diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 4c7068c5806..43e61eaadb5 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -452,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 From 34f7c05e4dd0e7cd3f84576f57593d034f666d31 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 7 Jun 2010 09:19:42 +0000 Subject: [PATCH 244/249] Initial conversion of the AnimviewView class to use the expanded MadsAnimation class, rather than the older AAFile skeleton class svn-id: r49478 --- engines/m4/animation.cpp | 12 ++-- engines/m4/animation.h | 3 +- engines/m4/graphics.cpp | 11 +--- engines/m4/mads_anim.cpp | 128 ++++++++++---------------------------- engines/m4/mads_anim.h | 39 ++---------- engines/m4/mads_menus.cpp | 2 +- engines/m4/viewmgr.h | 13 ++++ 7 files changed, 63 insertions(+), 145 deletions(-) diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp index b372222bd0a..1142ba48d12 100644 --- a/engines/m4/animation.cpp +++ b/engines/m4/animation.cpp @@ -39,6 +39,11 @@ MadsAnimation::MadsAnimation(MadsM4Engine *vm, MadsView *view): Animation(vm), _ _skipLoad = false; _unkIndex = -1; _messageCtr= 0; + _field12 = 0; + + _currentFrame = 0; + _oldFrameEntry = 0; + _nextFrameTimer = _madsVm->_currentTimer; } MadsAnimation::~MadsAnimation() { @@ -237,12 +242,14 @@ void MadsAnimation::load(const Common::String &filename, int abortTimers) { _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); -warning("%d", spriteSet.getCount()); + ..?.. } +*/ // Initialise miscellaneous fields _currentFrame = 0; @@ -463,9 +470,6 @@ void MadsAnimation::loadInterface(M4Surface *&interfaceSurface, M4Surface *&dept MadsSceneResources sceneResources; sceneResources.load(_roomNumber, _interfaceFile.c_str(), 0, depthSurface, interfaceSurface); - // Rex only supports a single dialog draw style - assert(sceneResources.drawStyle == 2); - } else if (_animMode == 4) { // Load a scene interface interfaceSurface->madsLoadInterface(_interfaceFile); diff --git a/engines/m4/animation.h b/engines/m4/animation.h index 883d3f2de6f..5c7227a256a 100644 --- a/engines/m4/animation.h +++ b/engines/m4/animation.h @@ -63,7 +63,7 @@ public: #define ANIM_SPRITE_SET_SIZE 50 -enum MadsAnimationFlags {ANIM_CUSTOM_FONT = 0x20}; +enum MadsAnimationFlags {ANIM_CUSTOM_FONT = 0x20, ANIM_HAS_SOUND = 0x8000}; class MadsAnimation: public Animation { private: @@ -114,6 +114,7 @@ public: virtual void setCurrentFrame(int frameNumber); bool freeFlag() const { return _freeFlag; } + int roomNumber() const { return _roomNumber; } }; } // End of namespace M4 diff --git a/engines/m4/graphics.cpp b/engines/m4/graphics.cpp index 29aaa184a34..8624f18da1f 100644 --- a/engines/m4/graphics.cpp +++ b/engines/m4/graphics.cpp @@ -633,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) { @@ -658,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); diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp index 24a041e04d5..7709b657801 100644 --- a/engines/m4/mads_anim.cpp +++ b/engines/m4/mads_anim.cpp @@ -441,7 +441,11 @@ 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; _screenType = VIEWID_ANIMVIEW; _screenFlags.layer = LAYER_BACKGROUND; @@ -452,27 +456,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; } @@ -515,19 +520,26 @@ void AnimviewView::updateState() { _previousUpdate = g_system->getMillis(); } - // Check if we're ready for the next command - bool animRunning = false; - if (!animRunning) { + if (!_activeAnimation) { + readNextCommand(); + assert(_activeAnimation); + } + + // 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 +574,15 @@ void AnimviewView::readNextCommand() { if (strchr(_currentLine, '.') == NULL) strcat(_currentLine, ".aa"); - AAFile aaFile(_currentLine, _vm); + _activeAnimation = new MadsAnimation(_vm, this); + _activeAnimation->load(_currentLine, 0); - // 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); - } - - // Grab what the final palete will be - RGB8 destPalette[256]; - _vm->_palette->grabPalette(destPalette, 0, 256); + _backgroundSurface.loadBackground(_activeAnimation->roomNumber()); + _codeSurface.create(_backgroundSurface.width(), _backgroundSurface.height(), 1); + _codeSurface.clear(); + _spriteSlots.fullRefresh(); +/* // Handle scene transition switch (_transition) { case kTransitionNone: @@ -631,16 +612,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 +693,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 680c5ff9016..8c4a5e6fb76 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_menus.cpp b/engines/m4/mads_menus.cpp index d00272d31ee..94894e78be3 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); diff --git a/engines/m4/viewmgr.h b/engines/m4/viewmgr.h index 16c3d6ecc37..211e6087f48 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 { From b2678ddf52117773bf08bed260a6512464e286aa Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 7 Jun 2010 09:35:59 +0000 Subject: [PATCH 245/249] Changed a create call to setSize to fix compiler error svn-id: r49479 --- engines/m4/mads_anim.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp index 7709b657801..4400dbf0943 100644 --- a/engines/m4/mads_anim.cpp +++ b/engines/m4/mads_anim.cpp @@ -578,7 +578,7 @@ void AnimviewView::readNextCommand() { _activeAnimation->load(_currentLine, 0); _backgroundSurface.loadBackground(_activeAnimation->roomNumber()); - _codeSurface.create(_backgroundSurface.width(), _backgroundSurface.height(), 1); + _codeSurface.setSize(_backgroundSurface.width(), _backgroundSurface.height()); _codeSurface.clear(); _spriteSlots.fullRefresh(); From 62402e743ece682c19f986ab25c9941686262ef7 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 7 Jun 2010 10:17:44 +0000 Subject: [PATCH 246/249] Added extra positioning and dummy depths surface so that the introduction cutscene now starts up svn-id: r49480 --- engines/m4/mads_anim.cpp | 11 ++--------- engines/m4/mads_views.cpp | 25 +++++++++++++------------ engines/m4/mads_views.h | 7 ++++--- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp index 4400dbf0943..e1dbbaf106e 100644 --- a/engines/m4/mads_anim.cpp +++ b/engines/m4/mads_anim.cpp @@ -446,6 +446,7 @@ AnimviewView::AnimviewView(MadsM4Engine *vm): MadsView::_bgSurface = &_backgroundSurface; MadsView::_depthSurface = &_codeSurface; + MadsView::_yOffset = MADS_Y_OFFSET; _screenType = VIEWID_ANIMVIEW; _screenFlags.layer = LAYER_BACKGROUND; @@ -512,14 +513,6 @@ 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); @@ -579,7 +572,7 @@ void AnimviewView::readNextCommand() { _backgroundSurface.loadBackground(_activeAnimation->roomNumber()); _codeSurface.setSize(_backgroundSurface.width(), _backgroundSurface.height()); - _codeSurface.clear(); + _codeSurface.fillRect(_codeSurface.bounds(), 0xff); _spriteSlots.fullRefresh(); /* diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp index cfcb113dcd0..c7b4f76a001 100644 --- a/engines/m4/mads_views.cpp +++ b/engines/m4/mads_views.cpp @@ -170,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 @@ -196,7 +196,7 @@ void MadsSpriteSlots::drawForeground(View *view) { // Minimalised drawing assert(slot.spriteListIndex < (int)_sprites.size()); M4Sprite *spr = spriteSet.getFrame((slot.frameNumber & 0x7fff) - 1); - spr->copyTo(view, slot.xp, slot.yp, slot.depth, _owner._depthSurface, slot.scale, 0); + 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); @@ -211,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); } } } @@ -326,12 +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].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); } } @@ -855,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); } } @@ -1180,7 +1180,8 @@ 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); @@ -1201,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(); @@ -1209,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(); diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h index f44d640c8b8..29adb7048a7 100644 --- a/engines/m4/mads_views.h +++ b/engines/m4/mads_views.h @@ -98,7 +98,7 @@ public: void deleteTimer(int seqIndex); void drawBackground(); - void drawForeground(View *view); + void drawForeground(View *view, int yOffset); void setDirtyAreas(); void fullRefresh(); void cleanUp(); @@ -139,7 +139,7 @@ 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(); @@ -289,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}; @@ -398,6 +398,7 @@ public: M4Surface *_depthSurface; M4Surface *_bgSurface; + int _yOffset; public: MadsView(View *view); ~MadsView(); From d5b5a8dbaeac596d02ad6063a61f566c6c092de0 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 7 Jun 2010 11:44:52 +0000 Subject: [PATCH 247/249] Allow for the other audio36 patch naming schemes (Mac and some Torin ones). svn-id: r49482 --- engines/sci/resource.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 5d60438f7f8..d7005138176 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1150,18 +1150,23 @@ void ResourceManager::readResourcePatchesBase36(ResourceSource *source) { // 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 "#" + // 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 mask, name, inputName; + Common::String name, inputName; Common::ArchiveMemberList files; //ResourceSource *psrcPatch; for (int i = kResourceTypeAudio36; i <= kResourceTypeSync36; ++i) { - // audio36 resources start with a @ + // audio36 resources start with a @, A, or B // sync36 resources start with a # - mask = (i == kResourceTypeAudio36) ? "@*.*" : "#*.*"; - SearchMan.listMatchingMembers(files, mask); + 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(); From 8ef5d55edb5b463abca1adf0ed1f359ce94bd391 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 7 Jun 2010 13:47:14 +0000 Subject: [PATCH 248/249] Fix gcc warning about an comparison which is always false due to data type range. svn-id: r49484 --- engines/sci/resource.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index d7005138176..4818428663b 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1073,7 +1073,7 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, byte patchtype, patch_data_offset; int fsize; - if (resnumber == -1) + if (resnumber == 0xFFFF) return; if (source->resourceFile) { From 356728dab7f2c4cedf73684d7fe3b968be7396fd Mon Sep 17 00:00:00 2001 From: Yotam Barnoy Date: Mon, 7 Jun 2010 13:47:27 +0000 Subject: [PATCH 249/249] PSP: found bug in fast getMillis() implementation. Fixed it by adding a fixed amount to the time counter. svn-id: r49485 --- backends/platform/psp/osys_psp.cpp | 3 +-- backends/platform/psp/osys_psp.h | 2 ++ backends/platform/psp/thread.cpp | 41 +++++++++++++++++++++++++++--- backends/platform/psp/thread.h | 16 ++++++++++-- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp index a36ae1847fd..2043a4bef24 100644 --- a/backends/platform/psp/osys_psp.cpp +++ b/backends/platform/psp/osys_psp.cpp @@ -37,7 +37,6 @@ #include "backends/platform/psp/psppixelformat.h" #include "backends/platform/psp/osys_psp.h" #include "backends/platform/psp/powerman.h" -#include "backends/platform/psp/thread.h" #include "backends/saves/psp/psp-saves.h" #include "backends/timer/default/default-timer.h" @@ -300,7 +299,7 @@ bool OSystem_PSP::pollEvent(Common::Event &event) { } uint32 OSystem_PSP::getMillis() { - return PspThread::getMillis(); + return _pspRtc.getMillis(); } void OSystem_PSP::delayMillis(uint msecs) { diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h index 3f075d01396..a6c84ba39a0 100644 --- a/backends/platform/psp/osys_psp.h +++ b/backends/platform/psp/osys_psp.h @@ -40,6 +40,7 @@ #include "backends/platform/psp/input.h" #include "backends/platform/psp/audio.h" #include "backends/timer/psp/timer.h" +#include "backends/platform/psp/thread.h" #include @@ -59,6 +60,7 @@ private: InputHandler _inputHandler; PspAudio _audio; PspTimer _pspTimer; + PspRtc _pspRtc; void initSDL(); diff --git a/backends/platform/psp/thread.cpp b/backends/platform/psp/thread.cpp index 88e7b6fe386..4e7d5eada90 100644 --- a/backends/platform/psp/thread.cpp +++ b/backends/platform/psp/thread.cpp @@ -29,6 +29,7 @@ #include #include "backends/platform/psp/thread.h" +#include "backends/platform/psp/trace.h" void PspThread::delayMillis(uint32 ms) { sceKernelDelayThread(ms * 1000); @@ -38,15 +39,49 @@ void PspThread::delayMicros(uint32 us) { sceKernelDelayThread(us); } -uint32 PspThread::getMillis() { +void PspRtc::init() { // init our starting ticks uint32 ticks[2]; sceRtcGetCurrentTick((u64 *)ticks); - return (ticks[0]/1000); + + _startMillis = ticks[0]/1000; + _startMicros = ticks[0]; + //_lastMillis = ticks[0]/1000; //debug - only when we don't subtract startMillis } -uint32 PspThread::getMicros() { +#define MS_LOOP_AROUND 4294967 /* We loop every 2^32 / 1000 = 71 minutes */ +#define MS_LOOP_CHECK 60000 /* Threading can cause weird mixups without this */ + +// Note that after we fill up 32 bits ie 50 days we'll loop back to 0, which may cause +// unpredictable results +uint32 PspRtc::getMillis() { uint32 ticks[2]; + + sceRtcGetCurrentTick((u64 *)ticks); // can introduce weird thread delays + + uint32 millis = ticks[0]/1000; + millis -= _startMillis; // get ms since start of program + + if ((int)_lastMillis - (int)millis > MS_LOOP_CHECK) { // we must have looped around + if (_looped == false) { // check to make sure threads do this once + _looped = true; + _milliOffset += MS_LOOP_AROUND; // add the needed offset + PSP_DEBUG_PRINT("looping around. last ms[%d], curr ms[%d]\n", _lastMillis, millis); + } + } else { + _looped = false; + } + + _lastMillis = millis; + + return millis + _milliOffset; +} + +uint32 PspRtc::getMicros() { + uint32 ticks[2]; + sceRtcGetCurrentTick((u64 *)ticks); + ticks[0] -= _startMicros; + return ticks[0]; } diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h index e83eead68e9..380159fa2d9 100644 --- a/backends/platform/psp/thread.h +++ b/backends/platform/psp/thread.h @@ -32,8 +32,20 @@ class PspThread { public: static void delayMillis(uint32 ms); static void delayMicros(uint32 us); - static uint32 getMillis(); - static uint32 getMicros(); +}; + +class PspRtc { +private: + uint32 _startMillis; + uint32 _startMicros; + uint32 _lastMillis; + uint32 _milliOffset; // to prevent looping around of millis + bool _looped; // make sure we only loop once +public: + PspRtc() : _startMillis(0), _startMicros(0), _lastMillis(0), _milliOffset(0), _looped(false) { init(); } + void init(); + uint32 getMillis(); + uint32 getMicros(); }; enum ThreadPriority {