TINSEL: Refactored Tinsel engine to use the Common coroutine scheduler

This commit is contained in:
Paul Gilbert 2012-05-11 23:10:12 +10:00
parent c6810c174e
commit 41692ef48a
32 changed files with 137 additions and 777 deletions

View file

@ -340,7 +340,7 @@ void RestoreActorProcess(int id, INT_CONTEXT *pic, bool savegameFlag) {
if (savegameFlag)
pic->resumeState = RES_SAVEGAME;
g_scheduler->createProcess(PID_TCODE, ActorRestoredProcess, &r, sizeof(r));
CoroScheduler.createProcess(PID_TCODE, ActorRestoredProcess, &r, sizeof(r));
}
/**
@ -358,7 +358,7 @@ void ActorEvent(int ano, TINSEL_EVENT event, PLR_EVENT be) {
atp.event = event;
atp.bev = be;
atp.pic = NULL;
g_scheduler->createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp));
CoroScheduler.createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp));
}
}
@ -369,7 +369,7 @@ void ActorEvent(CORO_PARAM, int ano, TINSEL_EVENT tEvent, bool bWait, int myEsca
ATP_INIT atp;
int index;
CORO_BEGIN_CONTEXT;
PPROCESS pProc;
Common::PPROCESS pProc;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
@ -389,7 +389,7 @@ void ActorEvent(CORO_PARAM, int ano, TINSEL_EVENT tEvent, bool bWait, int myEsca
myEscape);
if (atp.pic != NULL) {
_ctx->pProc = g_scheduler->createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp));
_ctx->pProc = CoroScheduler.createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp));
AttachInterpret(atp.pic, _ctx->pProc);
if (bWait)
@ -474,8 +474,8 @@ void StartTaggedActors(SCNHANDLE ah, int numActors, bool bRunScript) {
// Run actor's script for this scene
if (bRunScript) {
// Send in reverse order - they get swapped round in the scheduler
ActorEvent(nullContext, taggedActors[i].id, SHOWEVENT, false, 0);
ActorEvent(nullContext, taggedActors[i].id, STARTUP, false, 0);
ActorEvent(Common::nullContext, taggedActors[i].id, SHOWEVENT, false, 0);
ActorEvent(Common::nullContext, taggedActors[i].id, STARTUP, false, 0);
}
}
}

View file

@ -24,9 +24,9 @@
#ifndef TINSEL_BACKGND_H // prevent multiple includes
#define TINSEL_BACKGND_H
#include "common/coroutines.h"
#include "common/frac.h"
#include "common/rect.h"
#include "tinsel/coroutine.h"
#include "tinsel/dw.h" // for SCNHANDLE
#include "tinsel/palette.h" // palette definitions

View file

@ -255,17 +255,17 @@ void StartupBackground(CORO_PARAM, SCNHANDLE hFilm) {
g_BGspeed = ONE_SECOND / FROM_LE_32(pfilm->frate);
// Start display process for each reel in the film
g_scheduler->createProcess(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL));
CoroScheduler.createProcess(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL));
if (TinselV0) {
for (uint i = 1; i < FROM_LE_32(pfilm->numreels); ++i)
g_scheduler->createProcess(PID_REEL, BGotherProcess, &pfilm->reels[i], sizeof(FREEL));
CoroScheduler.createProcess(PID_REEL, BGotherProcess, &pfilm->reels[i], sizeof(FREEL));
}
if (g_pBG[0] == NULL)
ControlStartOff();
if (TinselV2 && (coroParam != nullContext))
if (TinselV2 && (coroParam != Common::nullContext))
CORO_GIVE_WAY;
CORO_END_CODE;

View file

@ -529,7 +529,7 @@ int BMVPlayer::MovieCommand(char cmd, int commandOffset) {
if (cmd & CD_PRINT) {
PRINT_CMD *pCmd = (PRINT_CMD *)(bigBuffer + commandOffset);
MovieText(nullContext, (int16)READ_LE_UINT16(&pCmd->stringId),
MovieText(Common::nullContext, (int16)READ_LE_UINT16(&pCmd->stringId),
(int16)READ_LE_UINT16(&pCmd->x),
(int16)READ_LE_UINT16(&pCmd->y),
pCmd->fontId,
@ -542,7 +542,7 @@ int BMVPlayer::MovieCommand(char cmd, int commandOffset) {
TALK_CMD *pCmd = (TALK_CMD *)(bigBuffer + commandOffset);
talkColor = TINSEL_RGB(pCmd->r, pCmd->g, pCmd->b);
MovieText(nullContext, (int16)READ_LE_UINT16(&pCmd->stringId),
MovieText(Common::nullContext, (int16)READ_LE_UINT16(&pCmd->stringId),
(int16)READ_LE_UINT16(&pCmd->x),
(int16)READ_LE_UINT16(&pCmd->y),
0,

View file

@ -24,12 +24,12 @@
#ifndef TINSEL_BMV_H
#define TINSEL_BMV_H
#include "common/coroutines.h"
#include "common/file.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "tinsel/coroutine.h"
#include "tinsel/object.h"
#include "tinsel/palette.h"

View file

@ -1,82 +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.
*/
#include "tinsel/coroutine.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
namespace Tinsel {
CoroContext nullContext = NULL; // FIXME: Avoid non-const global vars
#if COROUTINE_DEBUG
namespace {
static int s_coroCount = 0;
typedef Common::HashMap<Common::String, int> CoroHashMap;
static CoroHashMap *s_coroFuncs = 0;
static void changeCoroStats(const char *func, int change) {
if (!s_coroFuncs)
s_coroFuncs = new CoroHashMap();
(*s_coroFuncs)[func] += change;
}
static void displayCoroStats() {
debug("%d active coros", s_coroCount);
// Loop over s_coroFuncs and print info about active coros
if (!s_coroFuncs)
return;
for (CoroHashMap::const_iterator it = s_coroFuncs->begin();
it != s_coroFuncs->end(); ++it) {
if (it->_value != 0)
debug(" %3d x %s", it->_value, it->_key.c_str());
}
}
}
#endif
CoroBaseContext::CoroBaseContext(const char *func)
: _line(0), _sleep(0), _subctx(0) {
#if COROUTINE_DEBUG
_funcName = func;
changeCoroStats(_funcName, +1);
s_coroCount++;
#endif
}
CoroBaseContext::~CoroBaseContext() {
#if COROUTINE_DEBUG
s_coroCount--;
changeCoroStats(_funcName, -1);
debug("Deleting coro in %s at %p (subctx %p)",
_funcName, (void *)this, (void *)_subctx);
displayCoroStats();
#endif
delete _subctx;
}
} // End of namespace Tinsel

View file

