From cf82bef02ee2941ddad6664e34f3c94e35e015a3 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Fri, 8 Oct 2010 22:30:39 +0000 Subject: TOON: Merged Toon engine to ScummVM trunk svn-id: r53087 --- engines/toon/script.cpp | 506 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 506 insertions(+) create mode 100644 engines/toon/script.cpp (limited to 'engines/toon/script.cpp') diff --git a/engines/toon/script.cpp b/engines/toon/script.cpp new file mode 100644 index 0000000000..1187d0542c --- /dev/null +++ b/engines/toon/script.cpp @@ -0,0 +1,506 @@ +/* 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/endian.h" +#include "common/stream.h" +#include "common/util.h" +#include "common/system.h" + +#include "toon.h" +#include "script.h" + +namespace Toon { +EMCInterpreter::EMCInterpreter(ToonEngine *vm) : _vm(vm), _scriptData(0), _filename(0) { + +#define OPCODE(x) { &EMCInterpreter::x, #x } + static const OpcodeEntry opcodes[] = { + // 0x00 + OPCODE(op_jmp), + OPCODE(op_setRetValue), + OPCODE(op_pushRetOrPos), + OPCODE(op_push), + // 0x04 + OPCODE(op_push), + OPCODE(op_pushReg), + OPCODE(op_pushBPNeg), + OPCODE(op_pushBPAdd), + // 0x08 + OPCODE(op_popRetOrPos), + OPCODE(op_popReg), + OPCODE(op_popBPNeg), + OPCODE(op_popBPAdd), + // 0x0C + OPCODE(op_addSP), + OPCODE(op_subSP), + OPCODE(op_sysCall), + OPCODE(op_ifNotJmp), + // 0x10 + OPCODE(op_negate), + OPCODE(op_eval), + OPCODE(op_setRetAndJmp) + }; + _opcodes = opcodes; +#undef OPCODE +} + +bool EMCInterpreter::callback(Common::IFFChunk &chunk) { + switch (chunk._type) { + case MKID_BE('TEXT'): + _scriptData->text = new byte[chunk._size]; + assert(_scriptData->text); + if (chunk._stream->read(_scriptData->text, chunk._size) != chunk._size) + error("Couldn't read TEXT chunk from file '%s'", _filename); + break; + + case MKID_BE('ORDR'): + _scriptData->ordr = new uint16[chunk._size >> 1]; + assert(_scriptData->ordr); + if (chunk._stream->read(_scriptData->ordr, chunk._size) != chunk._size) + error("Couldn't read ORDR chunk from file '%s'", _filename); + + for (int i = (chunk._size >> 1) - 1; i >= 0; --i) + _scriptData->ordr[i] = READ_BE_UINT16(&_scriptData->ordr[i]); + break; + + case MKID_BE('DATA'): + _scriptData->data = new uint16[chunk._size >> 1]; + assert(_scriptData->data); + if (chunk._stream->read(_scriptData->data, chunk._size) != chunk._size) + error("Couldn't read DATA chunk from file '%s'", _filename); + + for (int i = (chunk._size >> 1) - 1; i >= 0; --i) + _scriptData->data[i] = READ_BE_UINT16(&_scriptData->data[i]); + break; + + default: + warning("Unexpected chunk '%s' of size %d found in file '%s'", Common::tag2string(chunk._type).c_str(), chunk._size, _filename); + } + + return false; +} + +bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Common::Array *opcodes) { + Common::SeekableReadStream *stream = _vm->resources()->openFile(filename); + if (!stream) { + error("Couldn't open script file '%s'", filename); + return false; // for compilers that don't support NORETURN + } + + memset(scriptData, 0, sizeof(EMCData)); + + _scriptData = scriptData; + _filename = filename; + + IFFParser iff(*stream); + Common::Functor1Mem< Common::IFFChunk &, bool, EMCInterpreter > c(this, &EMCInterpreter::callback); + iff.parse(c); + + if (!_scriptData->ordr) + error("No ORDR chunk found in file: '%s'", filename); + + if (!_scriptData->data) + error("No DATA chunk found in file: '%s'", filename); + + if (stream->err()) + error("Read error while parsing file '%s'", filename); + + delete stream; + + _scriptData->sysFuncs = opcodes; + + strncpy(_scriptData->filename, filename, 13); + _scriptData->filename[12] = 0; + + _scriptData = 0; + _filename = 0; + + return true; +} + +void EMCInterpreter::unload(EMCData *data) { + if (!data) + return; + + delete[] data->text; + delete[] data->ordr; + delete[] data->data; + + data->text = 0; + data->ordr = data->data = 0; +} + +void EMCInterpreter::init(EMCState *scriptStat, const EMCData *data) { + scriptStat->dataPtr = data; + scriptStat->ip = 0; + scriptStat->stack[EMCState::kStackLastEntry] = 0; + scriptStat->bp = EMCState::kStackSize + 1; + scriptStat->sp = EMCState::kStackLastEntry; + scriptStat->running = false; +} + +bool EMCInterpreter::start(EMCState *script, int function) { + if (!script->dataPtr) + return false; + + uint16 functionOffset = script->dataPtr->ordr[function]; + if (functionOffset == 0xFFFF) + return false; + + script->ip = &script->dataPtr->data[functionOffset+1]; + + return true; +} + +bool EMCInterpreter::isValid(EMCState *script) { + if (!script->ip || !script->dataPtr || _vm->shouldQuit()) + return false; + return true; +} + +bool EMCInterpreter::run(EMCState *script) { + + if (script->running) + return false; + + _parameter = 0; + + if (!script->ip) + return false; + + script->running = true; + + + // Should be no Problem at all to cast to uint32 here, since that's the biggest ptrdiff the original + // would allow, of course that's not realistic to happen to be somewhere near the limit of uint32 anyway. + const uint32 instOffset = (uint32)((const byte *)script->ip - (const byte *)script->dataPtr->data); + int16 code = *script->ip++; + int16 opcode = (code >> 8) & 0x1F; + + if (code & 0x8000) { + opcode = 0; + _parameter = code & 0x7FFF; + } else if (code & 0x4000) { + _parameter = (int8)(code); + } else if (code & 0x2000) { + _parameter = *script->ip++; + } else { + _parameter = 0; + } + + if (opcode > 18) { + error("Unknown script opcode: %d in file '%s' at offset 0x%.08X", opcode, script->dataPtr->filename, instOffset); + } else { + static bool EMCDebug = false; + if (EMCDebug ) + debugC(5, 0, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset*2, _opcodes[opcode].desc, _parameter, (uint)_parameter); + //debug(0, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset, _opcodes[opcode].desc, _parameter, (uint)_parameter); + + (this->*(_opcodes[opcode].proc))(script); + } + + script->running = false; + return (script->ip != 0); +} + +#pragma mark - +#pragma mark - Command implementations +#pragma mark - + +void EMCInterpreter::op_jmp(EMCState *script) { + script->ip = script->dataPtr->data + _parameter; +} + +void EMCInterpreter::op_setRetValue(EMCState *script) { + script->retValue = _parameter; +} + +void EMCInterpreter::op_pushRetOrPos(EMCState *script) { + switch (_parameter) { + case 0: + script->stack[--script->sp] = script->retValue; + break; + + case 1: + script->stack[--script->sp] = script->ip - script->dataPtr->data + 1; + script->stack[--script->sp] = script->bp; + script->bp = script->sp + 2; + break; + + default: + script->ip = 0; + } +} + +void EMCInterpreter::op_push(EMCState *script) { + script->stack[--script->sp] = _parameter; +} + +void EMCInterpreter::op_pushReg(EMCState *script) { + script->stack[--script->sp] = script->regs[_parameter]; +} + +void EMCInterpreter::op_pushBPNeg(EMCState *script) { + script->stack[--script->sp] = script->stack[(-(int32)(_parameter + 2)) + script->bp]; +} + +void EMCInterpreter::op_pushBPAdd(EMCState *script) { + script->stack[--script->sp] = script->stack[(_parameter - 1) + script->bp]; +} + +void EMCInterpreter::op_popRetOrPos(EMCState *script) { + switch (_parameter) { + case 0: + script->retValue = script->stack[script->sp++]; + break; + + case 1: + if (script->sp >= EMCState::kStackLastEntry) { + script->ip = 0; + } else { + script->bp = script->stack[script->sp++]; + script->ip = script->dataPtr->data + script->stack[script->sp++]; + } + break; + + default: + script->ip = 0; + } +} + +void EMCInterpreter::op_popReg(EMCState *script) { + script->regs[_parameter] = script->stack[script->sp++]; +} + +void EMCInterpreter::op_popBPNeg(EMCState *script) { + script->stack[(-(int32)(_parameter + 2)) + script->bp] = script->stack[script->sp++]; +} + +void EMCInterpreter::op_popBPAdd(EMCState *script) { + script->stack[(_parameter - 1) + script->bp] = script->stack[script->sp++]; +} + +void EMCInterpreter::op_addSP(EMCState *script) { + script->sp += _parameter; +} + +void EMCInterpreter::op_subSP(EMCState *script) { + script->sp -= _parameter; +} + +void EMCInterpreter::op_sysCall(EMCState *script) { + const uint8 id = _parameter; + + assert(script->dataPtr->sysFuncs); + assert(id < script->dataPtr->sysFuncs->size()); + + if ((*script->dataPtr->sysFuncs)[id] && ((*script->dataPtr->sysFuncs)[id])->isValid()) { + script->retValue = (*(*script->dataPtr->sysFuncs)[id])(script); + } else { + script->retValue = 0; + warning("Unimplemented system call 0x%.02X/%d used in file '%s'", id, id, script->dataPtr->filename); + } +} + +void EMCInterpreter::op_ifNotJmp(EMCState *script) { + if (!script->stack[script->sp++]) { + _parameter &= 0x7FFF; + script->ip = script->dataPtr->data + _parameter; + } +} + +void EMCInterpreter::op_negate(EMCState *script) { + int16 value = script->stack[script->sp]; + switch (_parameter) { + case 0: + if (!value) + script->stack[script->sp] = 1; + else + script->stack[script->sp] = 0; + break; + + case 1: + script->stack[script->sp] = -value; + break; + + case 2: + script->stack[script->sp] = ~value; + break; + + default: + warning("Unknown negation func: %d", _parameter); + script->ip = 0; + } +} + +void EMCInterpreter::op_eval(EMCState *script) { + int16 ret = 0; + bool error = false; + + int16 val1 = script->stack[script->sp++]; + int16 val2 = script->stack[script->sp++]; + + switch (_parameter) { + case 0: + ret = (val2 && val1) ? 1 : 0; + break; + + case 1: + ret = (val2 || val1) ? 1 : 0; + break; + + case 2: + ret = (val1 == val2) ? 1 : 0; + break; + + case 3: + ret = (val1 != val2) ? 1 : 0; + break; + + case 4: + ret = (val1 > val2) ? 1 : 0; + break; + + case 5: + ret = (val1 >= val2) ? 1 : 0; + break; + + case 6: + ret = (val1 < val2) ? 1 : 0; + break; + + case 7: + ret = (val1 <= val2) ? 1 : 0; + break; + + case 8: + ret = val1 + val2; + break; + + case 9: + ret = val2 - val1; + break; + + case 10: + ret = val1 * val2; + break; + + case 11: + ret = val2 / val1; + break; + + case 12: + ret = val2 >> val1; + break; + + case 13: + ret = val2 << val1; + break; + + case 14: + ret = val1 & val2; + break; + + case 15: + ret = val1 | val2; + break; + + case 16: + ret = val2 % val1; + break; + + case 17: + ret = val1 ^ val2; + break; + + default: + warning("Unknown evaluate func: %d", _parameter); + error = true; + } + + if (error) + script->ip = 0; + else + script->stack[--script->sp] = ret; +} + +void EMCInterpreter::op_setRetAndJmp(EMCState *script) { + if (script->sp >= EMCState::kStackLastEntry) { + script->ip = 0; + } else { + script->retValue = script->stack[script->sp++]; + uint16 temp = script->stack[script->sp++]; + script->stack[EMCState::kStackLastEntry] = 0; + script->ip = &script->dataPtr->data[temp]; + } +} + +void EMCInterpreter::saveState(EMCState* script, Common::WriteStream * stream) { + stream->writeSint16LE(script->bp); + stream->writeSint16LE(script->sp); + if (!script->ip) { + stream->writeSint16LE(-1); + } + else { + stream->writeSint16LE(script->ip - script->dataPtr->data); + } + + for (int32 i = 0; i < EMCState::kStackSize; i++) { + stream->writeSint16LE(script->stack[i]); + } + + for (int32 i = 0; i < 30; i++) { + stream->writeSint16LE(script->regs[i]); + } + + stream->writeSint16LE(script->retValue); + stream->writeByte(script->running); +} +void EMCInterpreter::loadState(EMCState* script, Common::ReadStream* stream) { + script->bp = stream->readSint16LE(); + script->sp = stream->readSint16LE(); + + int16 scriptIp = stream->readSint16LE(); + if(scriptIp == -1) { + script->ip = 0; + } + else { + script->ip = scriptIp + script->dataPtr->data; + } + + for (int32 i = 0; i < EMCState::kStackSize; i++) { + script->stack[i] = stream->readSint16LE(); + } + + for (int32 i = 0; i < 30; i++) { + script->regs[i] = stream->readSint16LE(); + } + + script->retValue = stream->readSint16LE(); + script->running = stream->readByte(); +} + +} // End of namespace Toon + -- cgit v1.2.3 From e11637c7bc41d59dc6a666d3f0399b9a699b2443 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Fri, 8 Oct 2010 22:45:28 +0000 Subject: TOON: Normalized include paths svn-id: r53089 --- engines/toon/script.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines/toon/script.cpp') diff --git a/engines/toon/script.cpp b/engines/toon/script.cpp index 1187d0542c..5598e8e10c 100644 --- a/engines/toon/script.cpp +++ b/engines/toon/script.cpp @@ -29,8 +29,8 @@ #include "common/util.h" #include "common/system.h" -#include "toon.h" -#include "script.h" +#include "toon/toon.h" +#include "toon/script.h" namespace Toon { EMCInterpreter::EMCInterpreter(ToonEngine *vm) : _vm(vm), _scriptData(0), _filename(0) { -- cgit v1.2.3 From eef9f7b57b493cfb7712fd47cb961d16e8ce878d Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 9 Oct 2010 11:11:26 +0000 Subject: TOON: Ran astyle over the toon engine (+ some manual corrections). svn-id: r53098 --- engines/toon/script.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'engines/toon/script.cpp') diff --git a/engines/toon/script.cpp b/engines/toon/script.cpp index 5598e8e10c..efd100db61 100644 --- a/engines/toon/script.cpp +++ b/engines/toon/script.cpp @@ -214,8 +214,8 @@ bool EMCInterpreter::run(EMCState *script) { error("Unknown script opcode: %d in file '%s' at offset 0x%.08X", opcode, script->dataPtr->filename, instOffset); } else { static bool EMCDebug = false; - if (EMCDebug ) - debugC(5, 0, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset*2, _opcodes[opcode].desc, _parameter, (uint)_parameter); + if (EMCDebug) + debugC(5, 0, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset * 2, _opcodes[opcode].desc, _parameter, (uint)_parameter); //debug(0, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset, _opcodes[opcode].desc, _parameter, (uint)_parameter); (this->*(_opcodes[opcode].proc))(script); @@ -457,16 +457,15 @@ void EMCInterpreter::op_setRetAndJmp(EMCState *script) { } } -void EMCInterpreter::saveState(EMCState* script, Common::WriteStream * stream) { +void EMCInterpreter::saveState(EMCState *script, Common::WriteStream *stream) { stream->writeSint16LE(script->bp); stream->writeSint16LE(script->sp); if (!script->ip) { stream->writeSint16LE(-1); - } - else { + } else { stream->writeSint16LE(script->ip - script->dataPtr->data); } - + for (int32 i = 0; i < EMCState::kStackSize; i++) { stream->writeSint16LE(script->stack[i]); } @@ -478,18 +477,17 @@ void EMCInterpreter::saveState(EMCState* script, Common::WriteStream * stream) { stream->writeSint16LE(script->retValue); stream->writeByte(script->running); } -void EMCInterpreter::loadState(EMCState* script, Common::ReadStream* stream) { +void EMCInterpreter::loadState(EMCState *script, Common::ReadStream *stream) { script->bp = stream->readSint16LE(); script->sp = stream->readSint16LE(); int16 scriptIp = stream->readSint16LE(); - if(scriptIp == -1) { + if (scriptIp == -1) { script->ip = 0; - } - else { + } else { script->ip = scriptIp + script->dataPtr->data; } - + for (int32 i = 0; i < EMCState::kStackSize; i++) { script->stack[i] = stream->readSint16LE(); } -- cgit v1.2.3 From 576d6429bcf2c7be379c1d3a6d9b916f93b90924 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 11 Oct 2010 21:27:28 +0000 Subject: TOON: Reduced CPU usage by about 40% svn-id: r53151 --- engines/toon/script.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines/toon/script.cpp') diff --git a/engines/toon/script.cpp b/engines/toon/script.cpp index efd100db61..06d482f4e2 100644 --- a/engines/toon/script.cpp +++ b/engines/toon/script.cpp @@ -175,7 +175,7 @@ bool EMCInterpreter::start(EMCState *script, int function) { } bool EMCInterpreter::isValid(EMCState *script) { - if (!script->ip || !script->dataPtr || _vm->shouldQuit()) + if (!script->ip || !script->dataPtr || _vm->shouldQuitGame()) return false; return true; } -- cgit v1.2.3