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  * Additional copyright for this file:
8  * Copyright (C) 1994-1998 Revolution Software Ltd.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 
25 // high level layer initializing
26 
27 // the system supports:
28 //	1 optional background parallax layer
29 //	1 not optional normal backdrop layer
30 //	3 normal sorted layers
31 //	up to 2 foreground parallax layers
32 
33 
34 #include "common/rect.h"
35 #include "common/textconsole.h"
36 
37 #include "sword2/sword2.h"
38 #include "sword2/defs.h"
39 #include "sword2/header.h"
40 #include "sword2/logic.h"
41 #include "sword2/mouse.h"
42 #include "sword2/resman.h"
43 #include "sword2/screen.h"
44 #include "sword2/sound.h"
45 
46 namespace Sword2 {
47 
48 /**
49  * This function is called when entering a new room.
50  * @param res resource id of the normal background layer
51  * @param new_palette 1 for new palette, otherwise 0
52  */
53 
initBackground(int32 res,int32 new_palette)54 void Screen::initBackground(int32 res, int32 new_palette) {
55 	int i;
56 
57 	assert(res);
58 
59 	_vm->_sound->clearFxQueue(false);
60 	waitForFade();
61 
62 	debug(1, "CHANGED TO LOCATION \"%s\"", _vm->_resman->fetchName(res));
63 
64 	// We have to clear this. Otherwise, if an exit warps back to the same
65 	// room (e.g. the jungle maze), clicking on the same exit again will be
66 	// misinterpreted as a double-click, and that only works if we're
67 	// actually walking towards that exit. Otherwise, the game would hang.
68 
69 	_vm->_logic->writeVar(EXIT_CLICK_ID, 0);
70 
71 	// if last screen was using a shading mask (see below)
72 	if (_thisScreen.mask_flag) {
73 		if (closeLightMask() != RD_OK)
74 			error("Could not close light mask");
75 	}
76 
77 	// Close the previous screen, if one is open
78 	if (_thisScreen.background_layer_id)
79 		closeBackgroundLayer();
80 
81 	_thisScreen.background_layer_id = res;
82 	_thisScreen.new_palette = new_palette;
83 
84 	// ok, now read the resource and pull out all the normal sort layer
85 	// info/and set them up at the beginning of the sort list - why do it
86 	// each cycle
87 
88 	byte *file = _vm->_resman->openResource(_thisScreen.background_layer_id);
89 	ScreenHeader screen_head;
90 
91 	screen_head.read(_vm->fetchScreenHeader(file));
92 
93 	// set number of special sort layers
94 	_thisScreen.number_of_layers = screen_head.noLayers;
95 	_thisScreen.screen_wide = screen_head.width;
96 	_thisScreen.screen_deep = screen_head.height;
97 
98 	debug(2, "layers=%d width=%d depth=%d", screen_head.noLayers, screen_head.width, screen_head.height);
99 
100 	// initialize the driver back buffer
101 	setLocationMetrics(screen_head.width, screen_head.height);
102 
103 	for (i = 0; i < screen_head.noLayers; i++) {
104 		debug(3, "init layer %d", i);
105 
106 		LayerHeader layer;
107 
108 		layer.read(_vm->fetchLayerHeader(file, i));
109 
110 		// Add the layer to the sort list. We only provide just enough
111 		// information so that it's clear that it's a layer, and where
112 		// to sort it in relation to other things in the list.
113 
114 		_sortList[i].layer_number = i + 1;
115 		_sortList[i].sort_y = layer.y + layer.height;
116 	}
117 
118 	// reset scroll offsets
119 	_thisScreen.scroll_offset_x = 0;
120 	_thisScreen.scroll_offset_y = 0;
121 
122 	if (screen_head.width > _screenWide || screen_head.height > _screenDeep) {
123 		// The layer is larger than the physical screen. Switch on
124 		// scrolling. (2 means first time on screen)
125 		_thisScreen.scroll_flag = 2;
126 
127 		// Note: if we've already set the player up then we could do
128 		// the initial scroll set here
129 
130 		// Calculate the maximum scroll offsets to prevent scrolling
131 		// off the edge. The minimum offsets are both 0.
132 
133 		_thisScreen.max_scroll_offset_x = screen_head.width - _screenWide;
134 		_thisScreen.max_scroll_offset_y = screen_head.height - (_screenDeep - (MENUDEEP * 2));
135 	} else {
136 		// The later fits on the phyiscal screen. Switch off scrolling.
137 		_thisScreen.scroll_flag = 0;
138 	}
139 
140 	resetRenderEngine();
141 
142 	// These are the physical screen coords where the system will try to
143 	// maintain George's actual feet coords.
144 
145 	_thisScreen.feet_x = 320;
146 	_thisScreen.feet_y = 340;
147 
148 	// shading mask
149 
150 	MultiScreenHeader screenLayerTable;
151 
152 	screenLayerTable.read(file + ResHeader::size());
153 
154 	if (screenLayerTable.maskOffset) {
155 		SpriteInfo spriteInfo;
156 
157 		spriteInfo.x = 0;
158 		spriteInfo.y = 0;
159 		spriteInfo.w = screen_head.width;
160 		spriteInfo.h = screen_head.height;
161 		spriteInfo.scale = 0;
162 		spriteInfo.scaledWidth = 0;
163 		spriteInfo.scaledHeight = 0;
164 		spriteInfo.type = 0;
165 		spriteInfo.blend = 0;
166 		spriteInfo.data = _vm->fetchShadingMask(file);
167 		spriteInfo.colorTable = 0;
168 
169 		if (openLightMask(&spriteInfo) != RD_OK)
170 			error("Could not open light mask");
171 
172 		// so we know to close it later! (see above)
173 		_thisScreen.mask_flag = true;
174 	} else {
175 		// no need to close a mask later
176 		_thisScreen.mask_flag = false;
177 	}
178 
179 	// Background parallax layers
180 
181 	for (i = 0; i < 2; i++) {
182 		if (screenLayerTable.bg_parallax[i])
183 			initializeBackgroundLayer(_vm->fetchBackgroundParallaxLayer(file, i));
184 		else
185 			initializeBackgroundLayer(NULL);
186 	}
187 
188 	// Normal backround layer
189 
190 	initializeBackgroundLayer(_vm->fetchBackgroundLayer(file));
191 
192 	// Foreground parallax layers
193 
194 	for (i = 0; i < 2; i++) {
195 		if (screenLayerTable.fg_parallax[i])
196 			initializeBackgroundLayer(_vm->fetchForegroundParallaxLayer(file, i));
197 		else
198 			initializeBackgroundLayer(NULL);
199 	}
200 
201 	_vm->_resman->closeResource(_thisScreen.background_layer_id);
202 }
203 
204 /**
205  * This function is called when entering a new room, PSX edition
206  * @param res resource id of the normal background layer
207  * @param new_palette 1 for new palette, otherwise 0
208  */
209 
initPsxBackground(int32 res,int32 new_palette)210 void Screen::initPsxBackground(int32 res, int32 new_palette) {
211 	int i;
212 
213 	assert(res);
214 
215 	_vm->_sound->clearFxQueue(false);
216 	waitForFade();
217 
218 	debug(1, "CHANGED TO LOCATION \"%s\"", _vm->_resman->fetchName(res));
219 
220 	_vm->_logic->writeVar(EXIT_CLICK_ID, 0);
221 
222 	// Close the previous screen, if one is open
223 	if (_thisScreen.background_layer_id)
224 		closeBackgroundLayer();
225 
226 	_thisScreen.background_layer_id = res;
227 	_thisScreen.new_palette = new_palette;
228 
229 	// ok, now read the resource and pull out all the normal sort layer
230 	// info/and set them up at the beginning of the sort list - why do it
231 	// each cycle
232 
233 	byte *file = _vm->_resman->openResource(_thisScreen.background_layer_id);
234 	ScreenHeader screen_head;
235 
236 	screen_head.read(_vm->fetchScreenHeader(file));
237 	screen_head.height *= 2;
238 
239 	// set number of special sort layers
240 	_thisScreen.number_of_layers = screen_head.noLayers;
241 	_thisScreen.screen_wide = screen_head.width;
242 	_thisScreen.screen_deep = screen_head.height;
243 
244 	debug(2, "layers=%d width=%d depth=%d", screen_head.noLayers, screen_head.width, screen_head.height);
245 
246 	// initialize the driver back buffer
247 	setLocationMetrics(screen_head.width, screen_head.height);
248 
249 	for (i = 0; i < screen_head.noLayers; i++) {
250 		debug(3, "init layer %d", i);
251 
252 		LayerHeader layer;
253 
254 		layer.read(_vm->fetchLayerHeader(file, i));
255 		_sortList[i].layer_number = i + 1;
256 		_sortList[i].sort_y = layer.y + layer.height;
257 	}
258 
259 	// reset scroll offsets
260 	_thisScreen.scroll_offset_x = 0;
261 	_thisScreen.scroll_offset_y = 0;
262 
263 	if (screen_head.width > _screenWide || screen_head.height > _screenDeep) {
264 		_thisScreen.scroll_flag = 2;
265 
266 		_thisScreen.max_scroll_offset_x = screen_head.width - _screenWide;
267 		_thisScreen.max_scroll_offset_y = screen_head.height - (_screenDeep - (MENUDEEP * 2));
268 	} else {
269 		// The later fits on the phyiscal screen. Switch off scrolling.
270 		_thisScreen.scroll_flag = 0;
271 	}
272 
273 	resetRenderEngine();
274 
275 	// These are the physical screen coords where the system will try to
276 	// maintain George's actual feet coords.
277 
278 	_thisScreen.feet_x = 320;
279 	_thisScreen.feet_y = 340;
280 
281 	// Background parallax layers
282 	initializePsxParallaxLayer(_vm->fetchBackgroundParallaxLayer(file, 0));
283 	initializePsxParallaxLayer(NULL);
284 
285 	// Normal backround layer
286 	initializePsxBackgroundLayer(_vm->fetchBackgroundLayer(file));
287 
288 	// Foreground parallax layers
289 	initializePsxParallaxLayer(_vm->fetchForegroundParallaxLayer(file, 1));
290 	initializePsxParallaxLayer(NULL);
291 
292 	_vm->_resman->closeResource(_thisScreen.background_layer_id);
293 
294 }
295 
296 } // End of namespace Sword2
297