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 "common/scummsys.h"
24 #include "backends/platform/psp/psppixelformat.h"
25 #include "backends/platform/psp/display_client.h"
26 #include "backends/platform/psp/default_display_client.h"
27 #include "backends/platform/psp/cursor.h"
28 
29 //#define __PSP_DEBUG_FUNCS__	/* For debugging the stack */
30 //#define __PSP_DEBUG_PRINT__
31 
32 #include "backends/platform/psp/trace.h"
33 
init()34 void Cursor::init() {
35 	DEBUG_ENTER_FUNC();
36 
37 	_renderer.setBuffer(&_buffer);			// We do this explicitly
38 	_renderer.setPalette(&_screenPalette);	// because we want to choose screenpalette by default
39 	_renderer.setUseGlobalScaler(true);
40 	setRendererModePalettized(true);		// Assume we start in 8bit mode
41 
42 	// Default modes
43 	_palette.setPixelFormats(PSPPixelFormat::Type_5551, PSPPixelFormat::Type_Palette_8bit); // default
44 	_screenPalette.setPixelFormats(PSPPixelFormat::Type_5551, PSPPixelFormat::Type_Palette_8bit);
45 	_buffer.setPixelFormat(PSPPixelFormat::Type_5551);
46 }
47 
deallocate()48 void Cursor::deallocate() {
49 	DEBUG_ENTER_FUNC();
50 
51 	_buffer.deallocate();
52 	_palette.deallocate();
53 	_screenPalette.deallocate();
54 }
55 
setCursorPalette(const byte * colors,uint start,uint num)56 void Cursor::setCursorPalette(const byte *colors, uint start, uint num) {
57 	DEBUG_ENTER_FUNC();
58 
59 	if (!_palette.isAllocated()) {
60 		_palette.allocate();
61 	}
62 
63 	// Workaround: This is wrong, but we seem to not be getting setScreenPalette
64 	if (!_screenPalette.isAllocated()) {
65 		_screenPalette.allocate();
66 	}
67 
68 	_palette.setPartial(colors, start, num);
69 	setDirty();
70 }
71 
setScreenPalette(const byte * colors,uint start,uint num)72 void Cursor::setScreenPalette(const byte *colors, uint start, uint num) {
73 	DEBUG_ENTER_FUNC();
74 
75 	if (!_screenPalette.isAllocated()) {
76 		_screenPalette.allocate();
77 	}
78 
79 	_screenPalette.setPartial(colors, start, num);
80 	setDirty();
81 }
82 
setKeyColor(uint32 color)83 void Cursor::setKeyColor(uint32 color) {
84 	DEBUG_ENTER_FUNC();
85 	PSP_DEBUG_PRINT("new color[%u], old color[%u]\n", color, _keyColor);
86 
87 	// If it's a different color, undo the last keycolor
88 	if (_buffer.hasPalette() && color != _keyColor) {
89 		if (_screenPalette.isAllocated())
90 			_screenPalette.setColorPositionAlpha(_keyColor, true);
91 		if (_palette.isAllocated())
92 			_palette.setColorPositionAlpha(_keyColor, true);
93 	}
94 	// Don't need anything special for 16-bit
95 	_keyColor = color;
96 }
97 
clearKeyColor()98 void Cursor::clearKeyColor() {
99 	DEBUG_ENTER_FUNC();
100 	PSP_DEBUG_PRINT("keyColor[%d]\n", _keyColor);
101 
102 	// We need 2 mechanisms: one for palettized and one for 16 bit
103 	if (_buffer.hasPalette()) {
104 		if (_screenPalette.isAllocated())
105 			_screenPalette.setColorPositionAlpha(_keyColor, false);		// set keycolor to 0
106 		if (_palette.isAllocated())
107 			_palette.setColorPositionAlpha(_keyColor, false);
108 	} else {	// 16bit
109 		_renderer.setKeyColor(_keyColor);
110 	}
111 	setDirty();
112 }
113 
enableCursorPalette(bool enable)114 void Cursor::enableCursorPalette(bool enable) {
115 	DEBUG_ENTER_FUNC();
116 	PSP_DEBUG_PRINT("enable[%s]\n", enable ? "true" : "false");
117 
118 	_useCursorPalette = enable;
119 	if (enable)
120 		_renderer.setPalette(&_palette);	// very important that we do this switch
121 	else
122 		_renderer.setPalette(&_screenPalette);
123 
124 	setDirty();
125 }
126 
setSize(uint32 width,uint32 height)127 inline void Cursor::setSize(uint32 width, uint32 height) {
128 	DEBUG_ENTER_FUNC();
129 	PSP_DEBUG_PRINT("width[%u], height[%u]\n", width, height);
130 
131 	_buffer.setSize(width, height, Buffer::kSizeByTextureSize);	// we'll use texture size for mouse
132 	_renderer.setDrawWholeBuffer();		// We need to let the renderer know how much to draw
133 }
134 
copyFromArray(const byte * array)135 void Cursor::copyFromArray(const byte *array) {
136 	DEBUG_ENTER_FUNC();
137 
138 	if (!_buffer.isAllocated())	{
139 		_buffer.allocate();
140 	}
141 
142 	_buffer.copyFromArray(array, _buffer.getSourceWidthInBytes());	// pitch is source width
143 	setDirty();
144 
145 	// debug
146 	//PSP_DEBUG_DO(_buffer.print(0xF));
147 }
148 
setHotspot(int32 x,int32 y)149 void Cursor::setHotspot(int32 x, int32 y) {
150 	DEBUG_ENTER_FUNC();
151 
152 	_hotspotX = x;
153 	_hotspotY = y;
154 	updateRendererOffset();	// Important
155 
156 	PSP_DEBUG_PRINT("hotspotX[%d], hotspotY[%d]\n", x, y);
157 }
158 
159 // Returns true if change in x or y
increaseXY(int32 incX,int32 incY)160 bool Cursor::increaseXY(int32 incX, int32 incY) {
161 	DEBUG_ENTER_FUNC();
162 
163 	int32 oldX = _x, oldY = _y;
164 
165 	// adjust for screen resolution
166 	adjustXYForScreenSize(incX, incY);
167 
168 	_x += incX;
169 	_y += incY;
170 
171 	// Clamp mouse
172 	if (_x < 0)
173 		_x = 0;
174 	if (_y < 0)
175 		_y = 0;
176 	if (_x >= (int)_mouseLimitWidth)
177 		_x = (int)_mouseLimitWidth - 1;
178 	if (_y >= (int)_mouseLimitHeight)
179 		_y = (int)_mouseLimitHeight - 1;
180 
181 	PSP_DEBUG_PRINT("X[%d], Y[%d]\n", _x, _y);
182 
183 	if (oldX != _x || oldY != _y) {
184 		updateRendererOffset();
185 		setDirty();
186 		return true;
187 	}
188 
189 	return false;
190 }
191 
192 // Set limits on the movement of the cursor ie. screen size
setLimits(uint32 width,uint32 height)193 void Cursor::setLimits(uint32 width, uint32 height) {
194 #define PSP_SCREEN_WIDTH 480
195 #define PSP_SCREEN_HEIGHT 272
196 	DEBUG_ENTER_FUNC();
197 
198 	PSP_DEBUG_PRINT("width[%u], height[%u]\n", width, height);
199 	_mouseLimitWidth = width;
200 	_mouseLimitHeight = height;
201 }
202 
203 // Adjust X,Y movement for the screen size to keep it consistent
adjustXYForScreenSize(int32 & x,int32 & y)204 inline void Cursor::adjustXYForScreenSize(int32 &x, int32 &y) {
205 	DEBUG_ENTER_FUNC();
206 	// We have our speed calibrated for the y axis at 480x272. The idea is to adjust this for other
207 	// resolutions
208 	int32 newX = x, newY = y;
209 
210 	if (_mouseLimitWidth >= 600) {	// multiply by 2
211 		newX *= 2;
212 		newY *= 2;
213 	} else if (_mouseLimitWidth >= 480) {	// multiply by 1.5
214 		newX = newX + (newX / 2);
215 		newY = newY + (newY / 2);
216 	}
217 }
218 
219 // This is only called when we have a new screen
setScreenPaletteScummvmPixelFormat(const Graphics::PixelFormat * format)220 void Cursor::setScreenPaletteScummvmPixelFormat(const Graphics::PixelFormat *format) {
221 	DEBUG_ENTER_FUNC();
222 
223 	PSPPixelFormat::Type bufferType = PSPPixelFormat::Type_Unknown;
224 	PSPPixelFormat::Type paletteType = PSPPixelFormat::Type_Unknown;
225 	bool swapRedBlue = false;
226 
227 	// Convert Scummvm Pixel Format to PSPPixelFormat
228 	PSPPixelFormat::convertFromScummvmPixelFormat(format, bufferType, paletteType, swapRedBlue);
229 
230 	if (paletteType == PSPPixelFormat::Type_None) {
231 		//_screenPalette.deallocate();		// leave palette for default CLUT8
232 		setRendererModePalettized(false);	// use 16-bit mechanism
233 	} else {	// We have a palette
234 		_screenPalette.setPixelFormats(paletteType, bufferType);
235 		_palette.setPixelFormats(paletteType, bufferType);
236 		setRendererModePalettized(true);	// use palettized mechanism
237 	}
238 }
239 
240 // This is called many many times
setSizeAndScummvmPixelFormat(uint32 width,uint32 height,const Graphics::PixelFormat * format)241 void Cursor::setSizeAndScummvmPixelFormat(uint32 width, uint32 height, const Graphics::PixelFormat *format) {
242 	DEBUG_ENTER_FUNC();
243 
244 	PSP_DEBUG_PRINT("useCursorPalette[%s]\n", _useCursorPalette ? "true" : "false");
245 
246 	uint32 oldBufferSize = 0;
247 
248 	if (_buffer.isAllocated())
249 		oldBufferSize = _buffer.getSizeInBytes();
250 
251 	setSize(width, height);
252 
253 	PSPPixelFormat::Type bufferType = PSPPixelFormat::Type_Unknown;
254 	PSPPixelFormat::Type paletteType = PSPPixelFormat::Type_Unknown;
255 	bool swapRedBlue = false;
256 
257 	PSPPixelFormat::convertFromScummvmPixelFormat(format, bufferType, paletteType, swapRedBlue);
258 	PSP_DEBUG_PRINT("bufferType[%u], paletteType[%u]\n", bufferType, paletteType);
259 
260 	// Check if we need to set new pixel format
261 	if (_buffer.getPixelFormat() != bufferType) {
262 		PSP_DEBUG_PRINT("new buffer pixel format[%u] is different from [%u]. Setting it.\n", bufferType, _buffer.getPixelFormat());
263 		_buffer.setPixelFormat(bufferType);
264 	}
265 
266 	// Check if we need to reallocate
267 	if (_buffer.getSizeInBytes() != oldBufferSize) {
268 		_buffer.allocate();
269 		PSP_DEBUG_PRINT("reallocating buffer. new size: width[%u], height[%u]\n", width, height);
270 	}
271 
272 	PSP_DEBUG_PRINT("palette pixel format[%u]\n", paletteType);
273 
274 	if (paletteType == PSPPixelFormat::Type_None) {
275 		setRendererModePalettized(false);	// use palettized mechanism
276 	} else {	// We have a palette
277 		_palette.setPixelFormats(paletteType, bufferType);
278 		setRendererModePalettized(true);	// use palettized mechanism
279 	}
280 
281 	// debug
282 	// PSP_DEBUG_DO(_palette.print(10));
283 	// PSP_DEBUG_DO(_screenPalette.print(10));
284 }
285 
setXY(int x,int y)286 void Cursor::setXY(int x, int y) {
287 	DEBUG_ENTER_FUNC();
288 
289 	_x = x;
290 	_y = y;
291 	updateRendererOffset();	// Very important to let renderer know things changed
292 	setDirty();
293 }
294 
updateRendererOffset()295 inline void Cursor::updateRendererOffset() {
296 	DEBUG_ENTER_FUNC();
297 	_renderer.setOffsetOnScreen(_x - _hotspotX, _y - _hotspotY);
298 }
299 
setRendererModePalettized(bool palettized)300 inline void Cursor::setRendererModePalettized(bool palettized) {
301 	if (palettized) {	// We have a palette. Use blending
302 		_renderer.setAlphaBlending(true);
303 		_renderer.setAlphaReverse(false);
304 		_renderer.setColorTest(false);
305 	} else {			// 16 bits, no palette
306 		// Color test is an easy way for the hardware to make our keycolor
307 		// transparent.
308 		_renderer.setColorTest(true);
309 
310 		// Alpha blending is not strictly required, but makes the cursor look
311 		// much better
312 		_renderer.setAlphaBlending(true);
313 
314 		// Pixel formats without alpha (5650) are considered to have their alpha set.
315 		// Since pixel formats with alpha don't have their alpha bits set, we reverse
316 		// the alpha format for them so that 0 alpha is 1.
317 		if (_buffer.getPixelFormat() != PSPPixelFormat::Type_5650)
318 			_renderer.setAlphaReverse(true);
319 		else
320 			_renderer.setAlphaReverse(false);
321 	}
322 }
323