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