1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 * Process scheduler.
22 */
23
24 #include "tinsel/handle.h"
25 #include "tinsel/pcode.h"
26 #include "tinsel/pid.h"
27 #include "tinsel/polygons.h"
28 #include "tinsel/sched.h"
29
30 #include "common/textconsole.h"
31 #include "common/util.h"
32
33 namespace Tinsel {
34
35 #include "common/pack-start.h" // START STRUCT PACKING
36
37 struct PROCESS_STRUC {
38 uint32 processId; // ID of process
39 SCNHANDLE hProcessCode; // handle to actor script
40 } PACKED_STRUCT;
41
42 #include "common/pack-end.h" // END STRUCT PACKING
43
44 //----------------- LOCAL GLOBAL DATA --------------------
45
46 // FIXME: Avoid non-const global vars
47
48 static uint32 g_numSceneProcess;
49 static SCNHANDLE g_hSceneProcess;
50
51 static uint32 g_numGlobalProcess;
52 static PROCESS_STRUC *g_pGlobalProcess;
53
54
55 /**************************************************************************\
56 |*********** Stuff to do with scene and global processes ************|
57 \**************************************************************************/
58
59 /**
60 * The code for for restored scene processes.
61 */
RestoredProcessProcess(CORO_PARAM,const void * param)62 static void RestoredProcessProcess(CORO_PARAM, const void *param) {
63 CORO_BEGIN_CONTEXT;
64 INT_CONTEXT *pic;
65 CORO_END_CONTEXT(_ctx);
66
67 CORO_BEGIN_CODE(_ctx);
68
69 // get the stuff copied to process when it was created
70 _ctx->pic = *(const PINT_CONTEXT *)param;
71
72 _ctx->pic = RestoreInterpretContext(_ctx->pic);
73 AttachInterpret(_ctx->pic, CoroScheduler.getCurrentProcess());
74
75 CORO_INVOKE_1(Interpret, _ctx->pic);
76
77 CORO_END_CODE;
78 }
79
80 /**
81 * Process Tinsel Process
82 */
ProcessTinselProcess(CORO_PARAM,const void * param)83 static void ProcessTinselProcess(CORO_PARAM, const void *param) {
84 const PINT_CONTEXT *pPic = (const PINT_CONTEXT *)param;
85
86 CORO_BEGIN_CONTEXT;
87 CORO_END_CONTEXT(_ctx);
88
89 CORO_BEGIN_CODE(_ctx);
90
91 // get the stuff copied to process when it was created
92 CORO_INVOKE_1(Interpret, *pPic);
93
94 CORO_KILL_SELF();
95 CORO_END_CODE;
96 }
97
98
99 /**************************************************************************\
100 |***************** Stuff to do with scene processes *****************|
101 \**************************************************************************/
102
103 /**
104 * Called to restore a scene process.
105 */
RestoreSceneProcess(INT_CONTEXT * pic)106 void RestoreSceneProcess(INT_CONTEXT *pic) {
107 uint32 i;
108 PROCESS_STRUC *pStruc;
109
110 pStruc = (PROCESS_STRUC *)LockMem(g_hSceneProcess);
111 for (i = 0; i < g_numSceneProcess; i++) {
112 if (FROM_32(pStruc[i].hProcessCode) == pic->hCode) {
113 CoroScheduler.createProcess(PID_PROCESS + i, RestoredProcessProcess,
114 &pic, sizeof(pic));
115 break;
116 }
117 }
118
119 assert(i < g_numSceneProcess);
120 }
121
122 /**
123 * Run a scene process with the given event.
124 */
SceneProcessEvent(CORO_PARAM,uint32 procID,TINSEL_EVENT event,bool bWait,int myEscape,bool * result)125 void SceneProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait, int myEscape,
126 bool *result) {
127 uint32 i; // Loop counter
128 if (result) *result = false;
129
130 CORO_BEGIN_CONTEXT;
131 PROCESS_STRUC *pStruc;
132 Common::PPROCESS pProc;
133 PINT_CONTEXT pic;
134 CORO_END_CONTEXT(_ctx);
135
136 CORO_BEGIN_CODE(_ctx);
137
138 _ctx->pStruc = (PROCESS_STRUC *)LockMem(g_hSceneProcess);
139 for (i = 0; i < g_numSceneProcess; i++) {
140 if (FROM_32(_ctx->pStruc[i].processId) == procID) {
141 assert(_ctx->pStruc[i].hProcessCode); // Must have some code to run
142
143 _ctx->pic = InitInterpretContext(GS_PROCESS,
144 FROM_32(_ctx->pStruc[i].hProcessCode),
145 event,
146 NOPOLY, // No polygon
147 0, // No actor
148 NULL, // No object
149 myEscape);
150 if (_ctx->pic == NULL)
151 return;
152
153 _ctx->pProc = CoroScheduler.createProcess(PID_PROCESS + i, ProcessTinselProcess,
154 &_ctx->pic, sizeof(_ctx->pic));
155 AttachInterpret(_ctx->pic, _ctx->pProc);
156 break;
157 }
158 }
159
160 if (i == g_numSceneProcess)
161 return;
162
163 if (bWait) {
164 CORO_INVOKE_2(WaitInterpret, _ctx->pProc, result);
165 }
166
167 CORO_END_CODE;
168 }
169
170 /**
171 * Kill all instances of a scene process.
172 */
KillSceneProcess(uint32 procID)173 void KillSceneProcess(uint32 procID) {
174 uint32 i; // Loop counter
175 PROCESS_STRUC *pStruc;
176
177 pStruc = (PROCESS_STRUC *) LockMem(g_hSceneProcess);
178 for (i = 0; i < g_numSceneProcess; i++) {
179 if (FROM_32(pStruc[i].processId) == procID) {
180 CoroScheduler.killMatchingProcess(PID_PROCESS + i, -1);
181 break;
182 }
183 }
184 }
185
186 /**
187 * Register the scene processes in a scene.
188 */
SceneProcesses(uint32 numProcess,SCNHANDLE hProcess)189 void SceneProcesses(uint32 numProcess, SCNHANDLE hProcess) {
190 g_numSceneProcess = numProcess;
191 g_hSceneProcess = hProcess;
192 }
193
194
195 /**************************************************************************\
196 |***************** Stuff to do with global processes ****************|
197 \**************************************************************************/
198
199 /**
200 * Called to restore a global process.
201 */
RestoreGlobalProcess(INT_CONTEXT * pic)202 void RestoreGlobalProcess(INT_CONTEXT *pic) {
203 uint32 i; // Loop counter
204
205 for (i = 0; i < g_numGlobalProcess; i++) {
206 if (g_pGlobalProcess[i].hProcessCode == pic->hCode) {
207 CoroScheduler.createProcess(PID_GPROCESS + i, RestoredProcessProcess,
208 &pic, sizeof(pic));
209 break;
210 }
211 }
212
213 assert(i < g_numGlobalProcess);
214 }
215
216 /**
217 * Kill them all (restore game).
218 */
KillGlobalProcesses()219 void KillGlobalProcesses() {
220
221 for (uint32 i = 0; i < g_numGlobalProcess; ++i) {
222 CoroScheduler.killMatchingProcess(PID_GPROCESS + i, -1);
223 }
224 }
225
226 /**
227 * Run a global process with the given event.
228 */
GlobalProcessEvent(CORO_PARAM,uint32 procID,TINSEL_EVENT event,bool bWait,int myEscape)229 bool GlobalProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait, int myEscape) {
230 CORO_BEGIN_CONTEXT;
231 PINT_CONTEXT pic;
232 Common::PPROCESS pProc;
233 CORO_END_CONTEXT(_ctx);
234
235 bool result = false;
236
237 CORO_BEGIN_CODE(_ctx);
238
239 uint32 i; // Loop counter
240 _ctx->pProc = NULL;
241
242 for (i = 0; i < g_numGlobalProcess; ++i) {
243 if (g_pGlobalProcess[i].processId == procID) {
244 assert(g_pGlobalProcess[i].hProcessCode); // Must have some code to run
245
246 _ctx->pic = InitInterpretContext(GS_GPROCESS,
247 g_pGlobalProcess[i].hProcessCode,
248 event,
249 NOPOLY, // No polygon
250 0, // No actor
251 NULL, // No object
252 myEscape);
253
254 if (_ctx->pic != NULL) {
255
256 _ctx->pProc = CoroScheduler.createProcess(PID_GPROCESS + i, ProcessTinselProcess,
257 &_ctx->pic, sizeof(_ctx->pic));
258 AttachInterpret(_ctx->pic, _ctx->pProc);
259 }
260 break;
261 }
262 }
263
264 if ((i == g_numGlobalProcess) || (_ctx->pic == NULL))
265 result = false;
266 else if (bWait)
267 CORO_INVOKE_ARGS_V(WaitInterpret, false, (CORO_SUBCTX, _ctx->pProc, &result));
268
269 CORO_END_CODE;
270 return result;
271 }
272
273 /**
274 * Kill all instances of a global process.
275 */
xKillGlobalProcess(uint32 procID)276 void xKillGlobalProcess(uint32 procID) {
277 uint32 i; // Loop counter
278
279 for (i = 0; i < g_numGlobalProcess; ++i) {
280 if (g_pGlobalProcess[i].processId == procID) {
281 CoroScheduler.killMatchingProcess(PID_GPROCESS + i, -1);
282 break;
283 }
284 }
285 }
286
287 /**
288 * Register the global processes list
289 */
GlobalProcesses(uint32 numProcess,byte * pProcess)290 void GlobalProcesses(uint32 numProcess, byte *pProcess) {
291 g_pGlobalProcess = new PROCESS_STRUC[numProcess];
292 g_numGlobalProcess = numProcess;
293 byte *p = pProcess;
294
295 for (uint i = 0; i < numProcess; ++i, p += 8) {
296 g_pGlobalProcess[i].processId = READ_32(p);
297 g_pGlobalProcess[i].hProcessCode = READ_32(p + 4);
298 }
299 }
300
301 /**
302 * Frees the global processes list
303 */
FreeGlobalProcesses()304 void FreeGlobalProcesses() {
305 delete[] g_pGlobalProcess;
306 g_pGlobalProcess = 0;
307 g_numGlobalProcess = 0;
308 }
309
310 } // End of namespace Tinsel
311