aboutsummaryrefslogtreecommitdiff
path: root/backends/platform/psp/cursor.cpp
blob: b295507de1c2df45911dc3a13901c08788eb60bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include "common/scummsys.h"
#include "backends/platform/psp/psppixelformat.h"
#include "backends/platform/psp/display_client.h"
#include "backends/platform/psp/default_display_client.h"
#include "backends/platform/psp/cursor.h"

//#define __PSP_DEBUG_FUNCS__	/* For debugging the stack */
//#define __PSP_DEBUG_PRINT__

#include "backends/platform/psp/trace.h"

void Cursor::init() {
	DEBUG_ENTER_FUNC();

	_renderer.setBuffer(&_buffer);			// We do this explicitly
	_renderer.setPalette(&_screenPalette);	// because we want to choose screenpalette by default
	_renderer.setUseGlobalScaler(true);
	setRendererModePalettized(true);		// Assume we start in 8bit mode

	// Default modes
	_palette.setPixelFormats(PSPPixelFormat::Type_5551, PSPPixelFormat::Type_Palette_8bit); // default
	_screenPalette.setPixelFormats(PSPPixelFormat::Type_5551, PSPPixelFormat::Type_Palette_8bit);
	_buffer.setPixelFormat(PSPPixelFormat::Type_5551);
}

void Cursor::deallocate() {
	DEBUG_ENTER_FUNC();

	_buffer.deallocate();
	_palette.deallocate();
	_screenPalette.deallocate();
}

void Cursor::setCursorPalette(const byte *colors, uint start, uint num) {
	DEBUG_ENTER_FUNC();

	if (!_palette.isAllocated()) {
		_palette.allocate();
	}

	// Workaround: This is wrong, but we seem to not be getting setScreenPalette
	if (!_screenPalette.isAllocated()) {
		_screenPalette.allocate();
	}

	_palette.setPartial(colors, start, num);
	setDirty();
}

void Cursor::setScreenPalette(const byte *colors, uint start, uint num) {
	DEBUG_ENTER_FUNC();

	if (!_screenPalette.isAllocated()) {
		_screenPalette.allocate();
	}

	_screenPalette.setPartial(colors, start, num);
	setDirty();
}

void Cursor::setKeyColor(uint32 color) {
	DEBUG_ENTER_FUNC();
	PSP_DEBUG_PRINT("new color[%u], old color[%u]\n", color, _keyColor);

	// If it's a different color, undo the last keycolor
	if (_buffer.hasPalette() && color != _keyColor) {
		if (_screenPalette.isAllocated())
			_screenPalette.setColorPositionAlpha(_keyColor, true);
		if (_palette.isAllocated())
			_palette.setColorPositionAlpha(_keyColor, true);
	}
	// Don't need anything special for 16-bit
	_keyColor = color;
}

void Cursor::clearKeyColor() {
	DEBUG_ENTER_FUNC();
	PSP_DEBUG_PRINT("keyColor[%d]\n", _keyColor);

	// We need 2 mechanisms: one for palettized and one for 16 bit
	if (_buffer.hasPalette()) {
		if (_screenPalette.isAllocated())
			_screenPalette.setColorPositionAlpha(_keyColor, false);		// set keycolor to 0
		if (_palette.isAllocated())
			_palette.setColorPositionAlpha(_keyColor, false);
	} else {	// 16bit
		_renderer.setKeyColor(_keyColor);
	}
	setDirty();
}

void Cursor::enableCursorPalette(bool enable) {
	DEBUG_ENTER_FUNC();
	PSP_DEBUG_PRINT("enable[%s]\n", enable ? "true" : "false");

	_useCursorPalette = enable;
	if (enable)
		_renderer.setPalette(&_palette);	// very important that we do this switch
	else
		_renderer.setPalette(&_screenPalette);

	setDirty();
}

