From a7cbe1fbd295518012cf7e342c92dff16ef4e142 Mon Sep 17 00:00:00 2001 From: djsrv Date: Sat, 13 Jun 2020 23:35:51 -0400 Subject: [PATCH] DIRECTOR: LINGO: Reduce compile/execute var reuse The compile/execute steps can and do happen at the same time, so this makes things slightly less messy. --- engines/director/lingo/lingo-builtins.cpp | 2 +- engines/director/lingo/lingo-bytecode.cpp | 41 ++++++++++++----------- engines/director/lingo/lingo-codegen.cpp | 8 ++--- engines/director/lingo/lingo-events.cpp | 4 +-- engines/director/lingo/lingo-the.cpp | 23 +++++++------ engines/director/lingo/lingo.cpp | 22 ++++++------ engines/director/lingo/lingo.h | 8 +++-- engines/director/resource.cpp | 4 +-- engines/director/score-loading.cpp | 16 +++++---- engines/director/score.cpp | 1 + engines/director/score.h | 1 + 11 files changed, 69 insertions(+), 61 deletions(-) diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp index 0e154e8d28a..35c1442c180 100644 --- a/engines/director/lingo/lingo-builtins.cpp +++ b/engines/director/lingo/lingo-builtins.cpp @@ -1617,7 +1617,7 @@ void LB::b_installMenu(int nargs) { } // TODO: Menu callbacks should probably not be in the movie's lingo archive - g_lingo->addCode(handlers.c_str(), kMovieScript, 1337); + g_lingo->addCode(handlers.c_str(), 0, kMovieScript, 1337); } Common::String Lingo::genMenuHandler(int *commandId, Common::String &command) { diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp index 4782579f3e7..b11c218ba8a 100644 --- a/engines/director/lingo/lingo-bytecode.cpp +++ b/engines/director/lingo/lingo-bytecode.cpp @@ -703,7 +703,7 @@ void LC::cb_zeropush() { g_lingo->push(d); } -void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType type, uint16 id, Common::String &archName) { +void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex, ScriptType type, uint16 id, Common::String &archName) { debugC(1, kDebugCompile, "Add V4 bytecode for type %s with id %d", scriptType2str(type), id); if (getScriptContext(type, id)) { @@ -713,9 +713,10 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty return; } - _currentScriptContext = new ScriptContext; + _assemblyArchive = archiveIndex; + _assemblyContext = new ScriptContext; _currentEntityId = id; - _archives[_archiveIndex].scriptContexts[type][id] = _currentScriptContext; + _archives[_assemblyArchive].scriptContexts[type][id] = _assemblyContext; if (stream.size() < 0x5c) { warning("Lscr header too small"); @@ -764,8 +765,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty stream.seek(globalsOffset); for (uint16 i = 0; i < globalsCount; i++) { uint16 index = stream.readUint16(); - if (index < _archives[_archiveIndex].names.size()) { - const char *name = _archives[_archiveIndex].names[index].c_str(); + if (index < _archives[_assemblyArchive].names.size()) { + const char *name = _archives[_assemblyArchive].names[index].c_str(); debugC(5, kDebugLoading, "%d: %s", i, name); if (!_globalvars.contains(name)) { _globalvars[name] = Symbol(); @@ -909,7 +910,7 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty break; } - _currentScriptContext->constants.push_back(constant); + _assemblyContext->constants.push_back(constant); } free(constsStore); @@ -989,8 +990,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty uint16 index = (uint16)READ_BE_UINT16(&codeStore[namePointer]); namePointer += 2; Common::String name; - if (index < _archives[_archiveIndex].names.size()) { - name = _archives[_archiveIndex].names[index]; + if (index < _archives[_assemblyArchive].names.size()) { + name = _archives[_assemblyArchive].names[index]; argMap[j] = index; } else { name = Common::String::format("arg_%d", j); @@ -1015,8 +1016,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty uint16 index = (uint16)READ_BE_UINT16(&codeStore[namePointer]); namePointer += 2; Common::String name; - if (index < _archives[_archiveIndex].names.size()) { - name = _archives[_archiveIndex].names[index]; + if (index < _archives[_assemblyArchive].names.size()) { + name = _archives[_assemblyArchive].names[index]; varMap[j] = index; } else { name = Common::String::format("var_%d", j); @@ -1057,7 +1058,7 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty warning("Opcode 0x%02x arg %d not a multiple of 6!", opcode, arg); } arg /= 6; - Datum constant = _currentScriptContext->constants[arg]; + Datum constant = _assemblyContext->constants[arg]; switch (constant.type) { case INT: g_lingo->code1(LC::c_intpush); @@ -1202,9 +1203,9 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty // Attach to handlers Symbol sym; - if (nameIndex < _archives[_archiveIndex].names.size()) { - debugC(5, kDebugLoading, "Function %d binding: %s()", i, _archives[_archiveIndex].names[nameIndex].c_str()); - sym = g_lingo->define(_archives[_archiveIndex].names[nameIndex], argCount, _currentAssembly, argNames, varNames); + if (nameIndex < _archives[_assemblyArchive].names.size()) { + debugC(5, kDebugLoading, "Function %d binding: %s()", i, _archives[_assemblyArchive].names[nameIndex].c_str()); + sym = g_lingo->define(_archives[_assemblyArchive].names[nameIndex], argCount, _currentAssembly, argNames, varNames); } else { warning("Function has unknown name id %d, skipping define", nameIndex); sym.name = new Common::String(); @@ -1217,8 +1218,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty } if (!skipdump && ConfMan.getBool("dump_scripts")) { - if (nameIndex < _archives[_archiveIndex].names.size()) - out.writeString(Common::String::format("function %s, %d args\n", _archives[_archiveIndex].names[nameIndex].c_str(), argCount)); + if (nameIndex < _archives[_assemblyArchive].names.size()) + out.writeString(Common::String::format("function %s, %d args\n", _archives[_assemblyArchive].names[nameIndex].c_str(), argCount)); else out.writeString(Common::String::format(", %d args\n", argCount)); @@ -1231,7 +1232,7 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty out.writeString(Common::String::format("\n\n")); } - _currentScriptContext->functions.push_back(sym); + _assemblyContext->functions.push_back(sym); _currentAssembly = nullptr; } @@ -1244,7 +1245,7 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty } -void Lingo::addNamesV4(Common::SeekableSubReadStreamEndian &stream) { +void Lingo::addNamesV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex) { debugC(1, kDebugCompile, "Add V4 script name index"); if (stream.size() < 0x14) { @@ -1276,7 +1277,7 @@ void Lingo::addNamesV4(Common::SeekableSubReadStreamEndian &stream) { stream.seek(offset); - _archives[_archiveIndex].names.clear(); + _archives[archiveIndex].names.clear(); Common::Array names; for (uint32 i = 0; i < count; i++) { @@ -1285,7 +1286,7 @@ void Lingo::addNamesV4(Common::SeekableSubReadStreamEndian &stream) { for (uint8 j = 0; j < size; j++) { name += stream.readByte(); } - _archives[_archiveIndex].names.push_back(name); + _archives[archiveIndex].names.push_back(name); debugC(5, kDebugLoading, "%d: \"%s\"", i, name.c_str()); } diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp index 1b5a00d5276..7378a1f08fb 100644 --- a/engines/director/lingo/lingo-codegen.cpp +++ b/engines/director/lingo/lingo-codegen.cpp @@ -73,8 +73,8 @@ Symbol Lingo::define(Common::String &name, int nargs, ScriptData *code, Common:: sym.maxArgs = nargs; sym.argNames = argNames; sym.varNames = varNames; - sym.ctx = _currentScriptContext; - sym.archiveIndex = _archiveIndex; + sym.ctx = _assemblyContext; + sym.archiveIndex = _assemblyArchive; if (debugChannelSet(1, kDebugCompile)) { uint pc = 0; @@ -97,9 +97,9 @@ Symbol Lingo::define(Common::String &name, int nargs, ScriptData *code, Common:: warning("Redefining handler '%s'", name.c_str()); if (!_eventHandlerTypeIds.contains(name)) { - _archives[_archiveIndex].functionHandlers[name] = sym; + _archives[_assemblyArchive].functionHandlers[name] = sym; } else { - _archives[_archiveIndex].eventHandlers[ENTITY_INDEX(_eventHandlerTypeIds[name], _currentEntityId)] = sym; + _archives[_assemblyArchive].eventHandlers[ENTITY_INDEX(_eventHandlerTypeIds[name], _currentEntityId)] = sym; } } diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp index 6e70c96a8ba..0f1c0e05dbc 100644 --- a/engines/director/lingo/lingo-events.cpp +++ b/engines/director/lingo/lingo-events.cpp @@ -102,8 +102,8 @@ int Lingo::getEventCount() { void Lingo::setPrimaryEventHandler(LEvent event, const Common::String &code) { debugC(3, kDebugLingoExec, "setting primary event handler (%s)", _eventHandlerTypes[event]); - _archives[_archiveIndex].primaryEventHandlers[event] = code; - addCode(code.c_str(), kGlobalScript, event); + _archives[0].primaryEventHandlers[event] = code; + addCode(code.c_str(), 0, kGlobalScript, event); } void Lingo::primaryEventHandler(LEvent event) { diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp index bba027ad5e8..fe708fe9076 100644 --- a/engines/director/lingo/lingo-the.cpp +++ b/engines/director/lingo/lingo-the.cpp @@ -378,15 +378,15 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) { break; case kTheKeyDownScript: d.type = STRING; - if (_archives[_archiveIndex].primaryEventHandlers.contains(kEventKeyDown)) - d.u.s = new Common::String(_archives[_archiveIndex].primaryEventHandlers[kEventKeyDown]); + if (_archives[0].primaryEventHandlers.contains(kEventKeyDown)) + d.u.s = new Common::String(_archives[0].primaryEventHandlers[kEventKeyDown]); else d.u.s = new Common::String(); break; case kTheKeyUpScript: d.type = STRING; - if (_archives[_archiveIndex].primaryEventHandlers.contains(kEventKeyUp)) - d.u.s = new Common::String(_archives[_archiveIndex].primaryEventHandlers[kEventKeyUp]); + if (_archives[0].primaryEventHandlers.contains(kEventKeyUp)) + d.u.s = new Common::String(_archives[0].primaryEventHandlers[kEventKeyUp]); else d.u.s = new Common::String(); break; @@ -480,8 +480,8 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) { break; case kTheMouseDownScript: d.type = STRING; - if (_archives[_archiveIndex].primaryEventHandlers.contains(kEventMouseDown)) - d.u.s = new Common::String(_archives[_archiveIndex].primaryEventHandlers[kEventMouseDown]); + if (_archives[0].primaryEventHandlers.contains(kEventMouseDown)) + d.u.s = new Common::String(_archives[0].primaryEventHandlers[kEventMouseDown]); else d.u.s = new Common::String(); break; @@ -499,8 +499,8 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) { break; case kTheMouseUpScript: d.type = STRING; - if (_archives[_archiveIndex].primaryEventHandlers.contains(kEventMouseUp)) - d.u.s = new Common::String(_archives[_archiveIndex].primaryEventHandlers[kEventMouseUp]); + if (_archives[0].primaryEventHandlers.contains(kEventMouseUp)) + d.u.s = new Common::String(_archives[0].primaryEventHandlers[kEventMouseUp]); else d.u.s = new Common::String(); break; @@ -563,8 +563,8 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) { break; case kTheTimeoutScript: d.type = STRING; - if (_archives[_archiveIndex].primaryEventHandlers.contains(kEventTimeout)) - d.u.s = new Common::String(_archives[_archiveIndex].primaryEventHandlers[kEventTimeout]); + if (_archives[0].primaryEventHandlers.contains(kEventTimeout)) + d.u.s = new Common::String(_archives[0].primaryEventHandlers[kEventTimeout]); else d.u.s = new Common::String(); break; @@ -1082,7 +1082,8 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) { warning("Lingo::setTheCast(): The cast %d not found. type: %d", id, castType); return; } - addCode(d.u.s->c_str(), kSpriteScript, id); + // FIXME: What if the cast member is in a different archive than the current one? + addCode(d.u.s->c_str(), _archiveIndex, kSpriteScript, id); castInfo->script = d.asString(); break; diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp index c3e5fd2d180..ae1edd14785 100644 --- a/engines/director/lingo/lingo.cpp +++ b/engines/director/lingo/lingo.cpp @@ -156,6 +156,10 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) { _currentScript = 0; _currentScriptContext = nullptr; + _assemblyArchive = 0; + _currentAssembly = nullptr; + _assemblyContext = nullptr; + _currentEntityId = 0; _currentChannelId = -1; _pc = 0; @@ -286,9 +290,7 @@ const char *Lingo::findNextDefinition(const char *s) { return NULL; } -void Lingo::addCode(const char *code, ScriptType type, uint16 id) { - pushContext(); - +void Lingo::addCode(const char *code, int archiveIndex, ScriptType type, uint16 id) { debugC(1, kDebugCompile, "Add code for type %s(%d) with id %d\n" "***********\n%s\n\n***********", scriptType2str(type), type, id, code); @@ -299,10 +301,11 @@ void Lingo::addCode(const char *code, ScriptType type, uint16 id) { warning("Script already defined for type %d, id %d", id, type); } - _currentScriptContext = new ScriptContext; + _assemblyArchive = archiveIndex; + _assemblyContext = new ScriptContext; _currentAssembly = new ScriptData; _currentEntityId = id; - _archives[_archiveIndex].scriptContexts[type][id] = _currentScriptContext; + _archives[_assemblyArchive].scriptContexts[type][id] = _assemblyContext; _methodVars = new Common::HashMap(); _linenumber = _colnumber = 1; @@ -399,7 +402,7 @@ void Lingo::addCode(const char *code, ScriptType type, uint16 id) { currentFunc.name = new Common::String("[unknown]"); } currentFunc.ctx = _currentScriptContext; - currentFunc.archiveIndex = _archiveIndex; + currentFunc.archiveIndex = _assemblyArchive; // arg names should be empty, but just in case Common::Array *argNames = new Common::Array; for (uint i = 0; i < _argstack.size(); i++) { @@ -429,10 +432,9 @@ void Lingo::addCode(const char *code, ScriptType type, uint16 id) { currentFunc.argNames = argNames; currentFunc.varNames = varNames; - _currentScriptContext->functions.push_back(currentFunc); + _assemblyContext->functions.push_back(currentFunc); + _assemblyContext = nullptr; _currentAssembly = nullptr; - - popContext(); } void Lingo::printStack(const char *s, uint pc) { @@ -1019,7 +1021,7 @@ void Lingo::runTests() { debug(">> Compiling file %s of size %d, id: %d", fileList[i].c_str(), size, counter); _hadError = false; - addCode(script, kMovieScript, counter); + addCode(script, 0, kMovieScript, counter); if (!debugChannelSet(-1, kDebugCompileOnly)) { if (!_hadError) diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h index 99374a5b5fc..b13070e3844 100644 --- a/engines/director/lingo/lingo.h +++ b/engines/director/lingo/lingo.h @@ -315,9 +315,9 @@ public: void restartLingo(bool keepSharedCast); - void addCode(const char *code, ScriptType type, uint16 id); - void addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType type, uint16 id, Common::String &archName); - void addNamesV4(Common::SeekableSubReadStreamEndian &stream); + void addCode(const char *code, int archiveIndex, ScriptType type, uint16 id); + void addCodeV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex, ScriptType type, uint16 id, Common::String &archName); + void addNamesV4(Common::SeekableSubReadStreamEndian &stream, int archiveIndex); void executeHandler(const Common::String &name); void executeScript(ScriptType type, uint16 id, uint16 function); void printStack(const char *s, uint pc); @@ -468,6 +468,8 @@ public: void processIf(int toplabel, int endlabel); void varCreate(const Common::String &name, bool global, SymbolHash *localvars = nullptr); + int _assemblyArchive; + ScriptContext *_assemblyContext; ScriptData *_currentAssembly; LexerDefineState _indef; LexerDefineState _indefStore; diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp index 3250dce9269..ae85dc053a1 100644 --- a/engines/director/resource.cpp +++ b/engines/director/resource.cpp @@ -79,7 +79,7 @@ void DirectorEngine::loadEXE(const Common::String movie) { if (iniStream) { char *script = (char *)calloc(iniStream->size() + 1, 1); iniStream->read(script, iniStream->size()); - _lingo->addCode(script, kMovieScript, 0); + _lingo->addCode(script, 0, kMovieScript, 0); _lingo->processEvent(kEventStartUp); free(script); } else { @@ -304,11 +304,9 @@ void DirectorEngine::loadSharedCastsFrom(Common::String filename) { debug(0, "@@@@ Loading Shared cast '%s'", filename.c_str()); debug(0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); - _lingo->_archiveIndex = 1; _sharedScore = new Score(this); _sharedScore->setArchive(sharedCast); _sharedScore->loadArchive(true); - _lingo->_archiveIndex = 0; } Cast *DirectorEngine::getCastMember(int castId) { diff --git a/engines/director/score-loading.cpp b/engines/director/score-loading.cpp index 208d73fa7b1..5a44fe95ee0 100644 --- a/engines/director/score-loading.cpp +++ b/engines/director/score-loading.cpp @@ -78,6 +78,8 @@ void Score::setArchive(Archive *archive) { } bool Score::loadArchive(bool isSharedCast) { + _lingoArchive = isSharedCast ? 1 : 0; + Common::Array clutList = _movieArchive->getResourceIDList(MKTAG('C', 'L', 'U', 'T')); Common::SeekableSubReadStreamEndian *r = nullptr; @@ -876,7 +878,7 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id, if (scriptId < _castScriptIds.size()) { int resourceId = _castScriptIds[scriptId]; Common::SeekableSubReadStreamEndian *r; - _lingo->addCodeV4(*(r = _movieArchive->getResource(MKTAG('L', 's', 'c', 'r'), resourceId)), ((ScriptCast *)member)->_scriptType, id, _macName); + _lingo->addCodeV4(*(r = _movieArchive->getResource(MKTAG('L', 's', 'c', 'r'), resourceId)), _lingoArchive, ((ScriptCast *)member)->_scriptType, id, _macName); delete r; } else { warning("Score::loadCastData(): Lingo context missing a resource entry for script %d referenced in cast %d", scriptId, id); @@ -888,7 +890,7 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id, if (ConfMan.getBool("dump_scripts")) dumpScript(ci->script.c_str(), ((ScriptCast *)member)->_scriptType, id); - _lingo->addCode(ci->script.c_str(), ((ScriptCast *)member)->_scriptType, id); + _lingo->addCode(ci->script.c_str(), _lingoArchive, ((ScriptCast *)member)->_scriptType, id); } else { warning("Score::loadCastData(): Wrong cast type: %d", member->_type); } @@ -1012,7 +1014,7 @@ void Score::loadActions(Common::SeekableSubReadStreamEndian &stream) { // continue; } if (!j->_value.empty()) { - _lingo->addCode(j->_value.c_str(), kFrameScript, j->_key); + _lingo->addCode(j->_value.c_str(), _lingoArchive, kFrameScript, j->_key); processImmediateFrameScript(j->_value, j->_key); } @@ -1023,7 +1025,7 @@ void Score::loadActions(Common::SeekableSubReadStreamEndian &stream) { void Score::loadLingoNames(Common::SeekableSubReadStreamEndian &stream) { if (_vm->getVersion() >= 4) { - _lingo->addNamesV4(stream); + _lingo->addNamesV4(stream, _lingoArchive); } else { error("Score::loadLingoNames: unsuported Director version (%d)", _vm->getVersion()); } @@ -1098,7 +1100,7 @@ void Score::loadScriptText(Common::SeekableSubReadStreamEndian &stream) { if (script.contains("\nmenu:") || script.hasPrefix("menu:")) return; - _lingo->addCode(script.c_str(), kMovieScript, _movieScriptCount); + _lingo->addCode(script.c_str(), _lingoArchive, kMovieScript, _movieScriptCount); _movieScriptCount++; } @@ -1129,7 +1131,7 @@ void Score::loadCastInfo(Common::SeekableSubReadStreamEndian &stream, uint16 id) dumpScript(ci->script.c_str(), kSpriteScript, id); if (!ci->script.empty()) - _lingo->addCode(ci->script.c_str(), kSpriteScript, id); + _lingo->addCode(ci->script.c_str(), _lingoArchive, kSpriteScript, id); ci->name = getString(castStrings[1]); ci->directory = getString(castStrings[2]); @@ -1157,7 +1159,7 @@ void Score::loadFileInfo(Common::SeekableSubReadStreamEndian &stream) { dumpScript(_script.c_str(), kMovieScript, _movieScriptCount); if (!_script.empty()) - _lingo->addCode(_script.c_str(), kMovieScript, _movieScriptCount); + _lingo->addCode(_script.c_str(), _lingoArchive, kMovieScript, _movieScriptCount); _movieScriptCount++; _changedBy = fileInfoStrings[1]; diff --git a/engines/director/score.cpp b/engines/director/score.cpp index e86a260e993..bbcf30d8bda 100644 --- a/engines/director/score.cpp +++ b/engines/director/score.cpp @@ -45,6 +45,7 @@ Score::Score(DirectorEngine *vm) { _backSurface = nullptr; _backSurface2 = nullptr; _lingo = _vm->getLingo(); + _lingoArchive = 0; _soundManager = _vm->getSoundManager(); _currentMouseDownSpriteId = 0; _currentClickOnSpriteId = 0; diff --git a/engines/director/score.h b/engines/director/score.h index e65d527c09e..ca5abdaabfa 100644 --- a/engines/director/score.h +++ b/engines/director/score.h @@ -239,6 +239,7 @@ private: uint16 _castArrayEnd; uint16 _movieScriptCount; Lingo *_lingo; + int _lingoArchive; DirectorSound *_soundManager; DirectorEngine *_vm;