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