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  */
22 
23 #include "ultima/ultima8/graphics/palette_fader_process.h"
24 #include "ultima/ultima8/kernel/kernel.h"
25 #include "ultima/ultima8/ultima8.h"
26 
27 namespace Ultima {
28 namespace Ultima8 {
29 
30 PaletteFaderProcess *PaletteFaderProcess::_fader = nullptr;
31 
32 // p_dynamic_class stuff
DEFINE_RUNTIME_CLASSTYPE_CODE(PaletteFaderProcess)33 DEFINE_RUNTIME_CLASSTYPE_CODE(PaletteFaderProcess)
34 
35 PaletteFaderProcess::PaletteFaderProcess() : Process(), _priority(0),
36 	_counter(0), _maxCounter(0) {
37 }
38 
PaletteFaderProcess(PalTransforms trans,int priority,int frames)39 PaletteFaderProcess::PaletteFaderProcess(PalTransforms trans,
40 		int priority, int frames) : _priority(priority),
41 	_counter(frames), _maxCounter(frames) {
42 	PaletteManager  *pm = PaletteManager::get_instance();
43 	Palette *pal = pm->getPalette(PaletteManager::Pal_Game);
44 	for (int i = 0; i < 12; i++) _oldMatrix[i] = pal->_matrix[i];
45 	pm->getTransformMatrix(_newMatrix, trans);
46 	pal->_transform = trans;
47 }
48 
PaletteFaderProcess(uint32 col32,bool from,int priority,int frames,bool current)49 PaletteFaderProcess::PaletteFaderProcess(uint32 col32, bool from,
50 		int priority, int frames, bool current) : _priority(priority),
51 	_counter(frames), _maxCounter(frames) {
52 	PaletteManager *pm = PaletteManager::get_instance();
53 	Palette *pal = pm->getPalette(PaletteManager::Pal_Game);
54 	if (!from) {
55 		if (current)
56 			for (int i = 0; i < 12; i++) _oldMatrix[i] = pal->_matrix[i];
57 		else
58 			pm->getTransformMatrix(_oldMatrix, pal->_transform);
59 		pm->getTransformMatrix(_newMatrix, col32);
60 	} else {
61 		pm->getTransformMatrix(_oldMatrix, col32);
62 		if (current)
63 			for (int i = 0; i < 12; i++) _newMatrix[i] = pal->_matrix[i];
64 		else
65 			pm->getTransformMatrix(_newMatrix, pal->_transform);
66 	}
67 }
68 
PaletteFaderProcess(const int16 from[12],const int16 to[12],int priority,int frames)69 PaletteFaderProcess::PaletteFaderProcess(const int16 from[12], const int16 to[12],
70 		int priority, int frames) : _priority(priority),
71 	_counter(frames), _maxCounter(frames) {
72 	int i;
73 	for (i = 0; i < 12; i++) _oldMatrix[i] = from[i];
74 	for (i = 0; i < 12; i++) _newMatrix[i] = to[i];
75 }
76 
~PaletteFaderProcess(void)77 PaletteFaderProcess::~PaletteFaderProcess(void) {
78 	if (_fader == this)
79 		_fader = nullptr;
80 }
81 
run()82 void PaletteFaderProcess::run() {
83 	int16   matrix[12];
84 
85 	for (int i = 0; i < 12; i++) {
86 		int32 o = _oldMatrix[i] * _counter;
87 		int32 n = _newMatrix[i] * (_maxCounter - _counter);
88 		matrix[i] = static_cast<int16>((o + n) / _maxCounter);
89 	}
90 
91 	PaletteManager::get_instance()->transformPalette(
92 	    PaletteManager::Pal_Game,
93 	    matrix);
94 
95 	if (!_counter--) terminate();
96 }
97 
saveData(Common::WriteStream * ws)98 void PaletteFaderProcess::saveData(Common::WriteStream *ws) {
99 	Process::saveData(ws);
100 
101 	ws->writeUint32LE(static_cast<uint32>(_priority));
102 	ws->writeUint32LE(static_cast<uint32>(_counter));
103 	ws->writeUint32LE(static_cast<uint32>(_maxCounter));
104 	unsigned int i;
105 	for (i = 0; i < 12; ++i)
106 		ws->writeUint16LE(_oldMatrix[i]);
107 	for (i = 0; i < 12; ++i)
108 		ws->writeUint16LE(_newMatrix[i]);
109 }
110 
loadData(Common::ReadStream * rs,uint32 version)111 bool PaletteFaderProcess::loadData(Common::ReadStream *rs, uint32 version) {
112 	if (!Process::loadData(rs, version)) return false;
113 
114 	_priority = static_cast<int>(rs->readUint32LE());
115 	_counter = static_cast<int>(rs->readUint32LE());
116 	_maxCounter = static_cast<int>(rs->readUint32LE());
117 
118 	unsigned int i;
119 	for (i = 0; i < 12; ++i)
120 		_oldMatrix[i] = rs->readUint16LE();
121 	for (i = 0; i < 12; ++i)
122 		_newMatrix[i] = rs->readUint16LE();
123 
124 	_fader = this; //static
125 	return true;
126 }
127 
I_fadeToPaletteTransform(const uint8 * args,unsigned int)128 uint32 PaletteFaderProcess::I_fadeToPaletteTransform(const uint8 *args,
129 		unsigned int /*argsize*/) {
130 	ARG_UINT16(transform);
131 	ARG_UINT16(priority);
132 
133 	// If current _fader has higher _priority, we do nothing
134 	if (_fader && _fader->_priority > priority)
135 		return 0;
136 	else if (_fader && !_fader->is_terminated())
137 		_fader->terminate();
138 
139 	_fader = new PaletteFaderProcess(static_cast<PalTransforms>(transform),
140 	                                priority, 45);
141 
142 	return Kernel::get_instance()->addProcess(_fader);
143 }
144 
I_fadeToBlack(const uint8 * args,unsigned int argsize)145 uint32 PaletteFaderProcess::I_fadeToBlack(const uint8 *args,
146 		unsigned int argsize) {
147 	if (_fader && _fader->_priority > 0x7FFF)
148 		return 0;
149 	else if (_fader && !_fader->is_terminated())
150 		_fader->terminate();
151 
152 	int nsteps = (GAME_IS_U8 ? 30 : 40);
153 	if (argsize > 0) {
154 		ARG_UINT16(n);
155 		nsteps = n;
156 		if (argsize > 2) {
157 			ARG_UINT16(unk);
158 			warning("PaletteFaderProcess::I_fadeToBlackWithParam: Ignoring param %d", unk);
159 		}
160 	}
161 
162 	_fader = new PaletteFaderProcess(0x00000000, false, 0x7FFF, nsteps, true);
163 	return Kernel::get_instance()->addProcess(_fader);
164 }
165 
I_fadeFromBlack(const uint8 * args,unsigned int argsize)166 uint32 PaletteFaderProcess::I_fadeFromBlack(const uint8 *args,
167 		unsigned int argsize) {
168 	if (_fader && _fader->_priority > 0x7FFF)
169 		return 0;
170 	else if (_fader && !_fader->is_terminated())
171 		_fader->terminate();
172 
173 	int nsteps = (GAME_IS_U8 ? 30 : 40);
174 	if (argsize > 0) {
175 		ARG_UINT16(n);
176 		nsteps = n;
177 		if (argsize > 2) {
178 			ARG_UINT16(unk);
179 			warning("PaletteFaderProcess::I_fadeFromBlackWithParam: Ignoring param %d", unk);
180 		}
181 	}
182 
183 	_fader = new PaletteFaderProcess(0x00000000, true, 0x7FFF, nsteps, false);
184 	return Kernel::get_instance()->addProcess(_fader);
185 }
186 
I_fadeToWhite(const uint8 *,unsigned int)187 uint32 PaletteFaderProcess::I_fadeToWhite(const uint8 * /*args*/,
188 		unsigned int /*argsize*/) {
189 	if (_fader && _fader->_priority > 0x7FFF)
190 		return 0;
191 	else if (_fader && !_fader->is_terminated())
192 		_fader->terminate();
193 
194 	_fader = new PaletteFaderProcess(0x00FFFFFF, false, 0x7FFF, 30, true);
195 	return Kernel::get_instance()->addProcess(_fader);
196 }
197 
I_fadeFromWhite(const uint8 *,unsigned int)198 uint32 PaletteFaderProcess::I_fadeFromWhite(const uint8 * /*args*/,
199 		unsigned int /*argsize*/) {
200 	if (_fader && _fader->_priority > 0x7FFF)
201 		return 0;
202 	else if (_fader && !_fader->is_terminated())
203 		_fader->terminate();
204 
205 	_fader = new PaletteFaderProcess(0x00FFFFFF, true, 0x7FFF, 30, false);
206 	return Kernel::get_instance()->addProcess(_fader);
207 }
208 
I_lightningBolt(const uint8 *,unsigned int)209 uint32 PaletteFaderProcess::I_lightningBolt(const uint8 * /*args*/,
210 		unsigned int /*argsize*/) {
211 	if (_fader && _fader->_priority > -1)
212 		return 0;
213 	else if (_fader && !_fader->is_terminated())
214 		_fader->terminate();
215 
216 	_fader = new PaletteFaderProcess(0x3FCFCFCF, true, -1, 10, false);
217 	return Kernel::get_instance()->addProcess(_fader);
218 }
219 
220 static const int16 NoFadeMatrix[] = {0x800, 0, 0, 0,
221 					0, 0x800, 0, 0,
222 					0, 0, 0x800, 0
223 };
224 // Transform used in Crusader is Yib.  We only care about Y:
225 // Y = (r * 0.299 + g * 0.587 + b * 0.114)
226 static const int16 GreyFadeMatrix[] = {612, 1202, 233, 0,
227 					612, 1202, 233, 0,
228 					612, 1202, 233, 0
229 };
230 
231 static const int16 AllWhiteMatrix[] = {0, 0, 0, 0x7ff,
232 					0, 0, 0, 0x7ff,
233 					0, 0, 0, 0x7ff
234 };
235 
236 static const int16 AllBlackMatrix[] = {0, 0, 0, 0,
237 					0, 0, 0, 0,
238 					0, 0, 0, 0
239 };
240 
I_fadeToGreyScale(const uint8 *,unsigned int)241 uint32 PaletteFaderProcess::I_fadeToGreyScale(const uint8 * /*args*/,
242 unsigned int /*argsize*/) {
243 	if (_fader && _fader->_priority > 0x7FFF) return 0;
244 	else if (_fader) _fader->terminate();
245 
246 	_fader = new PaletteFaderProcess(NoFadeMatrix, GreyFadeMatrix, 0x7FFF, 1);
247 	return Kernel::get_instance()->addProcess(_fader);
248 }
249 
I_fadeToGivenColor(const uint8 * args,unsigned int)250 uint32 PaletteFaderProcess::I_fadeToGivenColor(const uint8 *args,
251 		unsigned int /*argsize*/) {
252 	if (_fader && _fader->_priority > 0x7FFF) return 0;
253 	else if (_fader) _fader->terminate();
254 
255 	// TODO: guessing that color order should be same as other one below?
256 	ARG_UINT8(r);
257 	ARG_UINT8(g);
258 	ARG_UINT8(b);
259 	ARG_UINT16(nsteps);
260 	ARG_UINT16(unk);
261 
262 	uint32 target = (r << 16) | (g << 8) | (b << 0);
263 
264 	warning("PaletteFaderProcess::I_fadeToGivenColor: Ignoring param %d", unk);
265 
266 	_fader = new PaletteFaderProcess(target, true, 0x7FFF, nsteps, false);
267 	return Kernel::get_instance()->addProcess(_fader);
268 }
269 
I_fadeToGamePal(const uint8 * args,unsigned int argsize)270 uint32 PaletteFaderProcess::I_fadeToGamePal(const uint8 *args,
271 		unsigned int argsize) {
272 	if (_fader && _fader->_priority > 0x7FFF)
273 		return 0;
274 	else if (_fader && !_fader->is_terminated())
275 		_fader->terminate();
276 
277 	int nsteps = (GAME_IS_U8 ? 30 : 20);
278 	if (argsize > 0) {
279 		ARG_UINT16(n);
280 		nsteps = n;
281 		if (argsize > 2) {
282 			ARG_UINT16(unk);
283 			warning("PaletteFaderProcess::I_fadeToGamePalWithParam: Ignoring param %d", unk);
284 		}
285 	}
286 
287 	int16 curmatrix[12];
288 	PaletteManager *pm = PaletteManager::get_instance();
289 	pm->getTransformMatrix(curmatrix, PaletteManager::Pal_Game);
290 	_fader = new PaletteFaderProcess(curmatrix, NoFadeMatrix, 0x7FFF, nsteps);
291 	return Kernel::get_instance()->addProcess(_fader);
292 }
293 
I_jumpToGreyScale(const uint8 *,unsigned int)294 uint32 PaletteFaderProcess::I_jumpToGreyScale(const uint8 * /*args*/,
295 		unsigned int /*argsize*/) {
296 	if (_fader && _fader->_priority > 0x7FFF) return 0;
297 	else if (_fader) _fader->terminate();
298 
299 	PaletteManager::get_instance()->transformPalette(PaletteManager::Pal_Game,
300 													 GreyFadeMatrix);
301 	return 0;
302 }
303 
I_jumpToAllBlack(const uint8 *,unsigned int)304 uint32 PaletteFaderProcess::I_jumpToAllBlack(const uint8 * /*args*/,
305 		unsigned int /*argsize*/) {
306 	if (_fader && _fader->_priority > 0x7FFF) return 0;
307 	else if (_fader) _fader->terminate();
308 
309 	PaletteManager::get_instance()->transformPalette(PaletteManager::Pal_Game,
310 													 AllBlackMatrix);
311 	return 0;
312 }
313 
I_jumpToAllWhite(const uint8 *,unsigned int)314 uint32 PaletteFaderProcess::I_jumpToAllWhite(const uint8 * /*args*/,
315 		unsigned int /*argsize*/) {
316 	if (_fader && _fader->_priority > 0x7FFF) return 0;
317 	else if (_fader) _fader->terminate();
318 
319 	PaletteManager::get_instance()->transformPalette(PaletteManager::Pal_Game,
320 													 AllWhiteMatrix);
321 	return 0;
322 }
323 
I_jumpToAllGivenColor(const uint8 * args,unsigned int)324 uint32 PaletteFaderProcess::I_jumpToAllGivenColor(const uint8 *args,
325 		unsigned int /*argsize*/) {
326 	if (_fader && _fader->_priority > 0x7FFF) return 0;
327 	else if (_fader) _fader->terminate();
328 
329 	ARG_UINT8(r);
330 	ARG_UINT8(g);
331 	ARG_UINT8(b);
332 
333 	// Transform matrix goes 0~2048, scale 0-63 vals from input
334 	const int16 r16 = static_cast<int16>(r) * 32;
335 	const int16 g16 = static_cast<int16>(g) * 32;
336 	const int16 b16 = static_cast<int16>(b) * 32;
337 
338 	const int16 color_matrix[] = {0, 0, 0, r16,
339 						0, 0, 0, g16,
340 						0, 0, 0, b16
341 	};
342 
343 	PaletteManager::get_instance()->transformPalette(PaletteManager::Pal_Game,
344 													 color_matrix);
345 	return 0;
346 }
347 
I_jumpToNormalPalette(const uint8 *,unsigned int)348 uint32 PaletteFaderProcess::I_jumpToNormalPalette(const uint8 * /*args*/,
349 		unsigned int /*argsize*/) {
350 	if (_fader && _fader->_priority > 0x7FFF) return 0;
351 	else if (_fader) _fader->terminate();
352 
353 	PaletteManager::get_instance()->transformPalette(PaletteManager::Pal_Game,
354 													 NoFadeMatrix);
355 	return 0;
356 }
357 
358 } // End of namespace Ultima8
359 } // End of namespace Ultima
360