@ -1075,7 +1075,7 @@ static void PrimeSceneHopper() {
uint32 vSize;
// Open the file (it's on the CD)
CdCD(nullContext);
CdCD(Common::nullContext);
if (!f.open(HOPPER_FILENAME))
error(CANNOT_FIND_FILE, HOPPER_FILENAME);
@ -1191,13 +1191,13 @@ static void HopAction() {
debugC(DEBUG_BASIC, kTinselDebugAnimations, "Scene hopper chose scene %xh,%d\n", hScene, eNumber);
if (FROM_LE_32(pEntry->flags) & fCall) {
SaveScene(nullContext);
NewScene(nullContext, g_pChosenScene->hScene, pEntry->eNumber, TRANS_FADE);
SaveScene(Common::nullContext);
NewScene(Common::nullContext, g_pChosenScene->hScene, pEntry->eNumber, TRANS_FADE);
}
else if (FROM_LE_32(pEntry->flags) & fHook)
HookScene(hScene, eNumber, TRANS_FADE);
else
NewScene(nullContext, hScene, eNumber, TRANS_CUT);
NewScene(Common::nullContext, hScene, eNumber, TRANS_CUT);
}
/**************************************************************************/
@ -1406,13 +1406,13 @@ static void InvTinselEvent(INV_OBJECT *pinvo, TINSEL_EVENT event, PLR_EVENT be,
return;
g_GlitterIndex = index;
g_scheduler->createProcess(PID_TCODE, ObjectProcess, &to, sizeof(to));
CoroScheduler.createProcess(PID_TCODE, ObjectProcess, &to, sizeof(to));
}
extern void ObjectEvent(CORO_PARAM, int objId, TINSEL_EVENT event, bool bWait, int myEscape, bool *result) {
// COROUTINE
CORO_BEGIN_CONTEXT;
PROCESS *pProc;
Common::PROCESS *pProc;
INV_OBJECT *pInvo;
OP_INIT op;
CORO_END_CONTEXT(_ctx);
@ -1428,7 +1428,7 @@ extern void ObjectEvent(CORO_PARAM, int objId, TINSEL_EVENT event, bool bWait, i
_ctx->op.event = event;
_ctx->op.myEscape = myEscape;
g_scheduler->createProcess(PID_TCODE, ObjectProcess, &_ctx->op, sizeof(_ctx->op));
CoroScheduler.createProcess(PID_TCODE, ObjectProcess, &_ctx->op, sizeof(_ctx->op));
if (bWait)
CORO_INVOKE_2(WaitInterpret, _ctx->pProc, result);
@ -3540,9 +3540,9 @@ extern void ConvAction(int index) {
}
if (g_thisConvPoly != NOPOLY)
PolygonEvent(nullContext, g_thisConvPoly, CONVERSE, 0, false, 0);
PolygonEvent(Common::nullContext, g_thisConvPoly, CONVERSE, 0, false, 0);
else
ActorEvent(nullContext, g_thisConvActor, CONVERSE, false, 0);
ActorEvent(Common::nullContext, g_thisConvActor, CONVERSE, false, 0);
}
}
@ -5128,7 +5128,7 @@ static void InvPickup(int index) {
if (TinselV2)
InvPutDown(index);
else
g_scheduler->createProcess(PID_TCODE, InvPdProcess, &index, sizeof(index));
CoroScheduler.createProcess(PID_TCODE, InvPdProcess, &index, sizeof(index));
}
}
}

View file

