Bluddy 185337f6a5 PSP: fixed cursor disappearance bug in 16-bit games
The 5650 16-bit format doesn't include alpha bits and is treated as having alpha by the PSP hardware. Other formats such as 5551 don't have their alpha bit set in the cursor buffer. Instead of adding it, we just turn on the 'reverse alpha' feature for these bits. The problem was not making an exception for 5650.
2011-05-02 15:48:06 +03:00

347 lines
10 KiB
C++

/* 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.
*
* $URL$
* $Id$
*
*/
#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);
}
}