diff options
Diffstat (limited to 'backends/platform/psp/pspkeyboard.cpp')
-rw-r--r-- | backends/platform/psp/pspkeyboard.cpp | 945 |
1 files changed, 423 insertions, 522 deletions
diff --git a/backends/platform/psp/pspkeyboard.cpp b/backends/platform/psp/pspkeyboard.cpp index be8b98a3f8..d6fa0621b9 100644 --- a/backends/platform/psp/pspkeyboard.cpp +++ b/backends/platform/psp/pspkeyboard.cpp @@ -24,16 +24,19 @@ */ //#define PSP_KB_SHELL /* Need a hack to properly load the keyboard from the PSP shell */ + #ifdef PSP_KB_SHELL -#define PSP_KB_SHELL_PATH "ms0:/psp/game4xx/scummvm-1.0.0rc1/" /* path to kbd.zip */ + #define PSP_KB_SHELL_PATH "ms0:/psp/game4xx/scummvm-solid/" /* path to kbd.zip */ #endif -//#define PSP_KB_DEBUG +//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */ +//#define __PSP_DEBUG_PRINT__ + +#include "backends/platform/psp/trace.h" #include <malloc.h> #include "pspkernel.h" -#include <pspgu.h> #include "png.h" -#include "pspkeyboard.h" +#include "backends/platform/psp/pspkeyboard.h" #include "common/keyboard.h" #include "common/fs.h" #include "common/unzip.h" @@ -94,314 +97,145 @@ void pngReadStreamRead(png_structp png_ptr, png_bytep data, png_size_t length) { file->read(data, length); } +// Array with file names +const char *PSPKeyboard::_guiStrings[] = { + "keys4.png", "keys_s4.png", + "keys_c4.png", "keys_s_c4.png", + "nums4.png", "nums_s4.png", + "syms4.png", "syms_s4.png" +}; + // Constructor PSPKeyboard::PSPKeyboard() { + DEBUG_ENTER_FUNC(); + _init = false; // we're not initialized yet _prevButtons = 0; // Reset previous buttons - _dirty = true; // keyboard needs redrawing - _mode = 0; // charset selected. (0 - letters, 1 - uppercase 2 - numbers 3 - symbols) + _dirty = false; // keyboard needs redrawing + _mode = 0; // charset selected. (0: letters, 1: uppercase 2: numbers 3: symbols) _oldCursor = kCenter; // Center cursor by default - _moved_x = 20; // Default starting location - _moved_y = 50; + _movedX = 20; // Default starting location + _movedY = 50; _moved = false; // Keyboard wasn't moved recently _state = kInvisible; // We start invisible _lastState = kInvisible; + + // Constant renderer settings + _renderer.setAlphaBlending(true); + _renderer.setColorTest(false); + _renderer.setUseGlobalScaler(false); + + DEBUG_EXIT_FUNC(); } // Destructor PSPKeyboard::~PSPKeyboard() { - if (!_init) return; - - int a; - for (a = 0; a < guiStringsSize; a++) { - free(_keyTextures[a].texture); - free(_keyTextures[a].palette); - _keyTextures[a].texture = NULL; - _keyTextures[a].palette = NULL; + DEBUG_ENTER_FUNC(); + + if (!_init) { + DEBUG_EXIT_FUNC(); + return; + } + + for (int i = 0; i < guiStringsSize; i++) { + _buffers[i].deallocate(); + _palettes[i].deallocate(); } _init = false; + + DEBUG_EXIT_FUNC(); } -// Array with file names -const char *PSPKeyboard::_guiStrings[] = { - "keys4.png", "keys_s4.png", - "keys_c4.png", "keys_s_c4.png", - "nums4.png", "nums_s4.png", - "syms4.png", "syms_s4.png" -}; - -// Defines for working with PSP buttons -#define CHANGED(x) (buttonsChanged & (x)) -#define PRESSED(x) ((buttonsChanged & (x)) && (pad.Buttons & (x))) -#define UNPRESSED(x) ((buttonsChanged & (x)) && !(pad.Buttons & (x))) -#define DOWN(x) (pad.Buttons & (x)) -#define UP(x) (!(pad.Buttons & (x))) -#define PSP_DPAD (PSP_CTRL_DOWN|PSP_CTRL_UP|PSP_CTRL_LEFT|PSP_CTRL_RIGHT) -#define PSP_4BUTTONS (PSP_CTRL_CROSS | PSP_CTRL_CIRCLE | PSP_CTRL_TRIANGLE | PSP_CTRL_SQUARE) - -/* - * Attempts to read a character from the controller - * Uses the state machine. - */ -bool PSPKeyboard::processInput(Common::Event &event, SceCtrlData &pad, bool &usedInput) { - usedInput = false; // Assume we don't use an input - bool haveEvent = false; // Whether we have an event for the event manager to process - event.kbd.flags = 0; - unsigned int keyDown; - uint32 buttonsChanged = _prevButtons ^ pad.Buttons; - - if (!_init) // In case we never had init - goto END; - - if (PRESSED(PSP_CTRL_SELECT)) { +void PSPKeyboard::setVisible(bool val) { + if (val && _state == kInvisible && _init) { // Check also that were loaded correctly _lastState = _state; - _state = kMove; // Check for move or visible state - usedInput = true; - goto END; - } - - if (_state == kInvisible) // Return if we're invisible - goto END; - - if (DOWN(PSP_DPAD | PSP_4BUTTONS | PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER | PSP_CTRL_START)) - usedInput = true; // for now, we neutralize all button inputs - - // Check for moving the keyboard onscreen - if (_state == kMove) { - if (UNPRESSED(PSP_CTRL_SELECT)) { - _state = (_lastState == kInvisible) ? kDefault : kInvisible; // Back to previous state - _dirty = true; - - if (_moved) { // We moved the keyboard. Keep the keyboard onscreen - _state = kDefault; - _moved = false; // reset moved flag - } - } - else if (DOWN(PSP_DPAD)) { - _moved = true; - _dirty = true; - - if (DOWN(PSP_CTRL_DOWN)) - increaseKeyboardLocationY(5); - else if (DOWN(PSP_CTRL_UP)) - increaseKeyboardLocationY(-5); - else if (DOWN(PSP_CTRL_LEFT)) - increaseKeyboardLocationX(-5); - else /* DOWN(PSP_CTRL_RIGHT) */ - increaseKeyboardLocationX(5); - } - usedInput = true; // We used up the input (select was held down) - goto END; - } - - - // Handle 4 buttons + 2 triggers - if (_state == kDefault || _state == kCornersSelected) { - unsigned int changed; - - if (_state == kDefault) { // Handle default state - changed = CHANGED(PSP_4BUTTONS); // We only care about the 4 buttons - if (PRESSED(PSP_CTRL_LTRIGGER)) { // Don't say we used up the input - _state = kLTriggerDown; - goto END; - } - else if (PRESSED(PSP_CTRL_RTRIGGER)) { // Don't say we used up the input - _state = kRTriggerDown; - goto END; - } - - if (DOWN(PSP_4BUTTONS)) - usedInput = true; // Make sure these button presses don't get through - } else { /* _state == kCornersSelected */ - // We care about 4 buttons + triggers (for letter selection) - changed = CHANGED(PSP_4BUTTONS | PSP_CTRL_RTRIGGER | PSP_CTRL_LTRIGGER); - - if (DOWN(PSP_4BUTTONS | PSP_CTRL_RTRIGGER | PSP_CTRL_LTRIGGER)) - usedInput = true; // Make sure these button presses don't get through - } - - if (changed) { //pressing a char select button -- both states - - int innerChoice; - - if (UNPRESSED(PSP_CTRL_TRIANGLE)) { - innerChoice = 0; - event.type = Common::EVENT_KEYUP; // We give priority to key_up - } else if (UNPRESSED(PSP_CTRL_CIRCLE)) { - innerChoice = 1; - event.type = Common::EVENT_KEYUP; // We give priority to key_up - } else if (UNPRESSED(PSP_CTRL_CROSS)) { - innerChoice = 2; - event.type = Common::EVENT_KEYUP; // We give priority to key_up - } else if (UNPRESSED(PSP_CTRL_SQUARE)) { - innerChoice = 3; - event.type = Common::EVENT_KEYUP; // We give priority to key_up - } else if (UNPRESSED(PSP_CTRL_LTRIGGER) && _state == kCornersSelected) { - innerChoice = 4; - event.type = Common::EVENT_KEYUP; // We give priority to key_up - } else if (UNPRESSED(PSP_CTRL_RTRIGGER) && _state == kCornersSelected) { - innerChoice = 5; - event.type = Common::EVENT_KEYUP; // We give priority to key_up - } else if (PRESSED(PSP_CTRL_TRIANGLE)) { - innerChoice = 0; - event.type = Common::EVENT_KEYDOWN; - } else if (PRESSED(PSP_CTRL_CIRCLE)) { - innerChoice = 1; - event.type = Common::EVENT_KEYDOWN; - } else if (PRESSED(PSP_CTRL_CROSS)) { - innerChoice = 2; - event.type = Common::EVENT_KEYDOWN; - } else if (PRESSED(PSP_CTRL_SQUARE)) { - innerChoice = 3; - event.type = Common::EVENT_KEYDOWN; - } else if (PRESSED(PSP_CTRL_LTRIGGER) && _state == kCornersSelected) { - innerChoice = 4; - event.type = Common::EVENT_KEYDOWN; // We give priority to key_up - } else /* (UNPRESSED(PSP_CTRL_RTRIGGER)) && _state == kCornersSelected */ { - innerChoice = 5; - event.type = Common::EVENT_KEYDOWN; // We give priority to key_up - } - - #define IS_UPPERCASE(x) ((x) >= (unsigned short)'A' && (x) <= (unsigned short)'Z') - #define TO_LOWER(x) ((x) += 'a'-'A') - - //Now grab the value out of the array - short choice = _modeChar[_mode][_oldCursor][innerChoice]; - - event.kbd.ascii = choice <= 255 ? choice : 0; - - // Handle upper-case which is missing in Common::KeyCode - if (IS_UPPERCASE(choice)) { - event.kbd.keycode = (Common::KeyCode) TO_LOWER(choice); - event.kbd.flags = Common::KBD_SHIFT; - } else - event.kbd.keycode = (Common::KeyCode) choice; - - haveEvent = (choice != Common::KEYCODE_INVALID) ? true : false; // We have an event/don't if it's invalid - usedInput = true; - } - } - - // Check for movement of cursor - if (_state == kDefault || _state == kCornersSelected) { - // Check if a dependent button is down - if (_state == kDefault) - keyDown = DOWN(PSP_4BUTTONS); - else /* if (_state == kCornersSelected) */ - keyDown = DOWN(PSP_4BUTTONS | PSP_CTRL_RTRIGGER | PSP_CTRL_LTRIGGER); - - Cursor cursor = _oldCursor; - - // Find where the cursor is pointing - if (keyDown == false) { // Don't allow movement if a nub-dependent key is down - cursor = kCenter; - _state = kDefault; - - if (DOWN(PSP_DPAD)) { - _state = kCornersSelected; - usedInput = true; // Make sure the pressed d-pad is used up - - if (DOWN(PSP_CTRL_UP)) - cursor = kUp; - else if (DOWN(PSP_CTRL_RIGHT)) - cursor = kRight; - else if (DOWN(PSP_CTRL_DOWN)) - cursor = kDown; - else if (DOWN(PSP_CTRL_LEFT)) - cursor = kLeft; - } - } - - if (cursor != _oldCursor) { //If we've moved, update dirty and return - _dirty = true; - _oldCursor = cursor; - usedInput = true; // We 'used up' the input - //goto END; // We didn't find an event - } - } - - // Deal with trigger states - if (_state == kRTriggerDown) { - usedInput = true; - - if (UNPRESSED(PSP_CTRL_RTRIGGER)) { - _dirty = true; - - if(_mode > 1) - _mode = 0; - else - _mode = (_mode == 0) ? 1 : 0; - - usedInput = true; - _state = kDefault; - - goto END; - } - } else if (_state == kLTriggerDown) { - usedInput = true; - - if (UNPRESSED(PSP_CTRL_LTRIGGER)) { - _dirty = true; - - if(_mode < 2) - _mode = 2; - else - _mode = (_mode == 2) ? 3 : 2; - - usedInput = true; - _state = kDefault; - - goto END; - } + _state = kMove; } - - // Handle start button: enter plus make keyboard invisible - if (CHANGED(PSP_CTRL_START)) { - event.kbd.ascii = '\n'; - event.kbd.keycode = Common::KEYCODE_RETURN; - event.type = DOWN(PSP_CTRL_START) ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP; - usedInput = true; // Don't let start get through - haveEvent = true; - if (UP(PSP_CTRL_START)) - _state = kInvisible; // Make us invisible if unpressed + else if ( !val && _state != kInvisible) { + _lastState = _state; + _state = kInvisible; } - -END: - _prevButtons = pad.Buttons; - return haveEvent; + setDirty(); } - /* move the position the keyboard is currently drawn at */ void PSPKeyboard::moveTo(const int newX, const int newY) { - _moved_x = newX; - _moved_y = newY; + DEBUG_ENTER_FUNC(); + + _movedX = newX; + _movedY = newY; + setDirty(); + + DEBUG_EXIT_FUNC(); } /* move the position the keyboard is currently drawn at */ void PSPKeyboard::increaseKeyboardLocationX(int amount) { - int newX = _moved_x + amount; + DEBUG_ENTER_FUNC(); + + int newX = _movedX + amount; - if (newX > PSP_SCREEN_WIDTH - 5 || newX < 0 - 140) // clamp + if (newX > PSP_SCREEN_WIDTH - 5 || newX < 0 - 140) { // clamp + DEBUG_EXIT_FUNC(); return; - _moved_x = newX; + } + _movedX = newX; + setDirty(); + + DEBUG_EXIT_FUNC(); } /* move the position the keyboard is currently drawn at */ void PSPKeyboard::increaseKeyboardLocationY(int amount) { - int newY = _moved_y + amount; + DEBUG_ENTER_FUNC(); + + int newY = _movedY + amount; - if (newY > PSP_SCREEN_HEIGHT - 5 || newY < 0 - 140) // clamp + if (newY > PSP_SCREEN_HEIGHT - 5 || newY < 0 - 140) { // clamp + DEBUG_EXIT_FUNC(); return; - _moved_y = newY; + } + _movedY = newY; + setDirty(); + + DEBUG_EXIT_FUNC(); } /* draw the keyboard at the current position */ void PSPKeyboard::render() { - _dirty = false; + DEBUG_ENTER_FUNC(); + + unsigned int currentBuffer = _mode<<1; + + // Draw the background letters + // Set renderer to current buffer & palette + _renderer.setBuffer(&_buffers[currentBuffer]); + _renderer.setPalette(&_palettes[currentBuffer]); + _renderer.setOffsetOnScreen(_movedX, _movedY); + _renderer.setOffsetInBuffer(0, 0); + _renderer.setDrawWholeBuffer(); + _renderer.render(); + + // Get X and Y coordinates for the orange block int x, y; + convertCursorToXY(_oldCursor, x, y); + + const int OrangeBlockSize = 64; + const int GrayBlockSize = 43; + + // Draw the current Highlighted Selector (orange block) + _renderer.setBuffer(&_buffers[currentBuffer + 1]); + _renderer.setPalette(&_palettes[currentBuffer + 1]); + _renderer.setOffsetOnScreen(_movedX + (x * GrayBlockSize), _movedY + (y * GrayBlockSize)); + _renderer.setOffsetInBuffer(x * OrangeBlockSize, y * OrangeBlockSize); + _renderer.setDrawSize(OrangeBlockSize, OrangeBlockSize); + _renderer.render(); + + DEBUG_EXIT_FUNC(); +} - switch(_oldCursor) { +inline void PSPKeyboard::convertCursorToXY(CursorDirections cur, int &x, int &y) { + switch(cur) { case kUp: x = 1; y = 0; @@ -423,76 +257,17 @@ void PSPKeyboard::render() { y = 1; break; } - - // Draw the background letters - surface_draw_offset(&_keyTextures[_mode<<1], 0, 0, 0, 0, - _keyTextures[_mode<<1].texture_width, - _keyTextures[_mode<<1].texture_height); - - // Draw the current Highlighted Selector (orange bit) - surface_draw_offset(&_keyTextures[(_mode<<1) + 1], - //Offset from the current draw position to render at - x * 43, y * 43, - //internal offset of the image - x * 64, y * 64, - //size to render (always the same) - 64, 64); -} - - -// Render the given surface at the current screen position offset by screenX, screenY -// the surface will be internally offset by offsetX,offsetY. And the size of it to be drawn will be intWidth,intHeight -void PSPKeyboard::surface_draw_offset(struct gu_surface* surface, int screenX, int screenY, int offsetX, int offsetY, int intWidth, int intHeight) { - sceGuAlphaFunc( GU_GREATER, 0, 0xff ); - sceGuEnable( GU_ALPHA_TEST ); - sceGuTexFunc(GU_TFX_BLEND,GU_TCC_RGBA); - sceGuTexEnvColor(0xFF000000); - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0 ); - sceGuEnable(GU_BLEND); - if (surface->paletteSize == 256) { // 8-bit - sceGuClutMode(GU_PSM_8888, 0, 0xFF, 0); - sceGuClutLoad(32, surface->palette); // upload 32*8 entries (256) - sceGuTexMode(GU_PSM_T8, 0, 0, 0); // 8-bit image - } else if (surface->paletteSize == 16) { // 4-bit - sceGuClutMode(GU_PSM_8888, 0, 0x0F, 0); - sceGuClutLoad(2, surface->palette); // upload 2*8 entries (16) - sceGuTexMode(GU_PSM_T4, 0, 0, 0); // 4-bit image - } else { // 32-bit - sceGuTexMode(GU_PSM_8888,0,0,GU_FALSE); - } - sceGuTexImage(0,surface->surface_width, surface->surface_height,surface->surface_width, surface->texture); - sceGuTexFunc(GU_TFX_MODULATE,GU_TCC_RGBA); - - Vertex* c_vertices = (Vertex*)sceGuGetMemory(2 * sizeof(Vertex)); - - c_vertices[0].u = offsetX; - c_vertices[0].v = offsetY; - c_vertices[0].x = _moved_x + screenX; - c_vertices[0].y = _moved_y + screenY; - c_vertices[0].z = 0; - c_vertices[0].color = 0xFFFFFFFF; - - c_vertices[1].u = offsetX + intWidth; - c_vertices[1].v = offsetY + intHeight; - c_vertices[1].x = _moved_x + screenX + intWidth; - c_vertices[1].y = _moved_y + screenY + intHeight; - c_vertices[1].z = 0; - c_vertices[1].color = 0xFFFFFFFF; - - sceGuDrawArray(GU_SPRITES,GU_TEXTURE_32BITF|GU_COLOR_8888|GU_VERTEX_32BITF|GU_TRANSFORM_2D,2,0,c_vertices); - - sceGuDisable( GU_BLEND ); - sceGuDisable( GU_ALPHA_TEST ); } -/* load all the guibits that make up the OSK */ +/* load the keyboard into memory */ bool PSPKeyboard::load() { - unsigned char *temp_texture = NULL; - uint32 *temp_palette = NULL; - int a; + DEBUG_ENTER_FUNC(); - if (_init) + if (_init) { + PSP_DEBUG_PRINT("keyboard already loaded into memory\n"); + DEBUG_EXIT_FUNC(); return true; + } // For the shell, we must use a hack #ifdef PSP_KB_SHELL @@ -500,221 +275,131 @@ bool PSPKeyboard::load() { #else /* normal mode */ Common::FSNode node("."); // Look in current directory #endif -#ifdef PSP_KB_DEBUG - fprintf(stderr, "path = %s\n", node.getPath().c_str()); -#endif + PSP_DEBUG_PRINT("path[%s]\n", node.getPath().c_str()); Common::Archive *fileArchive = NULL; Common::Archive *zipArchive = NULL; Common::SeekableReadStream * file = 0; if (node.getChild("kbd").exists() && node.getChild("kbd").isDirectory()) { -#ifdef PSP_KB_DEBUG - fprintf(stderr, "found directory ./kbd\n"); -#endif + PSP_DEBUG_PRINT("found directory ./kbd\n"); fileArchive = new Common::FSDirectory(node.getChild("kbd")); } if (node.getChild("kbd.zip").exists()) { -#ifdef PSP_KB_DEBUG - fprintf(stderr, "found kbd.zip\n"); -#endif + PSP_DEBUG_PRINT("found kbd.zip\n"); zipArchive = Common::makeZipArchive(node.getChild("kbd.zip")); } - // Loop through different png images - for (a = 0; a < guiStringsSize; a++) { + int i; + + // Loop through all png images + for (i = 0; i < guiStringsSize; i++) { uint32 height = 0, width = 0, paletteSize = 0; -#ifdef PSP_KB_DEBUG - fprintf(stderr, "load(): Opening %s.\n", _guiStrings[a]); -#endif + PSP_DEBUG_PRINT("Opening %s.\n", _guiStrings[i]); // Look for the file in the kbd directory - if (fileArchive && fileArchive->hasFile(_guiStrings[a])) { - -#ifdef PSP_KB_DEBUG - fprintf(stderr, "load(): found it in kbd directory.\n"); -#endif + if (fileArchive && fileArchive->hasFile(_guiStrings[i])) { + PSP_DEBUG_PRINT("found it in kbd directory.\n"); - file = fileArchive->createReadStreamForMember(_guiStrings[a]); + file = fileArchive->createReadStreamForMember(_guiStrings[i]); if (!file) { - fprintf(stderr, "load(): Can't open kbd/%s for keyboard. No keyboard will load.\n", _guiStrings[a]); + PSP_ERROR("Can't open kbd/%s for keyboard. No keyboard will load.\n", _guiStrings[i]); goto ERROR; } } // We didn't find it. Look for it in the zip file - else if (zipArchive && zipArchive->hasFile(_guiStrings[a])) { + else if (zipArchive && zipArchive->hasFile(_guiStrings[i])) { + PSP_DEBUG_PRINT("found it in kbd.zip.\n"); -#ifdef PSP_KB_DEBUG - fprintf(stderr, "load(): found it in kbd.zip.\n"); -#endif - - file = zipArchive->createReadStreamForMember(_guiStrings[a]); + file = zipArchive->createReadStreamForMember(_guiStrings[i]); if (!file) { - fprintf(stderr, "Can't open %s in kbd.zip for keyboard. No keyboard will load.\n", _guiStrings[a]); + PSP_ERROR("Can't open %s in kbd.zip for keyboard. No keyboard will load.\n", _guiStrings[i]); goto ERROR; } } else { // Couldn't find the file - fprintf(stderr, "load(): Can't find %s for keyboard. No keyboard will load.\n", _guiStrings[a]); + PSP_ERROR("Can't find %s for keyboard. No keyboard will load.\n", _guiStrings[i]); goto ERROR; } - if (get_png_image_size(file, &width, &height, &paletteSize) == 0) { // Check image size and palette size + if (getPngImageSize(file, &width, &height, &paletteSize) == 0) { // Check image size and palette size // Allocate memory for image -#ifdef PSP_KB_DEBUG - fprintf(stderr, "load(): width=%d, height=%d, paletteSize=%d\n", width, height, paletteSize); -#endif - + PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d]\n", width, height, paletteSize); + _buffers[i].setSize(width, height, Buffer::kSizeByTextureSize); + if (paletteSize) { // 8 or 4-bit image - uint32 textureSize = 0; - if (paletteSize <= 16) { // 4 bit - paletteSize = 16; - textureSize = (width * height)>>1; + _buffers[i].setPixelFormat(PSPPixelFormat::Type_Palette_4bit); + _palettes[i].setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_4bit); + paletteSize = 16; } else if (paletteSize <= 256){ // 8-bit image paletteSize = 256; - textureSize = width * height; + _buffers[i].setPixelFormat(PSPPixelFormat::Type_Palette_8bit); + _palettes[i].setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_8bit); } else { - fprintf(stderr, "Error: palette of %d too big!\n", paletteSize); + PSP_ERROR("palette of %d too big!\n", paletteSize); goto ERROR; } -#ifdef PSP_KB_DEBUG - fprintf(stderr, "load(): allocating %d bytes for texture and %d for palette\n", textureSize, paletteSize*4); -#endif - temp_texture = (u8 *)malloc(textureSize); - temp_palette = (uint32 *)memalign(16, paletteSize<<2); - memset(temp_palette, 0, paletteSize<<2); // Set to 0 since we might only fill some of it + } else { // 32-bit image - temp_texture = (unsigned char *)malloc((width * height)<<2); + _buffers[i].setPixelFormat(PSPPixelFormat::Type_8888); } + + _buffers[i].allocate(); + _palettes[i].allocate(); // Try to load the image file->seek(0); // Go back to start - if (load_png_image(file, temp_texture, temp_palette) != 0) + if (loadPngImage(file, _buffers[i], _palettes[i]) != 0) goto ERROR; else { // Success -#ifdef PSP_KB_DEBUG - fprintf(stderr, "Managed to load the image.\n"); -#endif - // we need to store the texture in an image of width and heights of 2^n sizes - _keyTextures[a].texture_width = width; // original size - _keyTextures[a].texture_height = height; - _keyTextures[a].surface_width = convert_pow2(width); // converted size - _keyTextures[a].surface_height = convert_pow2(height); - _keyTextures[a].palette = temp_palette; - _keyTextures[a].paletteSize = paletteSize; - - uint32 size; - - if (paletteSize == 16) // 4 bit - size = (_keyTextures[a].surface_width * _keyTextures[a].surface_height)>>1; - else if (paletteSize == 256) // 8-bit - size = _keyTextures[a].surface_width * _keyTextures[a].surface_height; - else // 32 bit - size = (_keyTextures[a].surface_width * _keyTextures[a].surface_height)<<2; - -#ifdef PSP_KB_DEBUG - fprintf(stderr, "load(): perm texture width=%d, height=%d, size=%d\n", _keyTextures[a].surface_width, _keyTextures[a].surface_height, size); -#endif - _keyTextures[a].texture = (unsigned char *)memalign(16, size); // Allocate memory - - block_copy(&_keyTextures[a], temp_texture); // Copy temp texture to permanent texture + PSP_DEBUG_PRINT("Managed to load the image\n"); if (paletteSize == 16) // 4-bit - flipNibbles(&_keyTextures[a]); - - free(temp_texture); + _buffers[i].flipNibbles(); delete file; } } - else + else { + PSP_ERROR("couldn't obtain PNG image size\n"); goto ERROR; + } } /* for loop */ + _init = true; delete fileArchive; delete zipArchive; + DEBUG_EXIT_FUNC(); return true; ERROR: - // Error .. Couldn't get png info from one of the needed files - free(temp_texture); delete file; delete fileArchive; delete zipArchive; - for (int b = 0; b < a; b++) { - free(_keyTextures[b].texture); - free(_keyTextures[b].palette); - _keyTextures[b].texture = NULL; + for (int j = 0; j < i; j++) { + _buffers[j].deallocate(); + _palettes[j].deallocate(); } _init = false; + + DEBUG_EXIT_FUNC(); return false; } -// Copy texture from regular size image to power of 2 size image -// -void PSPKeyboard::block_copy(gu_surface* surface, u8 *texture) { - u32 stride = 0, width = 0; - - switch(surface->paletteSize) { - case 16: // 4-bit - width = surface->texture_width >> 1; - stride = (surface->surface_width - surface->texture_width)>>1; - break; - case 256: // 8-bit - width = surface->texture_width; - stride = surface->surface_width - surface->texture_width; - break; - case 0: // 32-bit - width = surface->texture_width << 2; - stride = (surface->surface_width - surface->texture_width)<<2; - break; - default: - fprintf(stderr, "Error in block_copy: bad value in paletteSize = %d\n", surface->paletteSize); - return; - } - - u8 *src = texture; - u8 *dest = surface->texture; - - for (unsigned int y = 0; y < surface->texture_height; y++) { - memcpy(dest, src, width); - dest += width; - src += width; - - // skip at the end of each line - if (stride > 0) { - dest += stride; - } - } -} - -// Convert 4 bit images to match weird PSP format -// -void PSPKeyboard::flipNibbles(gu_surface* surface) { - u32 *dest = (u32 *)surface->texture; - - for (u32 y = 0; y < surface->texture_height; y++) { - for (u32 x = 0; x < (surface->surface_width >> 3); x++) { - u32 val = *dest; - *dest++ = ((val >> 4) & 0x0F0F0F0F) | ((val << 4) & 0xF0F0F0F0); - } - } - -} - - static void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg) { // ignore PNG warnings } /* Get the width and height of a png image */ -int PSPKeyboard::get_png_image_size(Common::SeekableReadStream *file, uint32 *png_width, uint32 *png_height, u32 *paletteSize) { +int PSPKeyboard::getPngImageSize(Common::SeekableReadStream *file, uint32 *png_width, uint32 *png_height, u32 *paletteSize) { + DEBUG_ENTER_FUNC(); + png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; @@ -723,12 +408,14 @@ int PSPKeyboard::get_png_image_size(Common::SeekableReadStream *file, uint32 *pn png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { + DEBUG_EXIT_FUNC(); return -1; } png_set_error_fn(png_ptr, (png_voidp) NULL, (png_error_ptr) NULL, user_warning_fn); info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); + DEBUG_EXIT_FUNC(); return -1; } // Set the png lib to use our read function @@ -746,22 +433,27 @@ int PSPKeyboard::get_png_image_size(Common::SeekableReadStream *file, uint32 *pn *png_width = width; *png_height = height; + + DEBUG_EXIT_FUNC(); return 0; } // Load a texture from a png image // -int PSPKeyboard::load_png_image(Common::SeekableReadStream *file, unsigned char *ImageBuffer, uint32 *palette) { +int PSPKeyboard::loadPngImage(Common::SeekableReadStream *file, Buffer &buffer, Palette &palette) { + DEBUG_ENTER_FUNC(); + png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; png_uint_32 width, height; int bit_depth, color_type, interlace_type; - size_t x, y; + size_t y; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { - fprintf(stderr, "load_png_image(): Error: couldn't create read struct to load keyboard.\n"); + PSP_ERROR("Couldn't create read struct to load keyboard\n"); + DEBUG_EXIT_FUNC(); return -1; } // Use dummy error function @@ -769,11 +461,13 @@ int PSPKeyboard::load_png_image(Common::SeekableReadStream *file, unsigned char info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { + PSP_ERROR("Couldn't create info struct to load keyboard\n"); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); + DEBUG_EXIT_FUNC(); return -1; } - // Set the png lib to use our read function + // Set the png lib to use our customized read function png_set_read_fn(png_ptr, (void *)file, pngReadStreamRead); png_set_sig_bytes(png_ptr, sig_read); @@ -784,71 +478,278 @@ int PSPKeyboard::load_png_image(Common::SeekableReadStream *file, unsigned char png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) { - // We copy the palette - uint32 *dstPal = palette; + // Copy the palette png_colorp srcPal = info_ptr->palette; for(int i=0; i < info_ptr->num_palette; i++) { unsigned char alphaVal = (i < info_ptr->num_trans) ? info_ptr->trans[i] : 0xFF; // Load alpha if it's there - *dstPal++ = GU_ARGB(alphaVal, srcPal->red, srcPal->green, srcPal->blue); + palette.setSingleColorRGBA(i, srcPal->red, srcPal->green, srcPal->blue, alphaVal); srcPal++; } - - unsigned char *line = (unsigned char*) malloc(info_ptr->rowbytes); - if (!line) { - png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); - return -1; - } - - for (y = 0; y < height; y++) { - png_read_row(png_ptr, line, png_bytep_NULL); - memcpy(&ImageBuffer[y * info_ptr->rowbytes], line, info_ptr->rowbytes); - } - - free(line); } else { // Not a palettized image + // Round up grayscale images if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); // Convert trans channel to alpha for 32 bits if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); + // Filler for alpha? png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + } - u32* line = (u32*) malloc(width<<2); - if (!line) { - png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); - return -1; - } - - u32* Image = (u32 *)ImageBuffer; - for (y = 0; y < height; y++) { - png_read_row(png_ptr, (u8*) line, png_bytep_NULL); - for (x = 0; x < width; x++) { - Image[y*width + x] = line[x]; - } - } + unsigned char *line = (unsigned char*) malloc(info_ptr->rowbytes); + if (!line) { + png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); + PSP_ERROR("Couldn't allocate line\n"); + DEBUG_EXIT_FUNC(); + return -1; + } - free(line); + for (y = 0; y < height; y++) { + png_read_row(png_ptr, line, png_bytep_NULL); + buffer.copyFromRect(line, info_ptr->rowbytes, 0, y, width, 1); // Copy into buffer + //memcpy(buffer.getPixels()[y * buffer.getWidthInBytes()], line, info_ptr->rowbytes); } + free(line); + png_read_end(png_ptr, info_ptr); png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + DEBUG_EXIT_FUNC(); return 0; } -// Function to get the lowest power of 2 higher than our image size -// -uint32 PSPKeyboard::convert_pow2(uint32 size) { - uint32 pow_counter = 0; - - for (; pow_counter < 32; pow_counter++) { - // Find the first value which is higher - if ((size >> pow_counter) == 0) { - // take already good values into account - if (((uint32) 1 << pow_counter) != size) - return ((uint32)1 << pow_counter); - else - return ((uint32)1 << (pow_counter-1)); +// Defines for working with PSP buttons +#define CHANGED(x) (_buttonsChanged & (x)) +#define PRESSED(x) ((_buttonsChanged & (x)) && (pad.Buttons & (x))) +#define UNPRESSED(x) ((_buttonsChanged & (x)) && !(pad.Buttons & (x))) +#define DOWN(x) (pad.Buttons & (x)) +#define UP(x) (!(pad.Buttons & (x))) +#define PSP_DPAD (PSP_CTRL_DOWN|PSP_CTRL_UP|PSP_CTRL_LEFT|PSP_CTRL_RIGHT) +#define PSP_4BUTTONS (PSP_CTRL_CROSS | PSP_CTRL_CIRCLE | PSP_CTRL_TRIANGLE | PSP_CTRL_SQUARE) + +/* + * Attempts to read a character from the controller + * Uses the state machine. + * returns whether we have an event + */ +bool PSPKeyboard::processInput(Common::Event &event, SceCtrlData &pad) { + DEBUG_ENTER_FUNC(); + + bool haveEvent = false; // Whether we have an event for the event manager to process + event.kbd.flags = 0; + + _buttonsChanged = _prevButtons ^ pad.Buttons; + + if (!_init) // In case we never had init + return false; + if (_state == kInvisible) // Return if we're invisible + return false; + if (_state != kMove && PRESSED(PSP_CTRL_SELECT)) { + _lastState = _state; + _state = kMove; // Check for move or visible state + } + else if (CHANGED(PSP_CTRL_START)) { // Handle start button: enter, make KB invisible + event.kbd.ascii = '\r'; + event.kbd.keycode = Common::KEYCODE_RETURN; + event.type = DOWN(PSP_CTRL_START) ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP; + haveEvent = true; + _dirty = true; + if (UP(PSP_CTRL_START)) + _state = kInvisible; // Make us invisible if unpressed + } + // Check for being in state of moving the keyboard onscreen or pressing select + else if (_state == kMove) + handleMoveState(pad); + else if (_state == kDefault) + haveEvent = handleDefaultState(event, pad); + else if (_state == kCornersSelected) + haveEvent = handleCornersSelectedState(event, pad); + else if (_state == kRTriggerDown) + handleRTriggerDownState(pad); // Deal with trigger states + else if (_state == kLTriggerDown) + handleLTriggerDownState(pad); // Deal with trigger states + + _prevButtons = pad.Buttons; + + DEBUG_EXIT_FUNC(); + return haveEvent; +} + +void PSPKeyboard::handleMoveState(SceCtrlData &pad) { + DEBUG_ENTER_FUNC(); + if (UP(PSP_CTRL_SELECT)) { + // Toggle between visible and invisible + _state = (_lastState == kInvisible) ? kDefault : kInvisible; + _dirty = true; + + if (_moved) { // We moved the keyboard. Keep the keyboard onscreen anyway + _state = kDefault; + _moved = false; // reset moved flag } + } else if (DOWN(PSP_DPAD)) { // How we move the KB onscreen + _moved = true; + _dirty = true; + + if (DOWN(PSP_CTRL_DOWN)) + increaseKeyboardLocationY(5); + else if (DOWN(PSP_CTRL_UP)) + increaseKeyboardLocationY(-5); + else if (DOWN(PSP_CTRL_LEFT)) + increaseKeyboardLocationX(-5); + else /* DOWN(PSP_CTRL_RIGHT) */ + increaseKeyboardLocationX(5); } - return 0; + DEBUG_EXIT_FUNC(); +} + +bool PSPKeyboard::handleDefaultState(Common::Event &event, SceCtrlData &pad) { + DEBUG_ENTER_FUNC(); + bool haveEvent = false; + + if (PRESSED(PSP_CTRL_LTRIGGER)) // Don't say we used up the input + _state = kLTriggerDown; + else if (PRESSED(PSP_CTRL_RTRIGGER)) // Don't say we used up the input + _state = kRTriggerDown; + else if (CHANGED(PSP_4BUTTONS)) // We only care about the 4 buttons + haveEvent = getInputChoice(event, pad); + else if (!DOWN(PSP_4BUTTONS)) // Must be up to move cursor + getCursorMovement(pad); + + DEBUG_EXIT_FUNC(); + return haveEvent; } +bool PSPKeyboard::handleCornersSelectedState(Common::Event &event, SceCtrlData &pad) { + DEBUG_ENTER_FUNC(); + // We care about 4 buttons + triggers (for letter selection) + bool haveEvent = false; + + if (CHANGED(PSP_4BUTTONS | PSP_CTRL_RTRIGGER | PSP_CTRL_LTRIGGER)) + haveEvent = getInputChoice(event, pad); + if (!DOWN(PSP_4BUTTONS | PSP_CTRL_RTRIGGER | PSP_CTRL_LTRIGGER)) // Must be up to move cursor + getCursorMovement(pad) + + DEBUG_EXIT_FUNC(); + return haveEvent; +} + +bool PSPKeyboard::getInputChoice(Common::Event &event, SceCtrlData &pad) { + DEBUG_ENTER_FUNC(); + int innerChoice; + bool haveEvent = false; + + if (UNPRESSED(PSP_CTRL_TRIANGLE)) { + innerChoice = 0; + event.type = Common::EVENT_KEYUP; // We give priority to key_up + } else if (UNPRESSED(PSP_CTRL_CIRCLE)) { + innerChoice = 1; + event.type = Common::EVENT_KEYUP; // We give priority to key_up + } else if (UNPRESSED(PSP_CTRL_CROSS)) { + innerChoice = 2; + event.type = Common::EVENT_KEYUP; // We give priority to key_up + } else if (UNPRESSED(PSP_CTRL_SQUARE)) { + innerChoice = 3; + event.type = Common::EVENT_KEYUP; // We give priority to key_up + } else if (UNPRESSED(PSP_CTRL_LTRIGGER) && _state == kCornersSelected) { + innerChoice = 4; + event.type = Common::EVENT_KEYUP; // We give priority to key_up + } else if (UNPRESSED(PSP_CTRL_RTRIGGER) && _state == kCornersSelected) { + innerChoice = 5; + event.type = Common::EVENT_KEYUP; // We give priority to key_up + } else if (PRESSED(PSP_CTRL_TRIANGLE)) { + innerChoice = 0; + event.type = Common::EVENT_KEYDOWN; + } else if (PRESSED(PSP_CTRL_CIRCLE)) { + innerChoice = 1; + event.type = Common::EVENT_KEYDOWN; + } else if (PRESSED(PSP_CTRL_CROSS)) { + innerChoice = 2; + event.type = Common::EVENT_KEYDOWN; + } else if (PRESSED(PSP_CTRL_SQUARE)) { + innerChoice = 3; + event.type = Common::EVENT_KEYDOWN; + } else if (PRESSED(PSP_CTRL_LTRIGGER) && _state == kCornersSelected) { + innerChoice = 4; + event.type = Common::EVENT_KEYDOWN; // We give priority to key_up + } else /* (PRESSED(PSP_CTRL_RTRIGGER)) && _state == kCornersSelected */ { + innerChoice = 5; + event.type = Common::EVENT_KEYDOWN; // We give priority to key_up + } + + #define IS_UPPERCASE(x) ((x) >= (unsigned short)'A' && (x) <= (unsigned short)'Z') + #define TO_LOWER(x) ((x) += 'a'-'A') + + //Now grab the value out of the array + short choice = _modeChar[_mode][_oldCursor][innerChoice]; + + event.kbd.ascii = choice <= 255 ? choice : 0; + + // Handle upper-case which is missing in Common::KeyCode + if (IS_UPPERCASE(choice)) { + event.kbd.keycode = (Common::KeyCode) TO_LOWER(choice); + event.kbd.flags = Common::KBD_SHIFT; + } else + event.kbd.keycode = (Common::KeyCode) choice; + + haveEvent = (choice != Common::KEYCODE_INVALID) ? true : false; // We have an event/don't if it's invalid + + DEBUG_EXIT_FUNC(); + return haveEvent; +} + +void PSPKeyboard::getCursorMovement(SceCtrlData &pad) { + DEBUG_ENTER_FUNC(); + CursorDirections cursor; + + // Find where the cursor is pointing + cursor = kCenter; + _state = kDefault; + + if (DOWN(PSP_DPAD)) { + _state = kCornersSelected; + + if (DOWN(PSP_CTRL_UP)) + cursor = kUp; + else if (DOWN(PSP_CTRL_RIGHT)) + cursor = kRight; + else if (DOWN(PSP_CTRL_DOWN)) + cursor = kDown; + else if (DOWN(PSP_CTRL_LEFT)) + cursor = kLeft; + } + + if (cursor != _oldCursor) { //If we've moved, update dirty and return + _dirty = true; + _oldCursor = cursor; + } + DEBUG_EXIT_FUNC(); +} + +void PSPKeyboard::handleLTriggerDownState(SceCtrlData &pad) { + DEBUG_ENTER_FUNC(); + if (UNPRESSED(PSP_CTRL_LTRIGGER)) { + _dirty = true; + + if(_mode < 2) + _mode = 2; + else + _mode = (_mode == 2) ? 3 : 2; + + _state = kDefault; + } + DEBUG_EXIT_FUNC(); +} + +void PSPKeyboard::handleRTriggerDownState(SceCtrlData &pad) { + DEBUG_ENTER_FUNC(); + if (UNPRESSED(PSP_CTRL_RTRIGGER)) { + _dirty = true; + + if(_mode > 1) + _mode = 0; + else + _mode = (_mode == 0) ? 1 : 0; + + _state = kDefault; + } + DEBUG_EXIT_FUNC(); +} |