@ -48,13 +48,13 @@ void CdCD(CORO_PARAM) {
CORO_BEGIN_CODE(_ctx);
while (g_bChangingCD) {
if (g_scheduler->getCurrentProcess()) {
// FIXME: CdCD gets passed a nullContext in RegisterGlobals() and
if (CoroScheduler.getCurrentProcess()) {
// FIXME: CdCD gets passed a Common::nullContext in RegisterGlobals() and
// PrimeSceneHopper(), because I didn't know how to get a proper
// context without converting the whole calling stack to CORO'd
// functions. If these functions really get called while a CD
// change is requested, this needs to be resolved.
if (coroParam == nullContext)
if (coroParam == Common::nullContext)
error("CdCD needs context");
CORO_SLEEP(1);
} else

View file

@ -24,9 +24,9 @@
#ifndef TINSEL_DRIVES_H
#define TINSEL_DRIVES_H
#include "common/coroutines.h"
#include "common/stream.h"
#include "tinsel/dw.h"
#include "tinsel/coroutine.h"
namespace Tinsel {

View file

@ -108,7 +108,7 @@ static void FettleEffectPolys(int x, int y, int index, PMOVER pActor) {
epi.hEpoly = hPoly;
epi.pMover = pActor;
epi.index = index;
g_scheduler->createProcess(PID_TCODE, EffectProcess, &epi, sizeof(epi));
CoroScheduler.createProcess(PID_TCODE, EffectProcess, &epi, sizeof(epi));
}
}
}

View file

@ -22,10 +22,10 @@
* Also provides a couple of utility functions.
*/
#include "common/coroutines.h"
#include "tinsel/actors.h"
#include "tinsel/background.h"
#include "tinsel/config.h"
#include "tinsel/coroutine.h"
#include "tinsel/cursor.h"
#include "tinsel/dw.h"
#include "tinsel/events.h"
@ -276,7 +276,7 @@ static void WalkProcess(CORO_PARAM, const void *param) {
void WalkTo(int x, int y) {
WP_INIT to = { x, y };
g_scheduler->createProcess(PID_TCODE, WalkProcess, &to, sizeof(to));
CoroScheduler.createProcess(PID_TCODE, WalkProcess, &to, sizeof(to));
}
/**
@ -295,7 +295,7 @@ static void ProcessUserEvent(TINSEL_EVENT uEvent, const Common::Point &coOrds, P
if ((actor = GetTaggedActor()) != 0) {
// Event for a tagged actor
if (TinselV2)
ActorEvent(nullContext, actor, uEvent, false, 0);
ActorEvent(Common::nullContext, actor, uEvent, false, 0);
else
ActorEvent(actor, uEvent, be);
} else if ((hPoly = GetTaggedPoly()) != NOPOLY) {
@ -303,7 +303,7 @@ static void ProcessUserEvent(TINSEL_EVENT uEvent, const Common::Point &coOrds, P
if (!TinselV2)
RunPolyTinselCode(hPoly, uEvent, be, false);
else if (uEvent != PROV_WALKTO)
PolygonEvent(nullContext, hPoly, uEvent, 0, false, 0);
PolygonEvent(Common::nullContext, hPoly, uEvent, 0, false, 0);
} else {
GetCursorXY(&aniX, &aniY, true);
@ -312,7 +312,7 @@ static void ProcessUserEvent(TINSEL_EVENT uEvent, const Common::Point &coOrds, P
if ((hPoly = InPolygon(aniX, aniY, TAG)) != NOPOLY ||
(!TinselV2 && ((hPoly = InPolygon(aniX, aniY, EXIT)) != NOPOLY))) {
if (TinselV2 && (uEvent != PROV_WALKTO))
PolygonEvent(nullContext, hPoly, uEvent, 0, false, 0);
PolygonEvent(Common::nullContext, hPoly, uEvent, 0, false, 0);
else if (!TinselV2)
RunPolyTinselCode(hPoly, uEvent, be, false);
} else if ((uEvent == PROV_WALKTO) || (uEvent == WALKTO)) {
@ -604,7 +604,7 @@ void PolyTinselProcess(CORO_PARAM, const void *param) {
void PolygonEvent(CORO_PARAM, HPOLYGON hPoly, TINSEL_EVENT tEvent, int actor, bool bWait,
int myEscape, bool *result) {
CORO_BEGIN_CONTEXT;
PPROCESS pProc;
Common::PPROCESS pProc;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
@ -623,7 +623,7 @@ void PolygonEvent(CORO_PARAM, HPOLYGON hPoly, TINSEL_EVENT tEvent, int actor, bo
NULL, // No Object
myEscape);
if (to.pic != NULL) {
_ctx->pProc = g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
_ctx->pProc = CoroScheduler.createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
AttachInterpret(to.pic, _ctx->pProc);
if (bWait)
@ -640,14 +640,14 @@ void RunPolyTinselCode(HPOLYGON hPoly, TINSEL_EVENT event, PLR_EVENT be, bool tc
PTP_INIT to = { hPoly, event, be, tc, 0, NULL };
assert(!TinselV2);
g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
CoroScheduler.createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
}
void effRunPolyTinselCode(HPOLYGON hPoly, TINSEL_EVENT event, int actor) {
PTP_INIT to = { hPoly, event, PLR_NOEVENT, false, actor, NULL };
assert(!TinselV2);
g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
CoroScheduler.createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
}
/**

View file

@ -24,9 +24,9 @@
#ifndef TINSEL_EVENTS_H
#define TINSEL_EVENTS_H
#include "tinsel/dw.h"
#include "tinsel/coroutine.h"
#include "common/coroutines.h"
#include "common/rect.h"
#include "tinsel/dw.h"
namespace Tinsel {

View file

@ -145,7 +145,7 @@ static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) {
if (TinselV2) {
// The is only ever one cuncurrent fade
// But this could be a fade out and the fade in is still going!
g_scheduler->killMatchingProcess(PID_FADER);
CoroScheduler.killMatchingProcess(PID_FADER);
NoFadingPalettes();
}
@ -176,7 +176,7 @@ static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) {
fade.pPalQ = pPal;
// create a fader process for this palette
g_scheduler->createProcess(PID_FADER, FadeProcess, (void *)&fade, sizeof(FADE));
CoroScheduler.createProcess(PID_FADER, FadeProcess, (void *)&fade, sizeof(FADE));
}
}
}

View file

@ -361,7 +361,7 @@ byte *LockMem(SCNHANDLE offset) {
if (TinselV2) {
SetCD(pH->flags2 & fAllCds);
CdCD(nullContext);
CdCD(Common::nullContext);
}
LoadFile(pH);
}

View file

@ -9,7 +9,6 @@ MODULE_OBJS := \
bmv.o \
cliprect.o \
config.o \
coroutine.o \
cursor.o \
debugger.o \
detection.o \

View file

@ -1299,14 +1299,14 @@ static void SetOffWithinNodePath(PMOVER pMover, HPOLYGON StartPath, HPOLYGON Des
*/
void SSetActorDest(PMOVER pActor) {
if (pActor->UtargetX != -1 && pActor->UtargetY != -1) {
Stand(nullContext, pActor->actorID, pActor->objX, pActor->objY, 0);
Stand(Common::nullContext, pActor->actorID, pActor->objX, pActor->objY, 0);
if (pActor->UtargetX != -1 && pActor->UtargetY != -1) {
SetActorDest(pActor, pActor->UtargetX, pActor->UtargetY,
pActor->bIgPath, 0);
}
} else {
Stand(nullContext, pActor->actorID, pActor->objX, pActor->objY, 0);
Stand(Common::nullContext, pActor->actorID, pActor->objX, pActor->objY, 0);
}
}

View file

@ -243,13 +243,13 @@ static INT_CONTEXT *AllocateInterpretContext(GSORT gsort) {
for (i = 0, pic = g_icList; i < NUM_INTERPRET; i++, pic++) {
if (pic->GSort == GS_NONE) {
pic->pProc = g_scheduler->getCurrentProcess();
pic->pProc = CoroScheduler.getCurrentProcess();
pic->GSort = gsort;
return pic;
}
#ifdef DEBUG
else {
if (pic->pProc == g_scheduler->getCurrentProcess())
if (pic->pProc == CoroScheduler.getCurrentProcess())
error("Found unreleased interpret context");
}
#endif
@ -277,7 +277,7 @@ static void FreeWaitCheck(PINT_CONTEXT pic, bool bVoluntary) {
if ((g_icList + i)->waitNumber1 == pic->waitNumber2) {
(g_icList + i)->waitNumber1 = 0;
(g_icList + i)->resumeCode = bVoluntary ? RES_FINISHED : RES_CUTSHORT;
g_scheduler->reschedule((g_icList + i)->pProc);
CoroScheduler.reschedule((g_icList + i)->pProc);
break;
}
}
@ -301,7 +301,7 @@ static void FreeInterpretContextPi(INT_CONTEXT *pic) {
* Ensures that interpret contexts don't get lost when an Interpret()
* call doesn't complete.
*/
void FreeInterpretContextPr(PROCESS *pProc) {
void FreeInterpretContextPr(Common::PROCESS *pProc) {
INT_CONTEXT *pic;
int i;
@ -393,7 +393,7 @@ INT_CONTEXT *RestoreInterpretContext(INT_CONTEXT *ric) {
ic = AllocateInterpretContext(GS_NONE); // Sort will soon be overridden
memcpy(ic, ric, sizeof(INT_CONTEXT));
ic->pProc = g_scheduler->getCurrentProcess();
ic->pProc = CoroScheduler.getCurrentProcess();
ic->resumeState = RES_1;
LockCode(ic);
@ -422,7 +422,7 @@ void RegisterGlobals(int num) {
if (g_icList == NULL) {
error("Cannot allocate memory for interpret contexts");
}
g_scheduler->setResourceCallback(FreeInterpretContextPr);
CoroScheduler.setResourceCallback(FreeInterpretContextPr);
} else {
// Check size is still the same
assert(g_numGlobals == num);
@ -433,7 +433,7 @@ void RegisterGlobals(int num) {
if (TinselV2) {
// read initial values
CdCD(nullContext);
CdCD(Common::nullContext);
Common::File f;
if (!f.open(GLOBALS_FILENAME))
@ -839,7 +839,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
* Associates an interpret context with the
* process that will run it.
*/
void AttachInterpret(INT_CONTEXT *pic, PROCESS *pProc) {
void AttachInterpret(INT_CONTEXT *pic, Common::PROCESS *pProc) {
// Attach the process which is using this context
pic->pProc = pProc;
}
@ -869,9 +869,9 @@ static uint32 UniqueWaitNumber() {
/**
* WaitInterpret
*/
void WaitInterpret(CORO_PARAM, PPROCESS pWaitProc, bool *result) {
void WaitInterpret(CORO_PARAM, Common::PPROCESS pWaitProc, bool *result) {
int i;
PPROCESS currentProcess = g_scheduler->getCurrentProcess();
Common::PPROCESS currentProcess = CoroScheduler.getCurrentProcess();
assert(currentProcess);
assert(currentProcess != pWaitProc);
if (result) *result = false;

View file

@ -25,7 +25,7 @@
#define TINSEL_PCODE_H
#include "tinsel/events.h" // for TINSEL_EVENT
#include "tinsel/sched.h" // for PROCESS
#include "tinsel/sched.h" // for Common::PROCESS
namespace Common {
class Serializer;
@ -56,7 +56,7 @@ struct WorkaroundEntry;
struct INT_CONTEXT {
// Elements for interpret context management
PROCESS *pProc; ///< processes owning this context
Common::PROCESS *pProc; ///< processes owning this context
GSORT GSort; ///< sort of this context
// Previously parameters to Interpret()
@ -114,12 +114,12 @@ void SaveInterpretContexts(INT_CONTEXT *sICInfo);
void RegisterGlobals(int num);
void FreeGlobals();
void AttachInterpret(INT_CONTEXT *pic, PROCESS *pProc);
void AttachInterpret(INT_CONTEXT *pic, Common::PROCESS *pProc);
void WaitInterpret(CORO_PARAM, PPROCESS pWaitProc, bool *result);
void WaitInterpret(CORO_PARAM, Common::PPROCESS pWaitProc, bool *result);
#define NUM_INTERPRET (NUM_PROCESS - 20)
#define MAX_INTERPRET (MAX_PROCESSES - 20)
#define NUM_INTERPRET (CORO_NUM_PROCESS - 20)
#define MAX_INTERPRET (CORO_MAX_PROCESSES - 20)
/*----------------------------------------------------------------------*\
|* Library Procedure and Function codes parameter enums *|

View file

@ -23,9 +23,9 @@
* PointProcess()
*/
#include "common/coroutines.h"
#include "tinsel/actors.h"
#include "tinsel/background.h"
#include "tinsel/coroutine.h"
#include "tinsel/cursor.h"
#include "tinsel/dw.h"
#include "tinsel/events.h"
@ -265,7 +265,7 @@ void DisablePointing() {
if (hPoly != NOPOLY && PolyType(hPoly) == TAG && PolyIsPointedTo(hPoly)) {
SetPolyPointedTo(hPoly, false);
SetPolyTagWanted(hPoly, false, false, 0);
PolygonEvent(nullContext, hPoly, UNPOINT, 0, false, 0);
PolygonEvent(Common::nullContext, hPoly, UNPOINT, 0, false, 0);
}
}
@ -275,7 +275,7 @@ void DisablePointing() {
SetActorPointedTo(i, false);
SetActorTagWanted(i, false, false, 0);
ActorEvent(nullContext, i, UNPOINT, false, 0);
ActorEvent(Common::nullContext, i, UNPOINT, false, 0);
}
}
}

View file

@ -21,9 +21,9 @@
* Plays films within a scene, takes into account the actor in each 'column'. |
*/
#include "common/coroutines.h"
#include "tinsel/actors.h"
#include "tinsel/background.h"
#include "tinsel/coroutine.h"
#include "tinsel/dw.h"
#include "tinsel/film.h"
#include "tinsel/handle.h"
@ -395,7 +395,7 @@ static void SoundReelWaitCheck() {
if (--g_soundReelWait == 0) {
for (int i = 0; i < MAX_SOUNDREELS; i++) {
if (g_soundReels[i].hFilm) {
g_scheduler->createProcess(PID_REEL, ResSoundReel, &i, sizeof(i));
CoroScheduler.createProcess(PID_REEL, ResSoundReel, &i, sizeof(i));
}
}
}
@ -1001,7 +1001,7 @@ void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay
NewestFilm(hFilm, &pFilm->reels[i]);
ppi.column = i;
g_scheduler->createProcess(PID_REEL, PlayProcess, &ppi, sizeof(PPINIT));
CoroScheduler.createProcess(PID_REEL, PlayProcess, &ppi, sizeof(PPINIT));
}
if (TinselV2) {
@ -1011,7 +1011,7 @@ void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay
CORO_GIVE_WAY;
if (myescEvent && myescEvent != GetEscEvents())
g_scheduler->rescheduleAll();
CoroScheduler.rescheduleAll();
}
CORO_END_CODE;
@ -1063,7 +1063,7 @@ void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool spla
NewestFilm(hFilm, &pFilm->reels[i]);
_ctx->ppi.column = i;
g_scheduler->createProcess(PID_REEL, PlayProcess, &_ctx->ppi, sizeof(PPINIT));
CoroScheduler.createProcess(PID_REEL, PlayProcess, &_ctx->ppi, sizeof(PPINIT));
}
if (TinselV2) {
@ -1078,7 +1078,7 @@ void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool spla
// Wait until film changes or loop count increases
while (GetActorPresFilm(_ctx->i) == hFilm && GetLoopCount(_ctx->i) == _ctx->loopCount) {
if (myescEvent && myescEvent != GetEscEvents()) {
g_scheduler->rescheduleAll();
CoroScheduler.rescheduleAll();
break;
}
@ -1126,7 +1126,7 @@ void RestoreActorReels(SCNHANDLE hFilm, short reelnum, short z, int x, int y) {
NewestFilm(hFilm, &pfilm->reels[reelnum]);
// Start display process for the reel
g_scheduler->createProcess(PID_REEL, PlayProcess, &ppi, sizeof(ppi));
CoroScheduler.createProcess(PID_REEL, PlayProcess, &ppi, sizeof(ppi));
}
/**
@ -1160,7 +1160,7 @@ void RestoreActorReels(SCNHANDLE hFilm, int actor, int x, int y) {
NewestFilm(hFilm, &pFilm->reels[i]);
// Start display process for the reel
g_scheduler->createProcess(PID_REEL, PlayProcess, &ppi, sizeof(ppi));
CoroScheduler.createProcess(PID_REEL, PlayProcess, &ppi, sizeof(ppi));
g_soundReelWait++;
}

View file

@ -24,7 +24,7 @@
#ifndef TINSEL_PLAY_H // prevent multiple includes
#define TINSEL_PLAY_H
#include "tinsel/coroutine.h"
#include "common/coroutines.h"
#include "tinsel/dw.h"
#include "tinsel/multiobj.h"

View file

@ -1469,7 +1469,7 @@ static void SetExTags(SCNHANDLE ph) {
pts = &TagStates[SceneTags[i].offset];
for (j = 0; j < SceneTags[i].nooftags; j++, pts++) {
if (!pts->enabled)
DisableTag(nullContext, pts->tid);
DisableTag(Common::nullContext, pts->tid);
}
return;
}
@ -1873,7 +1873,7 @@ void InitPolygons(SCNHANDLE ph, int numPoly, bool bRestart) {
} else {
for (int i = numPoly - 1; i >= 0; i--) {
if (Polys[i]->polyType == TAG) {
PolygonEvent(nullContext, i, STARTUP, 0, false, 0);
PolygonEvent(Common::nullContext, i, STARTUP, 0, false, 0);
}
}
}

View file

@ -202,8 +202,8 @@ void KillMover(PMOVER pMover) {
pMover->bActive = false;
MultiDeleteObject(GetPlayfieldList(FIELD_WORLD), pMover->actorObj);
pMover->actorObj = NULL;
assert(g_scheduler->getCurrentProcess() != pMover->pProc);
g_scheduler->killProcess(pMover->pProc);
assert(CoroScheduler.getCurrentProcess() != pMover->pProc);
CoroScheduler.killProcess(pMover->pProc);
}
}
@ -856,10 +856,10 @@ void MoverProcessCreate(int X, int Y, int id, PMOVER pMover) {
iStruct.Y = Y;
iStruct.pMover = pMover;
g_scheduler->createProcess(PID_MOVER, T2MoverProcess, &iStruct, sizeof(MAINIT));
CoroScheduler.createProcess(PID_MOVER, T2MoverProcess, &iStruct, sizeof(MAINIT));
} else {
MoverProcessHelper(X, Y, id, pMover);
pMover->pProc = g_scheduler->createProcess(PID_MOVER, T1MoverProcess, &pMover, sizeof(PMOVER));
pMover->pProc = CoroScheduler.createProcess(PID_MOVER, T1MoverProcess, &pMover, sizeof(PMOVER));
}
}

View file

@ -31,7 +31,7 @@
namespace Tinsel {
struct OBJECT;
struct PROCESS;
struct Common::PROCESS;
enum NPS {NOT_IN, GOING_UP, GOING_DOWN, LEAVING, ENTERING};
@ -110,7 +110,7 @@ struct MOVER {
/* NOTE: If effect polys can overlap, this needs improving */
bool bInEffect;
PROCESS *pProc;
Common::PROCESS *pProc;
// Discworld 2 specific fields
int32 zOverride;

View file

@ -190,7 +190,7 @@ void sortActors(SAVED_DATA *sd) {
RestoreAuxScales(sd->SavedMoverInfo);
for (int i = 0; i < MAX_MOVERS; i++) {
if (sd->SavedMoverInfo[i].bActive)
Stand(nullContext, sd->SavedMoverInfo[i].actorID, sd->SavedMoverInfo[i].objX,
Stand(Common::nullContext, sd->SavedMoverInfo[i].actorID, sd->SavedMoverInfo[i].objX,
sd->SavedMoverInfo[i].objY, sd->SavedMoverInfo[i].hLastfilm);
}
}
@ -245,7 +245,7 @@ static void SortMAProcess(CORO_PARAM, const void *) {
void ResumeInterprets() {
// Master script only affected on restore game, not restore scene
if (!TinselV2 && (g_rsd == &g_sgData)) {
g_scheduler->killMatchingProcess(PID_MASTER_SCR, -1);
CoroScheduler.killMatchingProcess(PID_MASTER_SCR, -1);
FreeMasterInterpretContext();
}
@ -314,7 +314,7 @@ static int DoRestoreSceneFrame(SAVED_DATA *sd, int n) {
// Master script only affected on restore game, not restore scene
if (sd == &g_sgData) {
g_scheduler->killMatchingProcess(PID_MASTER_SCR);
CoroScheduler.killMatchingProcess(PID_MASTER_SCR);
KillGlobalProcesses();
FreeMasterInterpretContext();
}
@ -340,7 +340,7 @@ static int DoRestoreSceneFrame(SAVED_DATA *sd, int n) {
SetDoFadeIn(!g_bNoFade);
g_bNoFade = false;
StartupBackground(nullContext, sd->SavedBgroundHandle);
StartupBackground(Common::nullContext, sd->SavedBgroundHandle);
if (TinselV2) {
Offset(EX_USEXY, sd->SavedLoffset, sd->SavedToffset);
@ -354,7 +354,7 @@ static int DoRestoreSceneFrame(SAVED_DATA *sd, int n) {
if (TinselV2) {
// create process to sort out the moving actors
g_scheduler->createProcess(PID_MOVER, SortMAProcess, NULL, 0);
CoroScheduler.createProcess(PID_MOVER, SortMAProcess, NULL, 0);
g_bNotDoneYet = true;
RestoreActorZ(sd->savedActorZ);

View file

@ -193,7 +193,7 @@ void SendSceneTinselProcess(TINSEL_EVENT event) {
init.event = event;
init.hTinselCode = ss->hSceneScript;
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
CoroScheduler.createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
}
}
}
@ -271,7 +271,7 @@ static void LoadScene(SCNHANDLE scene, int entry) {
init.event = STARTUP;
init.hTinselCode = es->hScript;
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
CoroScheduler.createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
}
break;
}
@ -291,7 +291,7 @@ static void LoadScene(SCNHANDLE scene, int entry) {
init.event = STARTUP;
init.hTinselCode = ss->hSceneScript;
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
CoroScheduler.createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
}
}
@ -344,7 +344,7 @@ void EndScene() {
KillAllObjects();
// kill all destructable process
g_scheduler->killMatchingProcess(PID_DESTROY, PID_DESTROY);
CoroScheduler.killMatchingProcess(PID_DESTROY, PID_DESTROY);
}
/**
@ -405,16 +405,16 @@ void PrimeScene() {
if (!TinselV2)
EnableTags(); // Next scene with tags enabled
g_scheduler->createProcess(PID_SCROLL, ScrollProcess, NULL, 0);
g_scheduler->createProcess(PID_SCROLL, EffectPolyProcess, NULL, 0);
CoroScheduler.createProcess(PID_SCROLL, ScrollProcess, NULL, 0);
CoroScheduler.createProcess(PID_SCROLL, EffectPolyProcess, NULL, 0);
#ifdef DEBUG
if (g_ShowPosition)
g_scheduler->createProcess(PID_POSITION, CursorPositionProcess, NULL, 0);
CoroScheduler.createProcess(PID_POSITION, CursorPositionProcess, NULL, 0);
#endif
g_scheduler->createProcess(PID_TAG, TagProcess, NULL, 0);
g_scheduler->createProcess(PID_TAG, PointProcess, NULL, 0);
CoroScheduler.createProcess(PID_TAG, TagProcess, NULL, 0);
CoroScheduler.createProcess(PID_TAG, PointProcess, NULL, 0);
// init the current background
PrimeBackground();
@ -471,7 +471,7 @@ void DoHailScene(SCNHANDLE scene) {
init.event = NOEVENT;
init.hTinselCode = ss->hSceneScript;
g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
CoroScheduler.createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init));
}
}

View file

@ -32,8 +32,6 @@
namespace Tinsel {
Scheduler *g_scheduler = 0;
#include "common/pack-start.h" // START STRUCT PACKING
struct PROCESS_STRUC {
@ -53,471 +51,6 @@ static SCNHANDLE g_hSceneProcess;
static uint32 g_numGlobalProcess;
static PROCESS_STRUC *g_pGlobalProcess;
//--------------------- FUNCTIONS ------------------------
Scheduler::Scheduler() {
processList = 0;
pFreeProcesses = 0;
pCurrent = 0;
#ifdef DEBUG
// diagnostic process counters
numProcs = 0;
maxProcs = 0;
#endif
pRCfunction = 0;
active = new PROCESS;
active->pPrevious = NULL;
active->pNext = NULL;
g_scheduler = this; // FIXME HACK
}
Scheduler::~Scheduler() {
// Kill all running processes (i.e. free memory allocated for their state).
PROCESS *pProc = active->pNext;
while (pProc != NULL) {
delete pProc->state;
pProc->state = 0;
pProc = pProc->pNext;
}
free(processList);
processList = NULL;
delete active;
active = 0;
}
/**
* Kills all processes and places them on the free list.
*/
void Scheduler::reset() {
#ifdef DEBUG
// clear number of process in use
numProcs = 0;
#endif
if (processList == NULL) {
// first time - allocate memory for process list
processList = (PROCESS *)calloc(MAX_PROCESSES, sizeof(PROCESS));
// make sure memory allocated
if (processList == NULL) {
error("Cannot allocate memory for process data");
}
// fill with garbage
memset(processList, 'S', MAX_PROCESSES * sizeof(PROCESS));
}
// Kill all running processes (i.e. free memory allocated for their state).
PROCESS *pProc = active->pNext;
while (pProc != NULL) {
delete pProc->state;
pProc->state = 0;
pProc = pProc->pNext;
}
// no active processes
pCurrent = active->pNext = NULL;
// place first process on free list
pFreeProcesses = processList;
// link all other processes after first
for (int i = 1; i <= NUM_PROCESS; i++) {
processList[i - 1].pNext = (i == NUM_PROCESS) ? NULL : processList + i;
processList[i - 1].pPrevious = (i == 1) ? active : processList + (i - 2);
}
}
#ifdef DEBUG
/**
* Shows the maximum number of process used at once.
*/
void Scheduler::printStats() {
debug("%i process of %i used", maxProcs, NUM_PROCESS);
}
#endif
#ifdef DEBUG
/**
* Checks both the active and free process list to insure all the links are valid,
* and that no processes have been lost
*/
void Scheduler::CheckStack() {
Common::List<PROCESS *> pList;
// Check both the active and free process lists
for (int i = 0; i < 2; ++i) {
PROCESS *p = (i == 0) ? active : pFreeProcesses;
if (p != NULL) {
// Make sure the linkages are correct
while (p->pNext != NULL) {
assert(p->pNext->pPrevious == p);
pList.push_back(p);
p = p->pNext;
}
pList.push_back(p);
}
}
// Make sure all processes are accounted for
for (int idx = 0; idx < NUM_PROCESS; idx++) {
bool found = false;
for (Common::List<PROCESS *>::iterator i = pList.begin(); i != pList.end(); ++i) {
PROCESS *pTemp = *i;
if (*i == &processList[idx]) {
found = true;
break;
}
}
assert(found);
}
}
#endif
/**
* Give all active processes a chance to run
*/
void Scheduler::schedule() {
// start dispatching active process list
PROCESS *pNext;
PROCESS *pProc = active->pNext;
while (pProc != NULL) {
pNext = pProc->pNext;
if (--pProc->sleepTime <= 0) {
// process is ready for dispatch, activate it
pCurrent = pProc;
pProc->coroAddr(pProc->state, pProc->param);
if (!pProc->state || pProc->state->_sleep <= 0) {
// Coroutine finished
pCurrent = pCurrent->pPrevious;
killProcess(pProc);
} else {
pProc->sleepTime = pProc->state->_sleep;
}
// pCurrent may have been changed
pNext = pCurrent->pNext;
pCurrent = NULL;
}
pProc = pNext;
}
}
/**
* Reschedules all the processes to run again this query
*/
void Scheduler::rescheduleAll() {
assert(pCurrent);
// Unlink current process
pCurrent->pPrevious->pNext = pCurrent->pNext;
if (pCurrent->pNext)
pCurrent->pNext->pPrevious = pCurrent->pPrevious;
// Add process to the start of the active list
pCurrent->pNext = active->pNext;
active->pNext->pPrevious = pCurrent;
active->pNext = pCurrent;
pCurrent->pPrevious = active;
}
/**
* If the specified process has already run on this tick, make it run
* again on the current tick.
*/
void Scheduler::reschedule(PPROCESS pReSchedProc) {
// If not currently processing the schedule list, then no action is needed
if (!pCurrent)
return;
if (!pReSchedProc)
pReSchedProc = pCurrent;
PPROCESS pEnd;
// Find the last process in the list.
// But if the target process is down the list from here, do nothing
for (pEnd = pCurrent; pEnd->pNext != NULL; pEnd = pEnd->pNext) {
if (pEnd->pNext == pReSchedProc)
return;
}
assert(pEnd->pNext == NULL);
// Could be in the middle of a KillProc()!
// Dying process was last and this process was penultimate
if (pReSchedProc->pNext == NULL)
return;
// If we're moving the current process, move it back by one, so that the next
// schedule() iteration moves to the now next one
if (pCurrent == pReSchedProc)
pCurrent = pCurrent->pPrevious;
// Unlink the process, and add it at the end
pReSchedProc->pPrevious->pNext = pReSchedProc->pNext;
pReSchedProc->pNext->pPrevious = pReSchedProc->pPrevious;
pEnd->pNext = pReSchedProc;
pReSchedProc->pPrevious = pEnd;
pReSchedProc->pNext = NULL;
}
/**
* Moves the specified process to the end of the dispatch queue
* allowing it to run again within the current game cycle.
* @param pGiveProc Which process
*/
void Scheduler::giveWay(PPROCESS pReSchedProc) {
// If not currently processing the schedule list, then no action is needed
if (!pCurrent)
return;
if (!pReSchedProc)
pReSchedProc = pCurrent;
// If the process is already at the end of the queue, nothing has to be done
if (!pReSchedProc->pNext)
return;
PPROCESS pEnd;
// Find the last process in the list.
for (pEnd = pCurrent; pEnd->pNext != NULL; pEnd = pEnd->pNext)
;
assert(pEnd->pNext == NULL);
// If we're moving the current process, move it back by one, so that the next
// schedule() iteration moves to the now next one
if (pCurrent == pReSchedProc)
pCurrent = pCurrent->pPrevious;
// Unlink the process, and add it at the end
pReSchedProc->pPrevious->pNext = pReSchedProc->pNext;
pReSchedProc->pNext->pPrevious = pReSchedProc->pPrevious;
pEnd->pNext = pReSchedProc;
pReSchedProc->pPrevious = pEnd;
pReSchedProc->pNext = NULL;
}
/**
* Creates a new process.
*
* @param pid process identifier
* @param CORO_ADDR coroutine start address
* @param pParam process specific info
* @param sizeParam size of process specific info
*/
PROCESS *Scheduler::createProcess(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam) {
PROCESS *pProc;
// get a free process
pProc = pFreeProcesses;
// trap no free process
assert(pProc != NULL); // Out of processes
#ifdef DEBUG
// one more process in use
if (++numProcs > maxProcs)
maxProcs = numProcs;
#endif
// get link to next free process
pFreeProcesses = pProc->pNext;
if (pFreeProcesses)
pFreeProcesses->pPrevious = NULL;
if (pCurrent != NULL) {
// place new process before the next active process
pProc->pNext = pCurrent->pNext;
if (pProc->pNext)
pProc->pNext->pPrevious = pProc;
// make this new process the next active process
pCurrent->pNext = pProc;
pProc->pPrevious = pCurrent;
} else { // no active processes, place process at head of list
pProc->pNext = active->pNext;
pProc->pPrevious = active;
if (pProc->pNext)
pProc->pNext->pPrevious = pProc;
active->pNext = pProc;
}
// set coroutine entry point
pProc->coroAddr = coroAddr;
// clear coroutine state
pProc->state = 0;
// wake process up as soon as possible
pProc->sleepTime = 1;
// set new process id
pProc->pid = pid;
// set new process specific info
if (sizeParam) {
assert(sizeParam > 0 && sizeParam <= PARAM_SIZE);
// set new process specific info
memcpy(pProc->param, pParam, sizeParam);
}
// return created process
return pProc;
}
/**
* Kills the specified process.
*
* @param pKillProc which process to kill
*/
void Scheduler::killProcess(PROCESS *pKillProc) {
// make sure a valid process pointer
assert(pKillProc >= processList && pKillProc <= processList + NUM_PROCESS - 1);
// can not kill the current process using killProcess !
assert(pCurrent != pKillProc);
#ifdef DEBUG
// one less process in use
--numProcs;
assert(numProcs >= 0);
#endif
// Free process' resources
if (pRCfunction != NULL)
(pRCfunction)(pKillProc);
delete pKillProc->state;
pKillProc->state = 0;
// Take the process out of the active chain list
pKillProc->pPrevious->pNext = pKillProc->pNext;
if (pKillProc->pNext)
pKillProc->pNext->pPrevious = pKillProc->pPrevious;
// link first free process after pProc
pKillProc->pNext = pFreeProcesses;
if (pFreeProcesses)
pKillProc->pNext->pPrevious = pKillProc;
pKillProc->pPrevious = NULL;
// make pKillProc the first free process
pFreeProcesses = pKillProc;
}
/**
* Returns a pointer to the currently running process.
*/
PROCESS *Scheduler::getCurrentProcess() {
return pCurrent;
}
/**
* Returns the process identifier of the specified process.
*
* @param pProc which process
*/
int Scheduler::getCurrentPID() const {
PROCESS *pProc = pCurrent;
// make sure a valid process pointer
assert(pProc >= processList && pProc <= processList + NUM_PROCESS - 1);
// return processes PID
return pProc->pid;
}
/**
* Kills any process matching the specified PID. The current
* process cannot be killed.
*
* @param pidKill process identifier of process to kill
* @param pidMask mask to apply to process identifiers before comparison
* @return The number of processes killed is returned.
*/
int Scheduler::killMatchingProcess(int pidKill, int pidMask) {
int numKilled = 0;
PROCESS *pProc, *pPrev; // process list pointers
for (pProc = active->pNext, pPrev = active; pProc != NULL; pPrev = pProc, pProc = pProc->pNext) {
if ((pProc->pid & pidMask) == pidKill) {
// found a matching process
// dont kill the current process
if (pProc != pCurrent) {
// kill this process
numKilled++;
// Free the process' resources
if (pRCfunction != NULL)
(pRCfunction)(pProc);
delete pProc->state;
pProc->state = 0;
// make prev point to next to unlink pProc
pPrev->pNext = pProc->pNext;
if (pProc->pNext)
pPrev->pNext->pPrevious = pPrev;
// link first free process after pProc
pProc->pNext = pFreeProcesses;
pProc->pPrevious = NULL;
pFreeProcesses->pPrevious = pProc;
// make pProc the first free process
pFreeProcesses = pProc;
// set to a process on the active list
pProc = pPrev;
}
}
}
#ifdef DEBUG
// adjust process in use
numProcs -= numKilled;
assert(numProcs >= 0);
#endif
// return number of processes killed
return numKilled;
}
/**
* Set pointer to a function to be called by killProcess().
*
* May be called by a resource allocator, the function supplied is
* called by killProcess() to allow the resource allocator to free
* resources allocated to the dying process.
*
* @param pFunc Function to be called by killProcess()
*/
void Scheduler::setResourceCallback(VFPTRPP pFunc) {
pRCfunction = pFunc;
}
/**************************************************************************\
|*********** Stuff to do with scene and global processes ************|
@ -537,7 +70,7 @@ static void RestoredProcessProcess(CORO_PARAM, const void *param) {
_ctx->pic = *(const PINT_CONTEXT *)param;
_ctx->pic = RestoreInterpretContext(_ctx->pic);
AttachInterpret(_ctx->pic, g_scheduler->getCurrentProcess());
AttachInterpret(_ctx->pic, CoroScheduler.getCurrentProcess());
CORO_INVOKE_1(Interpret, _ctx->pic);
@ -577,7 +110,7 @@ void RestoreSceneProcess(INT_CONTEXT *pic) {
pStruc = (PROCESS_STRUC *)LockMem(g_hSceneProcess);
for (i = 0; i < g_numSceneProcess; i++) {
if (FROM_LE_32(pStruc[i].hProcessCode) == pic->hCode) {
g_scheduler->createProcess(PID_PROCESS + i, RestoredProcessProcess,
CoroScheduler.createProcess(PID_PROCESS + i, RestoredProcessProcess,
&pic, sizeof(pic));
break;
}
@ -596,7 +129,7 @@ void SceneProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait
CORO_BEGIN_CONTEXT;
PROCESS_STRUC *pStruc;
PPROCESS pProc;
Common::PPROCESS pProc;
PINT_CONTEXT pic;
CORO_END_CONTEXT(_ctx);
@ -617,7 +150,7 @@ void SceneProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait
if (_ctx->pic == NULL)
return;
_ctx->pProc = g_scheduler->createProcess(PID_PROCESS + i, ProcessTinselProcess,
_ctx->pProc = CoroScheduler.createProcess(PID_PROCESS + i, ProcessTinselProcess,
&_ctx->pic, sizeof(_ctx->pic));
AttachInterpret(_ctx->pic, _ctx->pProc);
break;
@ -644,7 +177,7 @@ void KillSceneProcess(uint32 procID) {
pStruc = (PROCESS_STRUC *) LockMem(g_hSceneProcess);
for (i = 0; i < g_numSceneProcess; i++) {
if (FROM_LE_32(pStruc[i].processId) == procID) {
g_scheduler->killMatchingProcess(PID_PROCESS + i, -1);
CoroScheduler.killMatchingProcess(PID_PROCESS + i, -1);
break;
}
}
@ -671,7 +204,7 @@ void RestoreGlobalProcess(INT_CONTEXT *pic) {
for (i = 0; i < g_numGlobalProcess; i++) {
if (g_pGlobalProcess[i].hProcessCode == pic->hCode) {
g_scheduler->createProcess(PID_GPROCESS + i, RestoredProcessProcess,
CoroScheduler.createProcess(PID_GPROCESS + i, RestoredProcessProcess,
&pic, sizeof(pic));
break;
}
@ -686,7 +219,7 @@ void RestoreGlobalProcess(INT_CONTEXT *pic) {
void KillGlobalProcesses() {
for (uint32 i = 0; i < g_numGlobalProcess; ++i) {
g_scheduler->killMatchingProcess(PID_GPROCESS + i, -1);
CoroScheduler.killMatchingProcess(PID_GPROCESS + i, -1);
}
}
@ -696,7 +229,7 @@ void KillGlobalProcesses() {
bool GlobalProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait, int myEscape) {
CORO_BEGIN_CONTEXT;
PINT_CONTEXT pic;
PPROCESS pProc;
Common::PPROCESS pProc;
CORO_END_CONTEXT(_ctx);
bool result = false;
@ -720,7 +253,7 @@ bool GlobalProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWai
if (_ctx->pic != NULL) {
_ctx->pProc = g_scheduler->createProcess(PID_GPROCESS + i, ProcessTinselProcess,
_ctx->pProc = CoroScheduler.createProcess(PID_GPROCESS + i, ProcessTinselProcess,
&_ctx->pic, sizeof(_ctx->pic));
AttachInterpret(_ctx->pic, _ctx->pProc);
}
@ -745,7 +278,7 @@ void xKillGlobalProcess(uint32 procID) {
for (i = 0; i < g_numGlobalProcess; ++i) {
if (g_pGlobalProcess[i].processId == procID) {
g_scheduler->killMatchingProcess(PID_GPROCESS + i, -1);
CoroScheduler.killMatchingProcess(PID_GPROCESS + i, -1);
break;
}
}

View file

@ -24,105 +24,16 @@
#ifndef TINSEL_SCHED_H // prevent multiple includes
#define TINSEL_SCHED_H
#include "common/coroutines.h"
#include "tinsel/dw.h" // new data types
#include "tinsel/coroutine.h"
#include "tinsel/events.h"
#include "tinsel/pcode.h"
#include "tinsel/tinsel.h"
namespace Tinsel {
// the size of process specific info
#define PARAM_SIZE 32
// the maximum number of processes
#define NUM_PROCESS (TinselV2 ? 70 : 64)
#define MAX_PROCESSES 70
typedef void (*CORO_ADDR)(CoroContext &, const void *);
/** process structure */
struct PROCESS {
PROCESS *pNext; ///< pointer to next process in active or free list
PROCESS *pPrevious; ///< pointer to previous process in active or free list
CoroContext state; ///< the state of the coroutine
CORO_ADDR coroAddr; ///< the entry point of the coroutine
int sleepTime; ///< number of scheduler cycles to sleep
int pid; ///< process ID
char param[PARAM_SIZE]; ///< process specific info
};
typedef PROCESS *PPROCESS;
struct INT_CONTEXT;
/**
* Create and manage "processes" (really coroutines).
*/
class Scheduler {
public:
/** Pointer to a function of the form "void function(PPROCESS)" */
typedef void (*VFPTRPP)(PROCESS *);
private:
/** list of all processes */
PROCESS *processList;
/** active process list - also saves scheduler state */
PROCESS *active;
/** pointer to free process list */
PROCESS *pFreeProcesses;
/** the currently active process */
PROCESS *pCurrent;
#ifdef DEBUG
// diagnostic process counters
int numProcs;
int maxProcs;
void CheckStack();
#endif
/**
* Called from killProcess() to enable other resources
* a process may be allocated to be released.
*/
VFPTRPP pRCfunction;
public:
Scheduler();
~Scheduler();
void reset();
#ifdef DEBUG
void printStats();
#endif
void schedule();
void rescheduleAll();
void reschedule(PPROCESS pReSchedProc = NULL);
void giveWay(PPROCESS pReSchedProc = NULL);
PROCESS *createProcess(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam);
void killProcess(PROCESS *pKillProc);
PROCESS *getCurrentProcess();
int getCurrentPID() const;
int killMatchingProcess(int pidKill, int pidMask = -1);
void setResourceCallback(VFPTRPP pFunc);
};
extern Scheduler *g_scheduler; // FIXME: Temporary global var, to be used until everything has been OOifyied
//----------------- FUNCTION PROTOTYPES --------------------
void SceneProcesses(uint32 numProcess, SCNHANDLE hProcess);

View file

@ -24,7 +24,7 @@
#ifndef TINSEL_TEXT_H // prevent multiple includes
#define TINSEL_TEXT_H
#include "tinsel/coroutine.h"
#include "common/coroutines.h"
#include "tinsel/object.h" // object manager defines
namespace Tinsel {

View file

@ -28,11 +28,11 @@
#define BODGE
#include "common/coroutines.h"
#include "tinsel/actors.h"
#include "tinsel/background.h"
#include "tinsel/bmv.h"
#include "tinsel/config.h"
#include "tinsel/coroutine.h"
#include "tinsel/cursor.h"
#include "tinsel/drives.h"
#include "tinsel/dw.h"
@ -1468,7 +1468,7 @@ void NewScene(CORO_PARAM, SCNHANDLE scene, int entrance, int transition) {
++g_sceneCtr;
// Prevent code subsequent to this call running before scene changes
if (g_scheduler->getCurrentPID() != PID_MASTER_SCR)
if (CoroScheduler.getCurrentPID() != PID_MASTER_SCR)
CORO_KILL_SELF();
CORO_END_CODE;
}
@ -2594,7 +2594,7 @@ static void Scroll(CORO_PARAM, EXTREME extreme, int xp, int yp, int xIter, int y
sm.y = _ctx->y;
sm.thisScroll = g_scrollNumber;
sm.myEscape = myEscape;
g_scheduler->createProcess(PID_TCODE, ScrollMonitorProcess, &sm, sizeof(sm));
CoroScheduler.createProcess(PID_TCODE, ScrollMonitorProcess, &sm, sizeof(sm));
}
}
CORO_END_CODE;
@ -2975,12 +2975,12 @@ static void StandTag(int actor, HPOLYGON hp) {
&& hFilm != TF_LEFT && hFilm != TF_RIGHT)
hFilm = 0;
Stand(nullContext, actor, pnodex, pnodey, hFilm);
Stand(Common::nullContext, actor, pnodex, pnodey, hFilm);
} else if (hFilm && (actor == LEAD_ACTOR || actor == GetLeadId()))
Stand(nullContext, actor, pnodex, pnodey, hFilm);
Stand(Common::nullContext, actor, pnodex, pnodey, hFilm);
else
Stand(nullContext, actor, pnodex, pnodey, 0);
Stand(Common::nullContext, actor, pnodex, pnodey, 0);
}

View file

@ -109,8 +109,8 @@ static Scene g_NextScene = { 0, 0, 0 };
static Scene g_HookScene = { 0, 0, 0 };
static Scene g_DelayedScene = { 0, 0, 0 };
static PROCESS *g_pMouseProcess = 0;
static PROCESS *g_pKeyboardProcess = 0;
static Common::PROCESS *g_pMouseProcess = 0;
static Common::PROCESS *g_pKeyboardProcess = 0;
static SCNHANDLE g_hCdChangeScene;
@ -324,7 +324,7 @@ static void MouseProcess(CORO_PARAM, const void *) {
if (TinselV2) {
// Kill off the button process and fire off the action command
g_scheduler->killMatchingProcess(PID_BTN_CLICK, -1);
CoroScheduler.killMatchingProcess(PID_BTN_CLICK, -1);
PlayerEvent(PLR_ACTION, _ctx->clickPos);
} else {
// signal left drag start
@ -368,7 +368,7 @@ static void MouseProcess(CORO_PARAM, const void *) {
// will activate a single button click
if (TinselV2 && ControlIsOn()) {
_ctx->clickPos = mousePos;
g_scheduler->createProcess(PID_BTN_CLICK, SingleLeftProcess, &_ctx->clickPos, sizeof(Common::Point));
CoroScheduler.createProcess(PID_BTN_CLICK, SingleLeftProcess, &_ctx->clickPos, sizeof(Common::Point));
}
} else
_ctx->lastLeftClick -= _vm->_config->_dclickSpeed;
@ -616,11 +616,11 @@ static void RestoredProcess(CORO_PARAM, const void *param) {
}
void RestoreProcess(INT_CONTEXT *pic) {
g_scheduler->createProcess(PID_TCODE, RestoredProcess, &pic, sizeof(pic));
CoroScheduler.createProcess(PID_TCODE, RestoredProcess, &pic, sizeof(pic));
}
void RestoreMasterProcess(INT_CONTEXT *pic) {
g_scheduler->createProcess(PID_MASTER_SCR, RestoredProcess, &pic, sizeof(pic));
CoroScheduler.createProcess(PID_MASTER_SCR, RestoredProcess, &pic, sizeof(pic));
}
// FIXME: CountOut is used by ChangeScene
@ -878,7 +878,6 @@ TinselEngine::~TinselEngine() {
FreeObjectList();
FreeGlobalProcesses();
FreeGlobals();
delete _scheduler;
delete _config;
@ -905,7 +904,7 @@ Common::Error TinselEngine::run() {
_console = new Console();
_scheduler = new Scheduler();
CoroScheduler.reset();
InitSysVars();
@ -1022,7 +1021,7 @@ void TinselEngine::NextGameCycle() {
ResetEcount();
// schedule process
_scheduler->schedule();
CoroScheduler.schedule();
if (_bmv->MoviePlaying())
_bmv->CopyMovieToScreen();
@ -1078,11 +1077,11 @@ bool TinselEngine::pollEvent() {
*/
void TinselEngine::CreateConstProcesses() {
// Process to run the master script
_scheduler->createProcess(PID_MASTER_SCR, MasterScriptProcess, NULL, 0);
CoroScheduler.createProcess(PID_MASTER_SCR, MasterScriptProcess, NULL, 0);
// Processes to run the cursor and inventory,
_scheduler->createProcess(PID_CURSOR, CursorProcess, NULL, 0);
_scheduler->createProcess(PID_INVENTORY, InventoryProcess, NULL, 0);
CoroScheduler.createProcess(PID_CURSOR, CursorProcess, NULL, 0);
CoroScheduler.createProcess(PID_INVENTORY, InventoryProcess, NULL, 0);
}
/**
@ -1132,11 +1131,11 @@ void TinselEngine::RestartDrivers() {
KillAllObjects();
// init the process scheduler
_scheduler->reset();
CoroScheduler.reset();
// init the event handlers
g_pMouseProcess = _scheduler->createProcess(PID_MOUSE, MouseProcess, NULL, 0);
g_pKeyboardProcess = _scheduler->createProcess(PID_KEYBOARD, KeyboardProcess, NULL, 0);
g_pMouseProcess = CoroScheduler.createProcess(PID_MOUSE, MouseProcess, NULL, 0);
g_pKeyboardProcess = CoroScheduler.createProcess(PID_KEYBOARD, KeyboardProcess, NULL, 0);
// open MIDI files
OpenMidiFiles();
@ -1164,8 +1163,8 @@ void TinselEngine::ChopDrivers() {
DeleteMidiBuffer();
// remove event drivers
_scheduler->killProcess(g_pMouseProcess);
_scheduler->killProcess(g_pKeyboardProcess);
CoroScheduler.killProcess(g_pMouseProcess);
CoroScheduler.killProcess(g_pKeyboardProcess);
}
/**

View file

@ -31,7 +31,7 @@ namespace Tinsel {
//----------------- LOCAL GLOBAL DATA --------------------
struct Token {
PROCESS *proc;
Common::PROCESS *proc;
};
static Token g_tokens[NUMTOKENS]; // FIXME: Avoid non-const global vars
@ -40,7 +40,7 @@ static Token g_tokens[NUMTOKENS]; // FIXME: Avoid non-const global vars
/**
* Release all tokens held by this process, and kill the process.
*/
static void TerminateProcess(PROCESS *tProc) {
static void TerminateProcess(Common::PROCESS *tProc) {
// Release tokens held by the process
for (int i = 0; i < NUMTOKENS; i++) {
@ -50,7 +50,7 @@ static void TerminateProcess(PROCESS *tProc) {
}
// Kill the process
g_scheduler->killProcess(tProc);
CoroScheduler.killProcess(tProc);
}
/**
@ -60,7 +60,7 @@ void GetControlToken() {
const int which = TOKEN_CONTROL;
if (g_tokens[which].proc == NULL) {
g_tokens[which].proc = g_scheduler->getCurrentProcess();
g_tokens[which].proc = CoroScheduler.getCurrentProcess();
}
}
@ -85,11 +85,11 @@ void GetToken(int which) {
assert(TOKEN_LEAD <= which && which < NUMTOKENS);
if (g_tokens[which].proc != NULL) {
assert(g_tokens[which].proc != g_scheduler->getCurrentProcess());
assert(g_tokens[which].proc != CoroScheduler.getCurrentProcess());
TerminateProcess(g_tokens[which].proc);
}
g_tokens[which].proc = g_scheduler->getCurrentProcess();
g_tokens[which].proc = CoroScheduler.getCurrentProcess();
}
/**
@ -99,7 +99,7 @@ void GetToken(int which) {
void FreeToken(int which) {
assert(TOKEN_LEAD <= which && which < NUMTOKENS);
assert(g_tokens[which].proc == g_scheduler->getCurrentProcess()); // we'd have been killed if some other proc had taken this token
assert(g_tokens[which].proc == CoroScheduler.getCurrentProcess()); // we'd have been killed if some other proc had taken this token
g_tokens[which].proc = NULL;
}