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 
26 #include "common/system.h"
27 #include "common/textconsole.h"
28 
29 #include "graphics/palette.h"
30 
31 #include "sword2/sword2.h"
32 #include "sword2/defs.h"
33 #include "sword2/header.h"
34 #include "sword2/logic.h"
35 #include "sword2/resman.h"
36 #include "sword2/screen.h"
37 
38 namespace Sword2 {
39 
40 /**
41  * Start layer palette fading up
42  */
43 
startNewPalette()44 void Screen::startNewPalette() {
45 	// If the screen is still fading down then wait for black - could
46 	// happen when everythings cached into a large memory model
47 	waitForFade();
48 
49 	byte *screenFile = _vm->_resman->openResource(_thisScreen.background_layer_id);
50 
51 	// Don't fetch palette match table while using PSX version,
52 	// because it is not present.
53 	if (!Sword2Engine::isPsx())
54 		memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(screenFile), PALTABLESIZE);
55 
56 	_vm->fetchPalette(screenFile, _palette);
57 	setPalette(0, 256, _palette, RDPAL_FADE);
58 
59 	// Indicating that it's a screen palette
60 	_lastPaletteRes = 0;
61 
62 	_vm->_resman->closeResource(_thisScreen.background_layer_id);
63 	fadeUp();
64 	_thisScreen.new_palette = 0;
65 }
66 
setFullPalette(int32 palRes)67 void Screen::setFullPalette(int32 palRes) {
68 	// fudge for hut interior
69 	// - unpausing should restore last palette as normal (could be screen
70 	// palette or 'dark_palette_13')
71 	// - but restoring the screen palette after 'dark_palette_13' should
72 	// now work properly too!
73 
74 	// "Hut interior" refers to the watchman's hut in Marseille, and this
75 	// is apparently needed for the palette to be restored properly when
76 	// you turn the light off. (I didn't even notice the light switch!)
77 
78 	if (_vm->_logic->readVar(LOCATION) == 13) {
79 		// unpausing
80 		if (palRes == -1) {
81 			// restore whatever palette was last set (screen
82 			// palette or 'dark_palette_13')
83 			palRes = _lastPaletteRes;
84 		}
85 	} else {
86 		// check if we're just restoring the current screen palette
87 		// because we might actually need to use a separate palette
88 		// file anyway eg. for pausing & unpausing during the eclipse
89 
90 		// unpausing (fudged for location 13)
91 		if (palRes == -1) {
92 			// we really meant '0'
93 			palRes = 0;
94 		}
95 
96 		if (palRes == 0 && _lastPaletteRes)
97 			palRes = _lastPaletteRes;
98 	}
99 
100 	// If non-zero, set palette to this separate palette file. Otherwise,
101 	// set palette to current screen palette.
102 
103 	if (palRes) {
104 		byte *pal = _vm->_resman->openResource(palRes);
105 
106 		assert(_vm->_resman->fetchType(pal) == PALETTE_FILE);
107 
108 		pal += ResHeader::size();
109 
110 		// always set color 0 to black because most background screen
111 		// palettes have a bright color 0 although it should come out
112 		// as black in the game!
113 
114 		_palette[0] = 0;
115 		_palette[1] = 0;
116 		_palette[2] = 0;
117 
118 		for (uint i = 4, j = 3; i < 4 * 256; i += 4, j += 3) {
119 			_palette[j + 0] = pal[i + 0];
120 			_palette[j + 1] = pal[i + 1];
121 			_palette[j + 2] = pal[i + 2];
122 		}
123 
124 		setPalette(0, 256, _palette, RDPAL_INSTANT);
125 		_vm->_resman->closeResource(palRes);
126 	} else {
127 		if (_thisScreen.background_layer_id) {
128 			byte *data = _vm->_resman->openResource(_thisScreen.background_layer_id);
129 
130 			// Do not fetch palette match table when using PSX version,
131 			// because it is not present.
132 			if (!Sword2Engine::isPsx())
133 				memcpy(_paletteMatch, _vm->fetchPaletteMatchTable(data), PALTABLESIZE);
134 
135 			_vm->fetchPalette(data, _palette);
136 			setPalette(0, 256, _palette, RDPAL_INSTANT);
137 			_vm->_resman->closeResource(_thisScreen.background_layer_id);
138 		} else
139 			error("setFullPalette(0) called, but no current screen available");
140 	}
141 
142 	if (palRes != CONTROL_PANEL_PALETTE)
143 		_lastPaletteRes = palRes;
144 }
145 
146 /**
147  * Matches a color triplet to a palette index.
148  * @param r red color component
149  * @param g green color component
150  * @param b blue color component
151  * @return the palette index of the closest matching color in the palette
152  */
153 
154 // FIXME: This used to be inlined - probably a good idea - but the
155 // linker complained when I tried to use it in sprite.cpp.
156 
quickMatch(uint8 r,uint8 g,uint8 b)157 uint8 Screen::quickMatch(uint8 r, uint8 g, uint8 b) {
158 	return _paletteMatch[((int32)(r >> 2) << 12) + ((int32)(g >> 2) << 6) + (b >> 2)];
159 }
160 
161 /**
162  * Sets the palette.
163  * @param startEntry the first color entry to set
164  * @param noEntries the number of color entries to set
165  * @param colorTable the new color entries
166  * @param fadeNow whether to perform the change immediately or delayed
167  */
168 
setPalette(int16 startEntry,int16 noEntries,byte * colorTable,uint8 fadeNow)169 void Screen::setPalette(int16 startEntry, int16 noEntries, byte *colorTable, uint8 fadeNow) {
170 	assert(noEntries > 0);
171 
172 	memmove(&_palette[3 * startEntry], colorTable, noEntries * 3);
173 
174 	if (fadeNow == RDPAL_INSTANT) {
175 		setSystemPalette(_palette, startEntry, noEntries);
176 		setNeedFullRedraw();
177 	}
178 }
179 
dimPalette(bool dim)180 void Screen::dimPalette(bool dim) {
181 	if (getFadeStatus() != RDFADE_NONE)
182 		return;
183 
184 	if (dim != _dimPalette) {
185 		_dimPalette = dim;
186 		setSystemPalette(_palette, 0, 256);
187 		setNeedFullRedraw();
188 	}
189 }
190 
191 /**
192  * Fades the palette up from black to the current palette.
193  * @param time the time it will take the palette to fade up
194  */
195 
fadeUp(float time)196 int32 Screen::fadeUp(float time) {
197 	if (getFadeStatus() != RDFADE_BLACK && getFadeStatus() != RDFADE_NONE)
198 		return RDERR_FADEINCOMPLETE;
199 
200 	_fadeTotalTime = (int32)(time * 1000);
201 	_fadeStatus = RDFADE_UP;
202 	_fadeStartTime = getTick();
203 
204 	return RD_OK;
205 }
206 
207 /**
208  * Fades the palette down to black from the current palette.
209  * @param time the time it will take the palette to fade down
210  */
211 
fadeDown(float time)212 int32 Screen::fadeDown(float time) {
213 	if (getFadeStatus() != RDFADE_BLACK && getFadeStatus() != RDFADE_NONE)
214 		return RDERR_FADEINCOMPLETE;
215 
216 	_fadeTotalTime = (int32)(time * 1000);
217 	_fadeStatus = RDFADE_DOWN;
218 	_fadeStartTime = getTick();
219 
220 	return RD_OK;
221 }
222 
223 /**
224  * Get the current fade status
225  * @return RDFADE_UP (fading up), RDFADE_DOWN (fading down), RDFADE_NONE
226  * (not faded), or RDFADE_BLACK (completely faded down)
227  */
228 
getFadeStatus()229 uint8 Screen::getFadeStatus() {
230 	return _fadeStatus;
231 }
232 
waitForFade()233 void Screen::waitForFade() {
234 	while (getFadeStatus() != RDFADE_NONE && getFadeStatus() != RDFADE_BLACK && !_vm->shouldQuit()) {
235 		updateDisplay();
236 		_vm->_system->delayMillis(20);
237 	}
238 }
239 
fadeServer()240 void Screen::fadeServer() {
241 	static int32 previousTime = 0;
242 	byte fadePalette[256 * 3];
243 	byte *newPalette = fadePalette;
244 	int32 currentTime;
245 	int16 fadeMultiplier;
246 	int16 i;
247 
248 	// If we're not in the process of fading, do nothing.
249 	if (getFadeStatus() != RDFADE_UP && getFadeStatus() != RDFADE_DOWN)
250 		return;
251 
252 	// I don't know if this is necessary, but let's limit how often the
253 	// palette is updated, just to be safe.
254 	currentTime = getTick();
255 	if (currentTime - previousTime <= 25)
256 		return;
257 
258 	previousTime = currentTime;
259 
260 	if (getFadeStatus() == RDFADE_UP) {
261 		if (currentTime >= _fadeStartTime + _fadeTotalTime) {
262 			_fadeStatus = RDFADE_NONE;
263 			newPalette = _palette;
264 		} else {
265 			fadeMultiplier = (int16)(((int32)(currentTime - _fadeStartTime) * 256) / _fadeTotalTime);
266 			for (i = 0; i < 256; i++) {
267 				newPalette[i * 3 + 0] = (_palette[i * 3 + 0] * fadeMultiplier) >> 8;
268 				newPalette[i * 3 + 1] = (_palette[i * 3 + 1] * fadeMultiplier) >> 8;
269 				newPalette[i * 3 + 2] = (_palette[i * 3 + 2] * fadeMultiplier) >> 8;
270 			}
271 		}
272 	} else {
273 		if (currentTime >= _fadeStartTime + _fadeTotalTime) {
274 			_fadeStatus = RDFADE_BLACK;
275 			memset(newPalette, 0, sizeof(fadePalette));
276 		} else {
277 			fadeMultiplier = (int16)(((int32)(_fadeTotalTime - (currentTime - _fadeStartTime)) * 256) / _fadeTotalTime);
278 			for (i = 0; i < 256; i++) {
279 				newPalette[i * 3 + 0] = (_palette[i * 3 + 0] * fadeMultiplier) >> 8;
280 				newPalette[i * 3 + 1] = (_palette[i * 3 + 1] * fadeMultiplier) >> 8;
281 				newPalette[i * 3 + 2] = (_palette[i * 3 + 2] * fadeMultiplier) >> 8;
282 			}
283 		}
284 	}
285 
286 	setSystemPalette(newPalette, 0, 256);
287 	setNeedFullRedraw();
288 }
289 
setSystemPalette(const byte * colors,uint start,uint num)290 void Screen::setSystemPalette(const byte *colors, uint start, uint num) {
291 	if (_dimPalette) {
292 		byte pal[256 * 3];
293 
294 		for (uint i = start * 3; i < 3 * (start + num); i++)
295 			pal[i] = colors[i] / 2;
296 
297 		_vm->_system->getPaletteManager()->setPalette(pal, start, num);
298 	} else {
299 		_vm->_system->getPaletteManager()->setPalette(colors, start, num);
300 	}
301 
302 }
303 
304 } // End of namespace Sword2
305