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  * Plays the background film of a scene.
22  */
23 
24 #include "tinsel/anim.h"
25 #include "tinsel/background.h"
26 #include "tinsel/dw.h"
27 #include "tinsel/faders.h"
28 #include "tinsel/film.h"
29 #include "tinsel/font.h"
30 #include "tinsel/handle.h"
31 #include "tinsel/multiobj.h"
32 #include "tinsel/object.h"
33 #include "tinsel/pcode.h"		// CONTROL_STARTOFF
34 #include "tinsel/pid.h"
35 #include "tinsel/sched.h"
36 #include "tinsel/timers.h"		// For ONE_SECOND constant
37 #include "tinsel/tinlib.h"		// For Control()
38 #include "tinsel/tinsel.h"
39 
40 #include "common/textconsole.h"
41 #include "common/util.h"
42 
43 namespace Tinsel {
44 
45 //----------------- LOCAL GLOBAL DATA --------------------
46 
47 #define MAX_BG	10
48 
49 // FIXME: Avoid non-const global vars
50 static SCNHANDLE g_hBgPal = 0;	// Background's palette
51 static POBJECT g_pBG[MAX_BG];
52 static ANIM	g_thisAnim[MAX_BG];	// used by BGmainProcess()
53 static int g_BGspeed = 0;
54 static SCNHANDLE g_hBackground = 0;	// Current scene handle - stored in case of Save_Scene()
55 static bool g_bDoFadeIn = false;
56 static int g_bgReels;
57 
58 /**
59  * GetBgObject
60  */
GetBgObject()61 OBJECT *GetBgObject() {
62 	return g_pBG[0];
63 }
64 
65 /**
66  * BackPal
67  */
BgPal()68 SCNHANDLE BgPal() {
69 	return g_hBgPal;
70 }
71 
72 /**
73  * SetDoFadeIn
74 */
SetDoFadeIn(bool tf)75 void SetDoFadeIn(bool tf) {
76 	g_bDoFadeIn = tf;
77 }
78 
79 /**
80  * Called before scene change.
81  */
DropBackground()82 void DropBackground() {
83 	g_pBG[0] = NULL;	// No background
84 
85 	if (!TinselV2)
86 		g_hBgPal = 0;	// No background palette
87 }
88 
89 /**
90  * Return the width of the current background.
91  */
BgWidth()92 int BgWidth() {
93 	assert(g_pBG[0]);
94 	return MultiRightmost(g_pBG[0]) + 1;
95 }
96 
97 /**
98  * Return the height of the current background.
99  */
BgHeight()100 int BgHeight() {
101 	assert(g_pBG[0]);
102 	return MultiLowest(g_pBG[0]) + 1;
103 }
104 
105 /**
106  * Run main animation that comprises the scene background.
107  */
BGmainProcess(CORO_PARAM,const void * param)108 static void BGmainProcess(CORO_PARAM, const void *param) {
109 	// COROUTINE
110 	CORO_BEGIN_CONTEXT;
111 	CORO_END_CONTEXT(_ctx);
112 
113 	CORO_BEGIN_CODE(_ctx);
114 
115 	const FILM *pFilm;
116 	const FREEL *pReel;
117 	const MULTI_INIT *pmi;
118 
119 	// get the stuff copied to process when it was created
120 	if (g_pBG[0] == NULL) {
121 		/*** At start of scene ***/
122 
123 		if (!TinselV2) {
124 			pReel = (const FREEL *)param;
125 
126 			// Get the MULTI_INIT structure
127 			pmi = (const MULTI_INIT *)LockMem(FROM_32(pReel->mobj));
128 
129 			// Initialize and insert the object, and initialize its script.
130 			g_pBG[0] = MultiInitObject(pmi);
131 			MultiInsertObject(GetPlayfieldList(FIELD_WORLD), g_pBG[0]);
132 			InitStepAnimScript(&g_thisAnim[0], g_pBG[0], FROM_32(pReel->script), g_BGspeed);
133 			g_bgReels = 1;
134 		} else {
135 			/*** At start of scene ***/
136 			pFilm = (const FILM *)LockMem(g_hBackground);
137 			g_bgReels = FROM_32(pFilm->numreels);
138 
139 			int i;
140 			for (i = 0; i < g_bgReels; i++) {
141 				// Get the MULTI_INIT structure
142 				pmi = (PMULTI_INIT) LockMem(FROM_32(pFilm->reels[i].mobj));
143 
144 				// Initialize and insert the object, and initialize its script.
145 				g_pBG[i] = MultiInitObject(pmi);
146 				MultiInsertObject(GetPlayfieldList(FIELD_WORLD), g_pBG[i]);
147 				MultiSetZPosition(g_pBG[i], 0);
148 				InitStepAnimScript(&g_thisAnim[i], g_pBG[i], FROM_32(pFilm->reels[i].script), g_BGspeed);
149 
150 				if (i > 0)
151 					g_pBG[i-1]->pSlave = g_pBG[i];
152 			}
153 		}
154 
155 		if (g_bDoFadeIn) {
156 			FadeInFast();
157 			g_bDoFadeIn = false;
158 		} else if (TinselV2)
159 			PokeInTagColor();
160 
161 		for (;;) {
162 			for (int i = 0; i < g_bgReels; i++) {
163 				if (StepAnimScript(&g_thisAnim[i]) == ScriptFinished)
164 					error("Background animation has finished");
165 			}
166 
167 			CORO_SLEEP(1);
168 		}
169 	} else {
170 		// New background during scene
171 		if (!TinselV2) {
172 			pReel = (const FREEL *)param;
173 			InitStepAnimScript(&g_thisAnim[0], g_pBG[0], FROM_32(pReel->script), g_BGspeed);
174 			StepAnimScript(&g_thisAnim[0]);
175 		} else {
176 			pFilm = (const FILM *)LockMem(g_hBackground);
177 			assert(g_bgReels == (int32)FROM_32(pFilm->numreels));
178 
179 			// Just re-initialize the scripts.
180 			for (int i = 0; i < g_bgReels; i++) {
181 				InitStepAnimScript(&g_thisAnim[i], g_pBG[i], pFilm->reels[i].script, g_BGspeed);
182 				StepAnimScript(&g_thisAnim[i]);
183 			}
184 		}
185 	}
186 
187 	CORO_END_CODE;
188 }
189 
190 /**
191  * Runs secondary reels for a scene background
192  */
BGotherProcess(CORO_PARAM,const void * param)193 static void BGotherProcess(CORO_PARAM, const void *param) {
194 	// COROUTINE
195 	CORO_BEGIN_CONTEXT;
196 		OBJECT *pObj;
197 		ANIM anim;
198 	CORO_END_CONTEXT(_ctx);
199 
200 	const FREEL *pReel = (const FREEL *)param;
201 	const MULTI_INIT *pmi = (const MULTI_INIT *)LockMem(FROM_32(pReel->mobj));
202 
203 	CORO_BEGIN_CODE(_ctx);
204 
205 	// Initialize and insert the object, and initialize its script.
206 	_ctx->pObj = MultiInitObject(pmi);
207 	MultiInsertObject(GetPlayfieldList(FIELD_WORLD), _ctx->pObj);
208 
209 	InitStepAnimScript(&_ctx->anim, g_pBG[0], FROM_32(pReel->script), g_BGspeed);
210 
211 	while (StepAnimScript(&_ctx->anim) != ScriptFinished)
212 		CORO_SLEEP(1);
213 
214 	CORO_END_CODE;
215 }
216 
217 /**
218  * AetBgPal()
219  */
SetBackPal(SCNHANDLE hPal)220 void SetBackPal(SCNHANDLE hPal) {
221 	g_hBgPal = hPal;
222 
223 	FettleFontPal(g_hBgPal);
224 	CreateTranslucentPalette(g_hBgPal);
225 }
226 
ChangePalette(SCNHANDLE hPal)227 void ChangePalette(SCNHANDLE hPal) {
228 	SwapPalette(FindPalette(g_hBgPal), hPal);
229 
230 	SetBackPal(hPal);
231 }
232 
233 /**
234  * Given the scene background film, extracts the palette handle for
235  * everything else's use, then starts a display process for each reel
236  * in the film.
237  * @param hFilm			Scene background film
238  */
StartupBackground(CORO_PARAM,SCNHANDLE hFilm)239 void StartupBackground(CORO_PARAM, SCNHANDLE hFilm) {
240 	CORO_BEGIN_CONTEXT;
241 	CORO_END_CONTEXT(_ctx);
242 
243 	CORO_BEGIN_CODE(_ctx);
244 
245 	const FILM *pfilm;
246 	IMAGE *pim;
247 
248 	g_hBackground = hFilm;		// Save handle in case of Save_Scene()
249 
250 	pim = GetImageFromFilm(hFilm, 0, NULL, NULL, &pfilm);
251 
252 	SetBackPal(FROM_32(pim->hImgPal));
253 
254 	// Extract the film speed
255 	g_BGspeed = ONE_SECOND / FROM_32(pfilm->frate);
256 
257 	// Start display process for each reel in the film
258 	CoroScheduler.createProcess(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL));
259 
260 	if (TinselV0) {
261 		for (uint i = 1; i < FROM_32(pfilm->numreels); ++i)
262 			CoroScheduler.createProcess(PID_REEL, BGotherProcess, &pfilm->reels[i], sizeof(FREEL));
263 	}
264 
265 	if (g_pBG[0] == NULL)
266 		ControlStartOff();
267 
268 	if (TinselV2 && (coroParam != Common::nullContext))
269 		CORO_GIVE_WAY;
270 
271 	CORO_END_CODE;
272 }
273 
274 /**
275  * Return the current scene handle.
276  */
GetBgroundHandle()277 SCNHANDLE GetBgroundHandle() {
278 	return g_hBackground;
279 }
280 
281 } // End of namespace Tinsel
282