inline void Cursor::setSize(uint32 width, uint32 height) {
	DEBUG_ENTER_FUNC();
	PSP_DEBUG_PRINT("width[%u], height[%u]\n", width, height);

	_buffer.setSize(width, height, Buffer::kSizeByTextureSize);	// we'll use texture size for mouse
	_renderer.setDrawWholeBuffer();		// We need to let the renderer know how much to draw
}

void Cursor::copyFromArray(const byte *array) {
	DEBUG_ENTER_FUNC();

	if (!_buffer.isAllocated())	{
		_buffer.allocate();
	}

	_buffer.copyFromArray(array, _buffer.getSourceWidthInBytes());	// pitch is source width
	setDirty();

	// debug
	//PSP_DEBUG_DO(_buffer.print(0xF));
}

void Cursor::setHotspot(int32 x, int32 y) {
	DEBUG_ENTER_FUNC();

	_hotspotX = x;
	_hotspotY = y;
	updateRendererOffset();	// Important

	PSP_DEBUG_PRINT("hotspotX[%d], hotspotY[%d]\n", x, y);
}

// Returns true if change in x or y
bool Cursor::increaseXY(int32 incX, int32 incY) {
	DEBUG_ENTER_FUNC();

	int32 oldX = _x, oldY = _y;

	// adjust for differences in X and Y
	adjustXYForScreenSize(incX, incY);

	_x += incX;
	_y += incY;

	// Clamp mouse
	if (_x < 0)
		_x = 0;
	if (_y < 0)
		_y = 0;
	if (_x >= (int)_mouseLimitWidth)
		_x = (int)_mouseLimitWidth - 1;
	if (_y >= (int)_mouseLimitHeight)
		_y = (int)_mouseLimitHeight - 1;

	PSP_DEBUG_PRINT("X[%d], Y[%d]\n", _x, _y);

	if (oldX != _x || oldY != _y) {
		updateRendererOffset();
		setDirty();
		return true;
	}

	return false;
}

// Set limits on the movement of the cursor ie. screen size
void Cursor::setLimits(uint32 width, uint32 height) {
#define PSP_SCREEN_WIDTH 480
#define PSP_SCREEN_HEIGHT 272
	DEBUG_ENTER_FUNC();

	PSP_DEBUG_PRINT("width[%u], height[%u]\n", width, height);
	_mouseLimitWidth = width;
	_mouseLimitHeight = height;
}

// Adjust X,Y movement for the screen size to keep it consistent
inline void Cursor::adjustXYForScreenSize(int32 &x, int32 &y) {
	DEBUG_ENTER_FUNC();
	// We have our speed calibrated for the y axis at 480x272. The idea is to adjust this for other
	// resolutions and for x, which is wider.
	int32 newX = x, newY = y;

	// adjust width movement to match height (usually around 1.5)
	if (_mouseLimitWidth >= _mouseLimitHeight + (_mouseLimitHeight >> 1))
		newX = newX + (newX >> 1);

	if (_mouseLimitWidth >= 600) {	// multiply by 2
		newX <<= 1;
		newY <<= 1;
	} else if (_mouseLimitWidth >= 480) {	// multiply by 1.5
		newX = newX + (newX >> 1);
		newY = newY + (newY >> 1);
	}

	// Divide all movements by 8
	newX >>= 3;
	newY >>= 3;

	// Make sure we didn't destroy minimum movement
	if (!((x && !newX) || (y && !newY))) {
		x = newX;
		y = newY;
	}
}

// This is only called when we have a new screen
void Cursor::setScreenPaletteScummvmPixelFormat(const Graphics::PixelFormat *format) {
	DEBUG_ENTER_FUNC();

	uint32 oldPaletteSize = 0;
	if (_screenPalette.isAllocated())
		oldPaletteSize = _screenPalette.getSizeInBytes();

	PSPPixelFormat::Type bufferType = PSPPixelFormat::Type_Unknown;
	PSPPixelFormat::Type paletteType = PSPPixelFormat::Type_Unknown;
	bool swapRedBlue = false;

	// Convert Scummvm Pixel Format to PSPPixelFormat
	PSPPixelFormat::convertFromScummvmPixelFormat(format, bufferType, paletteType, swapRedBlue);

	if (paletteType == PSPPixelFormat::Type_None) {
		//_screenPalette.deallocate();		// leave palette for default CLUT8
		setRendererModePalettized(false);	// use 16-bit mechanism
	} else {	// We have a palette
		_screenPalette.setPixelFormats(paletteType, bufferType);
		_palette.setPixelFormats(paletteType, bufferType);
		setRendererModePalettized(true);	// use palettized mechanism
	}
}

// This is called many many times
void Cursor::setSizeAndScummvmPixelFormat(uint32 width, uint32 height, const Graphics::PixelFormat *format) {
	DEBUG_ENTER_FUNC();

	PSP_DEBUG_PRINT("useCursorPalette[%s]\n", _useCursorPalette ? "true" : "false");

	uint32 oldBufferSize = 0, oldPaletteSize = 0;

	if (_buffer.isAllocated())
		oldBufferSize = _buffer.getSizeInBytes();

	if (_palette.isAllocated())
		oldPaletteSize = _palette.getSizeInBytes();

	setSize(width, height);

	PSPPixelFormat::Type bufferType = PSPPixelFormat::Type_Unknown;
	PSPPixelFormat::Type paletteType = PSPPixelFormat::Type_Unknown;
	bool swapRedBlue = false;

	PSPPixelFormat::convertFromScummvmPixelFormat(format, bufferType, paletteType, swapRedBlue);
	PSP_DEBUG_PRINT("bufferType[%u], paletteType[%u]\n", bufferType, paletteType);

	// Check if we need to set new pixel format
	if (_buffer.getPixelFormat() != bufferType) {
		PSP_DEBUG_PRINT("new buffer pixel format[%u] is different from [%u]. Setting it.\n", bufferType, _buffer.getPixelFormat());
		_buffer.setPixelFormat(bufferType);
	}

	// Check if we need to reallocate
	if (_buffer.getSizeInBytes() != oldBufferSize) {
		_buffer.allocate();
		PSP_DEBUG_PRINT("reallocating buffer. new size: width[%u], height[%u]\n", width, height);
	}

	PSP_DEBUG_PRINT("palette pixel format[%u]\n", paletteType);

	if (paletteType == PSPPixelFormat::Type_None) {
		setRendererModePalettized(false);	// use palettized mechanism
	} else {	// We have a palette
		_palette.setPixelFormats(paletteType, bufferType);
		setRendererModePalettized(true);	// use palettized mechanism
	}

	// debug
	// PSP_DEBUG_DO(_palette.print(10));
	// PSP_DEBUG_DO(_screenPalette.print(10));
}

void Cursor::setXY(int x, int y) {
	DEBUG_ENTER_FUNC();

	_x = x;
	_y = y;
	updateRendererOffset();	// Very important to let renderer know things changed
	setDirty();
}

inline void Cursor::updateRendererOffset() {
	DEBUG_ENTER_FUNC();
	_renderer.setOffsetOnScreen(_x - _hotspotX, _y - _hotspotY);
}

inline void Cursor::setRendererModePalettized(bool palettized) {
	if (palettized) {	// We have a palette. Use blending
		_renderer.setAlphaBlending(true);
		_renderer.setAlphaReverse(false);
		_renderer.setColorTest(false);
	} else {			// 16 bits, no palette
		// Color test is an easy way for the hardware to make our keycolor
		// transparent.
		_renderer.setColorTest(true);

		// Alpha blending is not strictly required, but makes the cursor look
		// much better
		_renderer.setAlphaBlending(true);

		// Pixel formats without alpha (5650) are considered to have their alpha set.
		// Since pixel formats with alpha don't have their alpha bits set, we reverse
		// the alpha format for them so that 0 alpha is 1.
		if (_buffer.getPixelFormat() != PSPPixelFormat::Type_5650)
			_renderer.setAlphaReverse(true);
		else
			_renderer.setAlphaReverse(false);
	}
}