aboutsummaryrefslogtreecommitdiff
path: root/backends/platform/psp
diff options
context:
space:
mode:
authorYotam Barnoy2010-10-31 11:08:43 +0000
committerYotam Barnoy2010-10-31 11:08:43 +0000
commit94c8d0a14df429a1b25bd9f5c5d75497fd0ddbd1 (patch)
tree3df2a4ae7967c56d464729669fc06ce4e93dff36 /backends/platform/psp
parent8df4278ba8cfbf71228e1927f9db635a9a30a57f (diff)
parentdca3c8d8bfc6c4db38cf8e8291818dd472041d4e (diff)
downloadscummvm-rg350-94c8d0a14df429a1b25bd9f5c5d75497fd0ddbd1.tar.gz
scummvm-rg350-94c8d0a14df429a1b25bd9f5c5d75497fd0ddbd1.tar.bz2
scummvm-rg350-94c8d0a14df429a1b25bd9f5c5d75497fd0ddbd1.zip
Updated with latest from trunk
svn-id: r53976
Diffstat (limited to 'backends/platform/psp')
-rw-r--r--backends/platform/psp/Makefile9
-rw-r--r--backends/platform/psp/README.PSP169
-rw-r--r--backends/platform/psp/README.PSP.in132
-rw-r--r--backends/platform/psp/audio.cpp38
-rw-r--r--backends/platform/psp/audio.h8
-rw-r--r--backends/platform/psp/cursor.h2
-rw-r--r--backends/platform/psp/display_client.cpp185
-rw-r--r--backends/platform/psp/display_client.h23
-rw-r--r--backends/platform/psp/display_manager.cpp129
-rw-r--r--backends/platform/psp/display_manager.h55
-rw-r--r--backends/platform/psp/dummy.cpp59
-rw-r--r--backends/platform/psp/image_viewer.cpp327
-rw-r--r--backends/platform/psp/image_viewer.h105
-rw-r--r--backends/platform/psp/input.cpp623
-rw-r--r--backends/platform/psp/input.h169
-rw-r--r--backends/platform/psp/memory.cpp405
-rw-r--r--backends/platform/psp/memory.h122
-rw-r--r--backends/platform/psp/module.mk5
-rw-r--r--backends/platform/psp/mp3.cpp90
-rw-r--r--backends/platform/psp/mp3.h23
-rw-r--r--backends/platform/psp/osys_psp.cpp52
-rw-r--r--backends/platform/psp/osys_psp.h4
-rw-r--r--backends/platform/psp/png_loader.cpp210
-rw-r--r--backends/platform/psp/png_loader.h74
-rw-r--r--backends/platform/psp/powerman.cpp52
-rw-r--r--backends/platform/psp/psp.spec2
-rw-r--r--backends/platform/psp/psp_main.cpp6
-rw-r--r--backends/platform/psp/pspkeyboard.cpp208
-rw-r--r--backends/platform/psp/pspkeyboard.h11
-rw-r--r--backends/platform/psp/rtc.cpp30
-rw-r--r--backends/platform/psp/rtc.h4
-rw-r--r--backends/platform/psp/tests.cpp248
-rw-r--r--backends/platform/psp/tests.h6
-rw-r--r--backends/platform/psp/thread.cpp60
-rw-r--r--backends/platform/psp/thread.h6
35 files changed, 2397 insertions, 1254 deletions
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile
index e564200897..9f6b5c8921 100644
--- a/backends/platform/psp/Makefile
+++ b/backends/platform/psp/Makefile
@@ -126,7 +126,7 @@ endif
# PSP LIBS
PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \
-lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \
- -lpspkernel
+ -lpspkernel -lpspnet_inet
# Add in PSPSDK includes and libraries.
@@ -148,7 +148,10 @@ OBJS := powerman.o \
thread.o \
rtc.o \
mp3.o \
- tests.o
+ png_loader.o \
+ image_viewer.o \
+ tests.o \
+ dummy.o
BACKEND := psp
@@ -200,4 +203,4 @@ SCEkxploit: $(TARGET).elf $(PSP_EBOOT_SFO)
$(PACK_PBP) "%__SCE__$(TARGET)/$(PSP_EBOOT)" $(PSP_EBOOT_SFO) $(PSP_EBOOT_ICON) \
$(PSP_EBOOT_ICON1) $(PSP_EBOOT_PIC0) $(PSP_EBOOT_PIC1) \
$(PSP_EBOOT_SND0) NULL $(PSP_EBOOT_PSAR)
-
+
diff --git a/backends/platform/psp/README.PSP b/backends/platform/psp/README.PSP
index f4d5bae6d6..b83f1cab6d 100644
--- a/backends/platform/psp/README.PSP
+++ b/backends/platform/psp/README.PSP
@@ -1,81 +1,130 @@
-ScummVM-PSP 1.2.0svn README
+ScummVM-PSP 1.3.0svn README
==============================================================================
Installation
============
- - Copy the relevant game datafiles to your memory stick (location
- doesn't matter).
- - Install ScummVM like any other homebrew
- - Run ScummVM and use the launcher to add games and run them
-
+ - Copy the relevant game datafiles to your memory stick (location doesn't matter).
+ - Install ScummVM like any other homebrew.
+ - Run ScummVM and use the launcher to add games and run them.
+ - Press Start to return to the launcher and play another game.
Controls
========
-
-Left trigger - ESC
Right trigger - Modifier key (see below for uses)
+Left trigger - ESC (Usually skips cutscenes. Depends on game)
Analog - Mouse movement
-Right trigger + Analog - Fine control mouse
-Directions - Arrow keys
-Directions + Right Trigger - Diagonal arrow keys
-Triangle - Enter
-Cross - Mouse button 1
-Circle - Mouse button 2
-Square - '.' (skip dialogue in some games)
-Start - F5 (Main Menu)
-Right trigger + Start - Return-To-Launcher menu
-
-Virtual Keyboard
-================
-
-Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen.
-Start - Enter
-Right trigger - Switch to/between letter modes
-Left trigger - Switch to/between numbers and symbols
-D-Pad - Select square of characters
-Buttons/Triggers - Choose a specific character
-
+Right trigger + Analog - Fine mouse movement
+D-Pad - Arrow keys (useful mostly in SCI and AGI games)
+D-Pad + Right Trigger - Diagonal arrow keys (it's hard to input diagonals on some PSPs)
+Triangle - Enter (useful for some dialogs)
+Cross - Left Mouse Button (usually the main button)
+Circle - Right Mouse Button (secondary button in some games)
+Square - '.' (skip dialogue in some games e.g. Scumm)
+Right trigger + Square - Spacebar (useful in Gobli*ns and SCI games)
+Right trigger + Start - F5 (Main Menu in some games)
+Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen (with D-Pad).
+Right trigger + Select - Show Image Viewer (see below)
+Start - Global Menu. Allows you to 'Return To Launcher' to play another game
+
+Virtual Keyboard Mode
+=====================
+Start - Enter key. Also exits virtual keyboard mode
+Select - Exit the virtual keyboard mode
+Right trigger - Input letters: lowercase/uppercase (press to toggle)
+Left trigger - Input numbers/symbols (press to toggle)
+D-Pad - Select square of characters (up, down, left or right)
+Buttons/Triggers - Choose a specific character in the square. The four center characters are chosen
+ by the button in the corresponding position. The 2 top characters are chosen by the
+ triggers.
+Analog - Moves in a direction (left/right/up/down) (Useful to keep moving
+ while typing in AGI games among other things)
+
+
+Image Viewer
+============
+For your convenience, I've included a simple image viewer in the PSP port.
+You can view anything you want while playing a game.
+There are a few simple rules to follow:
+
+- Images must be of PNG format. If you have images in another format, many
+ graphics utilities will convert them for you.
+- Images must be named psp_image1.png, psp_image2.png etc. This is to make
+ sure there's no possible conflict between image files and game files.
+- Images must be placed in the game directories. When using the image viewer,
+ only the images of the particular game being played will be available for viewing.
+- Don't place any images in the ScummVM directory, or you won't be able to see
+ the images in the game directories.
+- There's no guarantee that you'll be able to view your image. This is because
+ big images take a lot of memory (more than the size of the image on disk). If there
+ isn't enough memory left to show the image, ScummVM will tell you so. Try to make the
+ image smaller by either shrinking it or reducing the colors to 256 color palette mode.
+
+Image Viewer Controls:
+=====================
+Left/Right - previous/next image (e.g. go from psp_image1.png to psp_image2.png)
+Up/down - zoom in/out
+Analog - move around the image
+Triggers, Start: - exit image viewer
+
+
+1st Person Game Mode (Can be ignored by most users)
+====================
+This is a special mode built for 1st person games like Lands of Lore. If you don't have these games you can
+safely ignore this mode. To enter or leave this mode, use the combo:
+
+Right Trigger + Left Trigger + Square
+
+Some buttons have been switched around to make these games more playable:
+Square - Is the modifier key instead of Right Trigger.
+Left/Right Trigger - Strafe left/right
+D-Pad Left/Right - Turn left/right
+Square + D-Pad - F1/F2/F3/F4
+Square + Select - Image Viewer
+Square + Start - Esc (shows game menu)
+
+
+
+
Notes
=====
+- Notice that you can switch between games! This is much faster than quitting
+ and having to start ScummVM all over again. Go to the global menu and choose 'Return To Launcher'.
+ (Some games may not have the Return To Launcher option available yet.)
-- Plugin files are NOT interchangeable between versions! You must copy ALL the
- plugin files that come with every version of scummvm. They sit in the /plugin
+- The PSP version of ScummVM uses the Media Engine to accelerate decoding of MP3 files. This means
+ that if you have the choice of compressing using Ogg files or MP3 files, choose MP3 -- the game
+ will generally run faster.
+
+- Plugin files are NOT interchangeable between ScummVM versions! You must copy ALL the
+ plugin files that come with every version of ScummVM. They sit in the /plugin
subdirectory. If you get a crash upon startup, try deleting all the existing
plugin files in the plugin directory and copying the new ones over again.
-- While it's possible to compress certain game resources to reduce their size,
- this can (and usually will) cause games (especially animation) to be choppy
- sometimes, as it ofcourse needs extra CPU power to decode these files.
- As such, it is recommended to play games in their original, uncompressed,
- form whenever possible.
-
- This README may be outdated, for more up-to-date instructions and notes see
the PSP Port Wiki: http://wiki.scummvm.org/index.php/PlayStation_Portable
Frequently Asked Questions
==========================
-Q: Pressing select doesn't make the virtual keyboard show up on screen!
-A: You need to make sure that the kbd.zip file is in the same directory as the scummvm executable.
-
Q: Scummvm crashes upon starting up!
A: See the first note above.
+Q: Pressing select doesn't make the virtual keyboard show up on screen!
+A: You need to make sure that the kbd.zip file is in the same directory as the ScummVM executable.
+
Q: What do I need to run the games?
-A: A 1.00 or 1.50 firmware PSP (or an EBOOT loader on firmware 2.00 or
- higher), and the necessary datafiles for the game you want to play and
- obviously this ScummVM port.
+A: A PSP that can run homebrew and the necessary datafiles for the game you want to play.
Q: Can I run game X with this?
A: You can find the list of supported games on the compatibility page
- on http://www.scummvm.org.
- Note that ScummVM is NOT a 'DOS (game) emulator', but written
- specifically for certain games/engines.
+ at http://www.scummvm.org
+ Note that ScummVM is NOT an emulator. The supported games engines have been painstakingly rewritten.
+ It's not easy to add support for a game you want that currently isn't supported.
Q: My Monkey Island 1 doesn't have any music, what gives?
A: If your version of Monkey Island came on a CD then it has the music
- as CD Audio tracks. You need to rip those to MP3/Ogg and copy them
- to the same directory as the game datafiles for music to work.
+ as CD Audio tracks. You need to rip those to MP3/Ogg (MP3 is preferred), naming them track1.mp3 track2.mp3
+ etc. and copy them to the same directory as the game datafiles for music to work.
Q: Game X crashes, or feature Y doesn't work. Can you fix this?
A: Possibly.
@@ -83,21 +132,23 @@ A: Possibly.
played them all start-to-finish on the PSP, so it's possible there
are bugs or issues that we're not aware of.
When you encounter such a bug, please use the "Bug Tracker" you find linked
- on the ScummVM website, and mention all relevant info (i.e. that you're
+ on the ScummVM website, and mention all relevant info i.e. that you're
using the PSP version, which ScummVM version it is, if the problem exists
- in a recent PC SVN version, a detailed description of the problem,
- and if at all possible a nearby savegame), this will make it much easier
+ in a recent PC version, a detailed description of the problem,
+ and if at all possible a nearby savegame. This will make it much easier
for us to reproduce (and hopefully fix) the problem.
Building the source code
========================
To build ScummVM for PSP you need:
+- ScummVM source code (svn co https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk)
+
- PSP toolchain (svn co svn://svn.pspdev.org/psp/trunk/psptoolchain)
- PSPSDK (svn co svn://svn.pspdev.org/psp/trunk/pspsdk)
- Note: This usually gets installed by the PSP toolchain,
- so you don't have to do it manually.
+ Note: This usually gets installed by the PSP toolchain,
+ so you don't have to do it manually.
- zlib (svn co svn://svn.pspdev.org/psp/trunk/zlib)
@@ -107,21 +158,15 @@ To build ScummVM for PSP you need:
- libTremor(*) (svn co svn://svn.pspdev.org/psp/trunk/libTremor)
-
-
(*) = optional
-When you've installed these libraries (read their README.PSP for instructions),
-type "make" in the backends/platform/psp directory to build a 1.00 firmware
-EBOOT.PBP, or "make kxploit" to build the 1.50/kxploit EBOOT.PBPs
-
-You can control most of the build process (engines and libraries used) from
-the Makefile.
-
+Once you've installed these libraries (read their README.PSP for instructions),
+create a subdirectory in your ScummVM folder called 'builds/psp'. Then, in this folder, type
+'../../configure --host=psp --enable-plugins --default-dynamic'. If everything is installed
+correctly, ScummVM will inform you as it finds the right components. Finally type 'make' to build.
Port Authors
============
-
Joost Peters (joostp@scummvm.org)
Paolo Costabel (paoloc@pacbell.net)
Thomas Mayer (tommybear@internode.on.net)
diff --git a/backends/platform/psp/README.PSP.in b/backends/platform/psp/README.PSP.in
index 2d53fd3b47..57058abd85 100644
--- a/backends/platform/psp/README.PSP.in
+++ b/backends/platform/psp/README.PSP.in
@@ -3,79 +3,95 @@ ScummVM-PSP @VERSION@ README
Installation
============
- - Copy the relevant game datafiles to your memory stick (location
- doesn't matter).
- - Install ScummVM like any other homebrew
- - Run ScummVM and use the launcher to add games and run them
-
+ - Copy the relevant game datafiles to your memory stick (location doesn't matter).
+ - Install ScummVM like any other homebrew.
+ - Run ScummVM and use the launcher to add games and run them.
Controls
========
-
-Left trigger - ESC
Right trigger - Modifier key (see below for uses)
+Left trigger - ESC (Usually skips cutscenes. Depends on game)
Analog - Mouse movement
-Right trigger + Analog - Fine control mouse
-Directions - Arrow keys
-Directions + Right Trigger - Diagonal arrow keys
-Triangle - Enter
-Cross - Mouse button 1
-Circle - Mouse button 2
-Square - '.' (skip dialogue in some games)
-Start - F5 (Main Menu)
-Right trigger + Start - Return-To-Launcher menu
-
-Virtual Keyboard
-================
-
-Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen.
-Start - Enter
-Right trigger - Switch to/between letter modes
-Left trigger - Switch to/between numbers and symbols
-D-Pad - Select square of characters
-Buttons/Triggers - Choose a specific character
+Right trigger + Analog - Fine mouse movement
+D-Pad - Arrow keys (useful mostly in SCI and AGI games)
+D-Pad + Right Trigger - Diagonal arrow keys (it's hard to input diagonals on some PSPs)
+Triangle - Enter (useful for some dialogs)
+Cross - Left Mouse Button (usually the main button)
+Circle - Right Mouse Button (secondary button in some games)
+Square - '.' (skip dialogue in some games e.g. Scumm)
+Right trigger + Square - Spacebar (useful in Gobli*ns and SCI games)
+Start - Global Menu. Allows you to 'Return To Launcher' to play another game
+Right trigger + Start - F5 (Main Menu in some games)
+Select - Show/Hide Virtual Keyboard. Hold down to move keyboard onscreen (with D-Pad).
+
+Virtual Keyboard Mode
+=====================
+Start - Enter key. Also exits virtual keyboard mode
+Select - Exit the virtual keyboard mode
+Right trigger - Input letters: lowercase/uppercase (press to toggle)
+Left trigger - Input numbers/symbols (press to toggle)
+D-Pad - Select square of characters (up, down, left or right)
+Buttons/Triggers - Choose a specific character in the square. The four center characters are chosen
+ by the button in the corresponding position. The 2 top characters are chosen by the
+ triggers.
+Analog - Moves in a direction (left/right/up/down) (Useful to keep moving
+ while typing in AGI games among other things)
+
+1st Person Game Mode (Can be ignored by most users)
+====================
+This is a special mode built for 1st person games like Lands of Lore. If you don't have these games you can
+safely ignore this mode. To enter or leave this mode, use the combo:
+
+Right Trigger + Left Trigger + Square
+
+Some buttons have been switched around to make these games more playable:
+Square - Is the modifier key instead of Right Trigger.
+Left/Right Trigger - Strafe left/right
+D-Pad Left/Right - Turn left/right
+Square + D-Pad - F1/F2/F3/F4
+Square + Start - Esc (shows game menu)
+
Notes
=====
+- Notice that you can switch between games! This is much faster than quitting
+ and having to start ScummVM all over again. Go to the global menu and choose 'Return To Launcher'.
+ (Some games may not have the Return To Launcher option available yet.)
+
+- The PSP version of ScummVM uses the Media Engine to accelerate decoding of MP3 files. This means
+ that if you have the choice of compressing using Ogg files or MP3 files, choose MP3 -- the game
+ will generally run faster.
-- Plugin files are NOT interchangeable between versions! You must copy ALL the
- plugin files that come with every version of scummvm. They sit in the /plugin
+- Plugin files are NOT interchangeable between ScummVM versions! You must copy ALL the
+ plugin files that come with every version of ScummVM. They sit in the /plugin
subdirectory. If you get a crash upon startup, try deleting all the existing
plugin files in the plugin directory and copying the new ones over again.
-- While it's possible to compress certain game resources to reduce their size,
- this can (and usually will) cause games (especially animation) to be choppy
- sometimes, as it ofcourse needs extra CPU power to decode these files.
- As such, it is recommended to play games in their original, uncompressed,
- form whenever possible.
-
- This README may be outdated, for more up-to-date instructions and notes see
the PSP Port Wiki: http://wiki.scummvm.org/index.php/PlayStation_Portable
Frequently Asked Questions
==========================
-Q: Pressing select doesn't make the virtual keyboard show up on screen!
-A: You need to make sure that the kbd.zip file is in the same directory as the scummvm executable.
-
Q: Scummvm crashes upon starting up!
A: See the first note above.
+Q: Pressing select doesn't make the virtual keyboard show up on screen!
+A: You need to make sure that the kbd.zip file is in the same directory as the ScummVM executable.
+
Q: What do I need to run the games?
-A: A 1.00 or 1.50 firmware PSP (or an EBOOT loader on firmware 2.00 or
- higher), and the necessary datafiles for the game you want to play and
- obviously this ScummVM port.
+A: A PSP that can run homebrew and the necessary datafiles for the game you want to play.
Q: Can I run game X with this?
A: You can find the list of supported games on the compatibility page
- on http://www.scummvm.org.
- Note that ScummVM is NOT a 'DOS (game) emulator', but written
- specifically for certain games/engines.
+ at http://www.scummvm.org
+ Note that ScummVM is NOT an emulator. The supported games engines have been painstakingly rewritten.
+ It's not easy to add support for a game you want that currently isn't supported.
Q: My Monkey Island 1 doesn't have any music, what gives?
A: If your version of Monkey Island came on a CD then it has the music
- as CD Audio tracks. You need to rip those to MP3/Ogg and copy them
- to the same directory as the game datafiles for music to work.
+ as CD Audio tracks. You need to rip those to MP3/Ogg (MP3 is preferred), naming them track1.mp3 track2.mp3
+ etc. and copy them to the same directory as the game datafiles for music to work.
Q: Game X crashes, or feature Y doesn't work. Can you fix this?
A: Possibly.
@@ -83,21 +99,23 @@ A: Possibly.
played them all start-to-finish on the PSP, so it's possible there
are bugs or issues that we're not aware of.
When you encounter such a bug, please use the "Bug Tracker" you find linked
- on the ScummVM website, and mention all relevant info (i.e. that you're
+ on the ScummVM website, and mention all relevant info i.e. that you're
using the PSP version, which ScummVM version it is, if the problem exists
- in a recent PC SVN version, a detailed description of the problem,
- and if at all possible a nearby savegame), this will make it much easier
+ in a recent PC version, a detailed description of the problem,
+ and if at all possible a nearby savegame. This will make it much easier
for us to reproduce (and hopefully fix) the problem.
Building the source code
========================
To build ScummVM for PSP you need:
+- ScummVM source code (svn co https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk)
+
- PSP toolchain (svn co svn://svn.pspdev.org/psp/trunk/psptoolchain)
- PSPSDK (svn co svn://svn.pspdev.org/psp/trunk/pspsdk)
- Note: This usually gets installed by the PSP toolchain,
- so you don't have to do it manually.
+ Note: This usually gets installed by the PSP toolchain,
+ so you don't have to do it manually.
- zlib (svn co svn://svn.pspdev.org/psp/trunk/zlib)
@@ -107,21 +125,15 @@ To build ScummVM for PSP you need:
- libTremor(*) (svn co svn://svn.pspdev.org/psp/trunk/libTremor)
-
-
(*) = optional
-When you've installed these libraries (read their README.PSP for instructions),
-type "make" in the backends/platform/psp directory to build a 1.00 firmware
-EBOOT.PBP, or "make kxploit" to build the 1.50/kxploit EBOOT.PBPs
-
-You can control most of the build process (engines and libraries used) from
-the Makefile.
-
+Once you've installed these libraries (read their README.PSP for instructions),
+create a subdirectory in your ScummVM folder called 'builds/psp'. Then, in this folder, type
+'../../configure --host=psp --enable-plugins --default-dynamic'. If everything is installed
+correctly, ScummVM will inform you as it finds the right components. Finally type 'make' to build.
Port Authors
============
-
Joost Peters (joostp@scummvm.org)
Paolo Costabel (paoloc@pacbell.net)
Thomas Mayer (tommybear@internode.on.net)
diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp
index 14691befee..b5a72dccd0 100644
--- a/backends/platform/psp/audio.cpp
+++ b/backends/platform/psp/audio.cpp
@@ -23,10 +23,10 @@
*
*/
-#include <pspthreadman.h>
+#include <pspthreadman.h>
#include <pspaudio.h>
-
-#include "common/scummsys.h"
+
+#include "common/scummsys.h"
#include "backends/platform/psp/audio.h"
//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
@@ -39,37 +39,37 @@ bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, call
if (_init) {
PSP_ERROR("audio device already initialized\n");
return true;
- }
+ }
- PSP_DEBUG_PRINT("freq[%d], numOfChannels[%d], numOfSamples[%d], callback[%p], userData[%x]\n",
+ PSP_DEBUG_PRINT("freq[%d], numOfChannels[%d], numOfSamples[%d], callback[%p], userData[%x]\n",
freq, numOfChannels, numOfSamples, callback, (uint32)userData);
-
+
numOfSamples = PSP_AUDIO_SAMPLE_ALIGN(numOfSamples);
uint32 bufLen = numOfSamples * numOfChannels * NUM_BUFFERS * sizeof(uint16);
-
+
PSP_DEBUG_PRINT("total buffer size[%d]\n", bufLen);
-
+
_buffers[0] = (byte *)memalign(64, bufLen);
if (!_buffers[0]) {
PSP_ERROR("failed to allocate memory for audio buffers\n");
return false;
}
memset(_buffers[0], 0, bufLen); // clean the buffer
-
+
// Fill in the rest of the buffer pointers
byte *pBuffer = _buffers[0];
for (int i = 1; i < NUM_BUFFERS; i++) {
pBuffer += numOfSamples * numOfChannels * sizeof(uint16);
_buffers[i] = pBuffer;
}
-
+
// Reserve a HW channel for our audio
_pspChannel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, numOfSamples, numOfChannels == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO);
if (_pspChannel < 0) {
PSP_ERROR("failed to reserve audio channel\n");
return false;
}
-
+
PSP_DEBUG_PRINT("reserved channel[%d] for audio\n", _pspChannel);
// Save our data
@@ -80,17 +80,17 @@ bool PspAudio::open(uint32 freq, uint32 numOfChannels, uint32 numOfSamples, call
_userData = userData;
_bufferToFill = 0;
_bufferToPlay = 0;
-
+
_init = true;
_paused = true; // start in paused mode
-
+
threadCreateAndStart("audioThread", PRIORITY_AUDIO_THREAD, STACK_AUDIO_THREAD); // start the consumer thread
-
+
return true;
}
// The real thread function
-void PspAudio::threadFunction() {
+void PspAudio::threadFunction() {
assert(_callback);
PSP_DEBUG_PRINT_FUNC("audio thread started\n");
@@ -108,12 +108,12 @@ void PspAudio::threadFunction() {
PSP_DEBUG_PRINT("filling buffer[%d]\n", _bufferToFill);
_callback(_userData, _buffers[_bufferToFill], _bufferSize); // ask mixer to fill in data
nextBuffer(_bufferToFill);
-
+
PSP_DEBUG_PRINT("playing buffer[%d].\n", _bufferToPlay);
playBuffer();
nextBuffer(_bufferToPlay);
} // while _init
-
+
// destroy everything
free(_buffers[0]);
sceAudioChRelease(_pspChannel);
@@ -136,7 +136,7 @@ inline bool PspAudio::playBuffer() {
ret = sceAudioOutputBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]);
else
ret = sceAudioOutputPannedBlocking(_pspChannel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, _buffers[_bufferToPlay]);
-
+
if (ret < 0) {
PSP_ERROR("failed to output audio. Error[%d]\n", ret);
return false;
@@ -146,5 +146,5 @@ inline bool PspAudio::playBuffer() {
void PspAudio::close() {
PSP_DEBUG_PRINT("close has been called ***************\n");
- _init = false;
+ _init = false;
}
diff --git a/backends/platform/psp/audio.h b/backends/platform/psp/audio.h
index 07f70cec7d..f5179028dc 100644
--- a/backends/platform/psp/audio.h
+++ b/backends/platform/psp/audio.h
@@ -35,9 +35,9 @@ public:
FREQUENCY = 44100 /* only frequency we allow */
};
typedef void (* callbackFunc)(void *userData, byte *samples, int len); // audio callback to call
- PspAudio() : _pspChannel(0),
- _numOfChannels(0), _numOfSamples(0), _callback(0),
- _bufferToPlay(0), _bufferToFill(0),
+ PspAudio() : _pspChannel(0),
+ _numOfChannels(0), _numOfSamples(0), _callback(0),
+ _bufferToPlay(0), _bufferToFill(0),
_init(false), _paused(true) {
for (int i=0; i<NUM_BUFFERS; i++)
_buffers[i] = 0;
@@ -51,7 +51,7 @@ public:
void pause() { _paused = true; }
void unpause() { _paused = false; }
virtual void threadFunction(); // actual audio thread
-
+
private:
int _pspChannel; // chosen hardware output channel
uint32 _numOfChannels; // 1 for mono; 2 for stereo
diff --git a/backends/platform/psp/cursor.h b/backends/platform/psp/cursor.h
index c3d4d76803..2ff0415c6c 100644
--- a/backends/platform/psp/cursor.h
+++ b/backends/platform/psp/cursor.h
@@ -26,6 +26,8 @@
#ifndef MOUSE_H
#define MOUSE_H
+#include "backends/platform/psp/default_display_client.h"
+
class Cursor : public DefaultDisplayClient {
private:
int _hotspotX, _hotspotY;
diff --git a/backends/platform/psp/display_client.cpp b/backends/platform/psp/display_client.cpp
index 6360772c96..4310b195dd 100644
--- a/backends/platform/psp/display_client.cpp
+++ b/backends/platform/psp/display_client.cpp
@@ -32,6 +32,7 @@
#include "backends/platform/psp/psppixelformat.h"
#include "backends/platform/psp/display_client.h"
#include "backends/platform/psp/display_manager.h"
+#define PSP_INCLUDE_SWAP
#include "backends/platform/psp/memory.h"
//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
@@ -341,14 +342,13 @@ void Buffer::copyFromRect(const byte *buf, uint32 pitch, int destX, int destY, u
if (pitch == realWidthInBytes && pitch == recWidthInBytes) {
//memcpy(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth));
if (_pixelFormat.swapRB)
- PspMemory::fastSwap(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth), _pixelFormat);
+ PspMemorySwap::fastSwap(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth), _pixelFormat);
else
PspMemory::fastCopy(dst, buf, _pixelFormat.pixelsToBytes(recHeight * recWidth));
} else {
do {
- //memcpy(dst, buf, recWidthInBytes);
if (_pixelFormat.swapRB)
- PspMemory::fastSwap(dst, buf, recWidthInBytes, _pixelFormat);
+ PspMemorySwap::fastSwap(dst, buf, recWidthInBytes, _pixelFormat);
else
PspMemory::fastCopy(dst, buf, recWidthInBytes);
buf += pitch;
@@ -370,7 +370,7 @@ void Buffer::copyToArray(byte *dst, int pitch) {
do {
//memcpy(dst, src, sourceWidthInBytes);
if (_pixelFormat.swapRB)
- PspMemory::fastSwap(dst, src, sourceWidthInBytes, _pixelFormat);
+ PspMemorySwap::fastSwap(dst, src, sourceWidthInBytes, _pixelFormat);
else
PspMemory::fastCopy(dst, src, sourceWidthInBytes);
src += realWidthInBytes;
@@ -378,45 +378,45 @@ void Buffer::copyToArray(byte *dst, int pitch) {
} while (--h);
}
-/* We can size the buffer either by texture size (multiple of 2^n) or source size. The GU can
- really handle both, but is supposed to get only 2^n size buffers */
void Buffer::setSize(uint32 width, uint32 height, HowToSize textureOrSource/*=kSizeByTextureSize*/) {
DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT("w[%u], h[%u], %s\n", width, height, textureOrSource ? "size by source" : "size by texture");
-
+
+ // We can size the buffer either by texture size (multiple of 2^n) or source size.
+ // At higher sizes, increasing the texture size to 2^n is a waste of space. At these sizes kSizeBySourceSize should be used.
+
_sourceSize.width = width;
_sourceSize.height = height;
- _textureSize.width = scaleUpToPowerOfTwo(width);
+ _textureSize.width = scaleUpToPowerOfTwo(width); // can only scale up to 512
_textureSize.height = scaleUpToPowerOfTwo(height);
-
+
if (textureOrSource == kSizeByTextureSize) {
_width = _textureSize.width;
_height = _textureSize.height;
- } else { /* kSizeBySourceSize */
- _width = _sourceSize.width;
+ } else { // sizeBySourceSize
+ _width = _sourceSize.width;
_height = _sourceSize.height;
+
+ // adjust allocated width to be divisible by 32.
+ // The GU can only handle multiples of 16 bytes. A 4 bit image x 32 will give us 16 bytes
+ // We don't necessarily know the depth of the pixels here. So just make it divisible by 32.
+ uint32 checkDiv = _width & 31;
+ if (checkDiv)
+ _width += 32 - checkDiv;
}
+
+ PSP_DEBUG_PRINT("width[%u], height[%u], texW[%u], texH[%u], sourceW[%d], sourceH[%d] %s\n", _width, _height, _textureSize.width, _textureSize.height, _sourceSize.width, _sourceSize.height, textureOrSource ? "size by source" : "size by texture");
}
-/* Scale a dimension (width/height) up to power of 2 for the texture */
+// Scale a dimension (width/height) up to power of 2 for the texture
+// Will only go up to 512 since that's the maximum PSP texture size
uint32 Buffer::scaleUpToPowerOfTwo(uint32 size) {
- uint32 textureDimension = 0;
- if (size <= 16)
- textureDimension = 16;
- else if (size <= 32)
- textureDimension = 32;
- else if (size <= 64)
- textureDimension = 64;
- else if (size <= 128)
- textureDimension = 128;
- else if (size <= 256)
- textureDimension = 256;
- else
- textureDimension = 512;
+ uint32 textureDimension = 16;
+ while (size > textureDimension && textureDimension < 512)
+ textureDimension <<= 1;
- PSP_DEBUG_PRINT("power of 2 = %u\n", textureDimension);
+ PSP_DEBUG_PRINT("size[%u]. power of 2[%u]\n", size, textureDimension);
return textureDimension;
}
@@ -539,51 +539,41 @@ void GuRenderer::render() {
DEBUG_ENTER_FUNC();
PSP_DEBUG_PRINT("Buffer[%p] Palette[%p]\n", _buffer->getPixels(), _palette->getRawValues());
- setMaxTextureOffsetByIndex(0, 0);
-
guProgramDrawBehavior();
if (_buffer->hasPalette())
guLoadPalette();
guProgramTextureFormat();
- guLoadTexture();
-
- Vertex *vertices = guGetVertices();
- fillVertices(vertices);
- guDrawVertices(vertices);
-
- if (_buffer->getSourceWidth() > 512) {
- setMaxTextureOffsetByIndex(1, 0);
-
- guLoadTexture();
-
- vertices = guGetVertices();
- fillVertices(vertices);
-
- guDrawVertices(vertices);
+ // Loop over patches of 512x512 pixel textures and draw them
+ for (uint32 j = 0; j < _buffer->getSourceHeight(); j += 512) {
+ _textureLoadOffset.y = j;
+
+ for (uint32 i = 0; i < _buffer->getSourceWidth(); i += 512) {
+ _textureLoadOffset.x = i;
+
+ guLoadTexture();
+ Vertex *vertices = guGetVertices();
+ fillVertices(vertices);
+
+ guDrawVertices(vertices);
+ }
}
}
-inline void GuRenderer::setMaxTextureOffsetByIndex(uint32 x, uint32 y) {
- DEBUG_ENTER_FUNC();
- const uint32 maxTextureSizeShift = 9; /* corresponds to 512 = max texture size*/
-
- _maxTextureOffset.x = x << maxTextureSizeShift; /* x times 512 */
- _maxTextureOffset.y = y << maxTextureSizeShift; /* y times 512 */
-}
-
inline void GuRenderer::guProgramDrawBehavior() {
DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n", _blending ? "on" : "off", _colorTest ? "on" : "off", _alphaReverse ? "on" : "off", _keyColor);
+ PSP_DEBUG_PRINT("blending[%s] colorTest[%s] reverseAlpha[%s] keyColor[%u]\n",
+ _blending ? "on" : "off", _colorTest ? "on" : "off",
+ _alphaReverse ? "on" : "off", _keyColor);
if (_blending) {
sceGuEnable(GU_BLEND);
- if (_alphaReverse) // Reverse the alpha value (0 is 1)
+ if (_alphaReverse) // Reverse the alpha value (ie. 0 is 1) easier to do in some cases
sceGuBlendFunc(GU_ADD, GU_ONE_MINUS_SRC_ALPHA, GU_SRC_ALPHA, 0, 0);
- else // Normal alpha values
+ else // Normal alpha values
sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
} else
@@ -591,7 +581,9 @@ inline void GuRenderer::guProgramDrawBehavior() {
if (_colorTest) {
sceGuEnable(GU_COLOR_TEST);
- sceGuColorFunc(GU_NOTEQUAL, _keyColor, 0x00ffffff);
+ sceGuColorFunc(GU_NOTEQUAL, // show only colors not equal to this color
+ _keyColor,
+ 0x00ffffff); // match everything but alpha
} else
sceGuDisable(GU_COLOR_TEST);
}
@@ -612,7 +604,8 @@ inline void GuRenderer::guLoadPalette() {
PSP_DEBUG_PRINT("bpp[%d], pixelformat[%d], mask[%x]\n", _buffer->getBitsPerPixel(), _palette->getPixelFormat(), mask);
sceGuClutMode(convertToGuPixelFormat(_palette->getPixelFormat()), 0, mask, 0);
- sceGuClutLoad(_palette->getNumOfEntries() >> 3, _palette->getRawValues());
+ sceGuClutLoad(_palette->getNumOfEntries() >> 3, // it's in batches of 8 for some reason
+ _palette->getRawValues());
}
inline void GuRenderer::guProgramTextureFormat() {
@@ -658,7 +651,17 @@ inline uint32 GuRenderer::convertToGuPixelFormat(PSPPixelFormat::Type format) {
inline void GuRenderer::guLoadTexture() {
DEBUG_ENTER_FUNC();
- sceGuTexImage(0, _buffer->getTextureWidth(), _buffer->getTextureHeight(), _buffer->getWidth(), _buffer->getPixels() + _buffer->_pixelFormat.pixelsToBytes(_maxTextureOffset.x));
+ byte *startPoint = _buffer->getPixels();
+ if (_textureLoadOffset.x)
+ startPoint += _buffer->_pixelFormat.pixelsToBytes(_textureLoadOffset.x);
+ if (_textureLoadOffset.y)
+ startPoint += _buffer->getWidthInBytes() * _textureLoadOffset.y;
+
+ sceGuTexImage(0,
+ _buffer->getTextureWidth(), // texture width (must be power of 2)
+ _buffer->getTextureHeight(), // texture height (must be power of 2)
+ _buffer->getWidth(), // width of a line of the image (to get to the next line)
+ startPoint); // where to start reading
}
inline Vertex *GuRenderer::guGetVertices() {
@@ -676,40 +679,40 @@ void GuRenderer::fillVertices(Vertex *vertices) {
uint32 outputWidth = _displayManager->getOutputWidth();
uint32 outputHeight = _displayManager->getOutputHeight();
- float textureStartX, textureStartY, textureEndX, textureEndY;
-
// Texture adjustments for eliminating half-pixel artifacts from scaling
// Not necessary if we don't scale
- float textureAdjustment = 0.0f;
+ float textureFix = 0.0f;
if (_useGlobalScaler &&
- (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleX() != 1.0f))
- textureAdjustment = 0.5f;
-
- textureStartX = textureAdjustment + _offsetInBuffer.x; //debug
- textureStartY = textureAdjustment + _offsetInBuffer.y;
- // We subtract maxTextureOffset because our shifted texture starts at 512 and will go to 640
- textureEndX = _offsetInBuffer.x + _drawSize.width - textureAdjustment - _maxTextureOffset.x;
- textureEndY = _offsetInBuffer.y + _drawSize.height - textureAdjustment;
-
+ (_displayManager->getScaleX() != 1.0f || _displayManager->getScaleY() != 1.0f))
+ textureFix = 0.5f;
+
+ // These coordinates describe an area within the texture. ie. we already loaded a square of texture,
+ // now the coordinates within it are 0 to the edge of the area of the texture we want to draw
+ float textureStartX = textureFix + _offsetInBuffer.x;
+ float textureStartY = textureFix + _offsetInBuffer.y;
+ // even when we draw one of several textures, we use the whole drawsize of the image. The GU
+ // will draw what it can with the texture it has and scale it properly for us.
+ float textureEndX = -textureFix + _offsetInBuffer.x + _drawSize.width - _textureLoadOffset.x;
+ float textureEndY = -textureFix + _offsetInBuffer.y + _drawSize.height - _textureLoadOffset.y;
// For scaling to the final image size, calculate the gaps on both sides
uint32 gapX = _useGlobalScaler ? (PSP_SCREEN_WIDTH - outputWidth) >> 1 : 0;
uint32 gapY = _useGlobalScaler ? (PSP_SCREEN_HEIGHT - outputHeight) >> 1 : 0;
// Save scaled offset on screen
- float scaledOffsetOnScreenX = scaleSourceToOutputX(_offsetOnScreen.x);
- float scaledOffsetOnScreenY = scaleSourceToOutputY(_offsetOnScreen.y);
-
- float imageStartX, imageStartY, imageEndX, imageEndY;
+ float scaledOffsetOnScreenX = scaleSourceToOutput(true, _offsetOnScreen.x);
+ float scaledOffsetOnScreenY = scaleSourceToOutput(false, _offsetOnScreen.y);
- imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutputX(_maxTextureOffset.x));
- imageStartY = gapY + scaledOffsetOnScreenY;
+ float imageStartX = gapX + scaledOffsetOnScreenX + (scaleSourceToOutput(true, stretch(true, _textureLoadOffset.x)));
+ float imageStartY = gapY + scaledOffsetOnScreenY + (scaleSourceToOutput(false, stretch(false, _textureLoadOffset.y)));
+ float imageEndX, imageEndY;
+
if (_fullScreen) { // shortcut
- imageEndX = PSP_SCREEN_WIDTH - gapX + scaledOffsetOnScreenX;
+ imageEndX = PSP_SCREEN_WIDTH - gapX + scaledOffsetOnScreenX;
imageEndY = PSP_SCREEN_HEIGHT - gapY + scaledOffsetOnScreenY; // needed for screen shake
} else { /* !fullScreen */
- imageEndX = imageStartX + scaleSourceToOutputX(_drawSize.width);
- imageEndY = imageStartY + scaleSourceToOutputY(_drawSize.height);
+ imageEndX = gapX + scaledOffsetOnScreenX + scaleSourceToOutput(true, stretch(true, _drawSize.width));
+ imageEndY = gapY + scaledOffsetOnScreenY + scaleSourceToOutput(false, stretch(false, _drawSize.height));
}
vertices[0].u = textureStartX;
@@ -728,8 +731,8 @@ void GuRenderer::fillVertices(Vertex *vertices) {
PSP_DEBUG_PRINT("ImageStart: X[%f] Y[%f] ImageEnd: X[%.1f] Y[%.1f]\n", imageStartX, imageStartY, imageEndX, imageEndY);
}
-/* Scale the input X offset to appear in proper position on the screen */
-inline float GuRenderer::scaleSourceToOutputX(float offset) {
+/* Scale the input X/Y offset to appear in proper position on the screen */
+inline float GuRenderer::scaleSourceToOutput(bool x, float offset) {
float result;
if (!_useGlobalScaler)
@@ -737,28 +740,22 @@ inline float GuRenderer::scaleSourceToOutputX(float offset) {
else if (!offset)
result = 0.0f;
else
- result = offset * _displayManager->getScaleX();
+ result = x ? offset * _displayManager->getScaleX() : offset * _displayManager->getScaleY();
return result;
}
-/* Scale the input Y offset to appear in proper position on the screen */
-inline float GuRenderer::scaleSourceToOutputY(float offset) {
- float result;
-
- if (!_useGlobalScaler)
- result = offset;
- else if (!offset)
- result = 0.0f;
- else
- result = offset * _displayManager->getScaleY();
-
- return result;
+/* Scale the input X/Y offset to appear in proper position on the screen */
+inline float GuRenderer::stretch(bool x, float size) {
+ if (!_stretch)
+ return size;
+ return (x ? size * _stretchX : size * _stretchY);
}
inline void GuRenderer::guDrawVertices(Vertex *vertices) {
DEBUG_ENTER_FUNC();
+ // This function shouldn't need changing. The '32' here refers to floating point vertices.
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_TRANSFORM_2D, 2, 0, vertices);
}
diff --git a/backends/platform/psp/display_client.h b/backends/platform/psp/display_client.h
index d05b0b046c..005fc76c7c 100644
--- a/backends/platform/psp/display_client.h
+++ b/backends/platform/psp/display_client.h
@@ -30,6 +30,7 @@
#include "graphics/surface.h"
#include "common/system.h"
#include "backends/platform/psp/memory.h"
+#include "backends/platform/psp/psppixelformat.h"
#define MAX_TEXTURE_SIZE 512
@@ -173,8 +174,13 @@ protected:
class GuRenderer {
public:
// Constructors
- GuRenderer() : _useGlobalScaler(false), _buffer(0), _palette(0), _blending(false), _alphaReverse(false), _colorTest(false), _keyColor(0), _fullScreen(false) {}
- GuRenderer(Buffer *buffer, Palette *palette) : _useGlobalScaler(false), _buffer(buffer), _palette(palette), _blending(false), _alphaReverse(false), _colorTest(false), _keyColor(0), _fullScreen(false) {}
+ GuRenderer() : _useGlobalScaler(false), _buffer(0), _palette(0),
+ _blending(false), _alphaReverse(false), _colorTest(false),
+ _keyColor(0), _fullScreen(false), _stretch(false), _stretchX(1.0f), _stretchY(1.0f) {}
+ GuRenderer(Buffer *buffer, Palette *palette) :
+ _useGlobalScaler(false), _buffer(buffer), _palette(palette),
+ _blending(false), _alphaReverse(false), _colorTest(false),
+ _keyColor(0), _fullScreen(false), _stretch(false), _stretchX(1.0f), _stretchY(1.0f) {}
static void setDisplayManager(DisplayManager *dm) { _displayManager = dm; } // Called by the Display Manager
// Setters
@@ -189,8 +195,7 @@ public:
}
void setBuffer(Buffer *buffer) { _buffer = buffer; }
void setPalette(Palette *palette) { _palette = palette; }
- void setMaxTextureOffsetByIndex(uint32 x, uint32 y); // For drawing multiple textures
- void setOffsetOnScreen(uint32 x, uint32 y) { _offsetOnScreen.x = x; _offsetOnScreen.y = y; }
+ void setOffsetOnScreen(int x, int y) { _offsetOnScreen.x = x; _offsetOnScreen.y = y; }
void setOffsetInBuffer(uint32 x, uint32 y) { _offsetInBuffer.x = x; _offsetInBuffer.y = y; }
void setColorTest(bool value) { _colorTest = value; }
void setKeyColor(uint32 value) { _keyColor = _buffer->_pixelFormat.convertTo32BitColor(value); }
@@ -198,6 +203,8 @@ public:
void setAlphaReverse(bool value) { _alphaReverse = value; }
void setFullScreen(bool value) { _fullScreen = value; } // Shortcut for rendering
void setUseGlobalScaler(bool value) { _useGlobalScaler = value; } // Scale to screen
+ void setStretch(bool active) { _stretch = active; }
+ void setStretchXY(float x, float y) { _stretchX = x; _stretchY = y; }
static void cacheInvalidate(void *pointer, uint32 size);
@@ -215,11 +222,11 @@ protected:
void guDrawVertices(Vertex *vertices);
uint32 convertToGuPixelFormat(PSPPixelFormat::Type format);
- float scaleSourceToOutputX(float offset);
- float scaleSourceToOutputY(float offset);
+ float scaleSourceToOutput(bool x, float offset);
+ float stretch(bool x, float size);
friend class MasterGuRenderer;
- Point _maxTextureOffset; ///> For rendering textures > 512 pixels
+ Point _textureLoadOffset; ///> For rendering textures > 512 pixels
Point _offsetOnScreen; ///> Where on screen to draw
Point _offsetInBuffer; ///> Where in the texture to draw
bool _useGlobalScaler; ///> Scale to the output size on screen
@@ -232,6 +239,8 @@ protected:
bool _colorTest;
uint32 _keyColor; ///> Color to test against for color test. in 32 bits.
bool _fullScreen; ///> Speeds up for fullscreen rendering
+ bool _stretch; ///> Whether zooming is activated
+ float _stretchX, _stretchY;
};
#endif /* PSP_SCREEN_H */
diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp
index e65d6f4fd0..7454211da6 100644
--- a/backends/platform/psp/display_manager.cpp
+++ b/backends/platform/psp/display_manager.cpp
@@ -34,6 +34,7 @@
#include "backends/platform/psp/default_display_client.h"
#include "backends/platform/psp/cursor.h"
#include "backends/platform/psp/pspkeyboard.h"
+#include "backends/platform/psp/image_viewer.h"
#define USE_DISPLAY_CALLBACK // to use callback for finishing the render
#include "backends/platform/psp/display_manager.h"
@@ -59,28 +60,93 @@ const OSystem::GraphicsMode DisplayManager::_supportedModes[] = {
{0, 0, 0}
};
+
+// Class VramAllocator -----------------------------------
+
+DECLARE_SINGLETON(VramAllocator)
+
+//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
+//#define __PSP_DEBUG_PRINT__
+
+#include "backends/platform/psp/trace.h"
+
+
+void *VramAllocator::allocate(int32 size, bool smallAllocation /* = false */) {
+ DEBUG_ENTER_FUNC();
+ assert(size > 0);
+
+ byte *lastAddress = smallAllocation ? (byte *)VRAM_SMALL_ADDRESS : (byte *)VRAM_START_ADDRESS;
+ Common::List<Allocation>::iterator i;
+
+ // Find a block that fits, starting from the beginning
+ for (i = _allocList.begin(); i != _allocList.end(); ++i) {
+ byte *currAddress = (*i).address;
+
+ if (currAddress - lastAddress >= size) // We found a match
+ break;
+
+ if ((*i).getEnd() > lastAddress)
+ lastAddress = (byte *)(*i).getEnd();
+ }
+
+ if (lastAddress + size > (byte *)VRAM_END_ADDRESS) {
+ PSP_DEBUG_PRINT("No space for allocation of %d bytes. %d bytes already allocated.\n",
+ size, _bytesAllocated);
+ return NULL;
+ }
+
+ _allocList.insert(i, Allocation(lastAddress, size));
+ _bytesAllocated += size;
+
+ PSP_DEBUG_PRINT("Allocated in VRAM, size %u at %p.\n", size, lastAddress);
+ PSP_DEBUG_PRINT("Total allocated %u, remaining %u.\n", _bytesAllocated, (2 * 1024 * 1024) - _bytesAllocated);
+
+ return lastAddress;
+}
+
+// Deallocate a block from VRAM
+void VramAllocator::deallocate(void *address) {
+ DEBUG_ENTER_FUNC();
+ address = (byte *)CACHED(address); // Make sure all addresses are the same
+
+ Common::List<Allocation>::iterator i;
+
+ // Find the Allocator to deallocate
+ for (i = _allocList.begin(); i != _allocList.end(); ++i) {
+ if ((*i).address == address) {
+ _bytesAllocated -= (*i).size;
+ _allocList.erase(i);
+ PSP_DEBUG_PRINT("Deallocated address[%p], size[%u]\n", (*i).address, (*i).size);
+ return;
+ }
+ }
+
+ PSP_DEBUG_PRINT("Address[%p] not allocated.\n", address);
+}
+
+
// Class MasterGuRenderer ----------------------------------------------
void MasterGuRenderer::setupCallbackThread() {
DEBUG_ENTER_FUNC();
-
+
// start the thread that updates the display
- threadCreateAndStart("DisplayCbThread", PRIORITY_DISPLAY_THREAD, STACK_DISPLAY_THREAD);
+ threadCreateAndStart("DisplayCbThread", PRIORITY_DISPLAY_THREAD, STACK_DISPLAY_THREAD);
}
// this function gets called by PspThread when starting the new thread
void MasterGuRenderer::threadFunction() {
DEBUG_ENTER_FUNC();
-
+
// Create the callback. It should always get the pointer to MasterGuRenderer
_callbackId = sceKernelCreateCallback("Display Callback", guCallback, this);
if (_callbackId < 0) {
- PSP_ERROR("failed to create display callback\n");
+ PSP_ERROR("failed to create display callback\n");
}
-
+
PSP_DEBUG_PRINT("created callback. Going to sleep\n");
- sceKernelSleepThreadCB(); // sleep until we get a callback
+ sceKernelSleepThreadCB(); // sleep until we get a callback
}
// This callback is called when the render is finished. It swaps the buffers
@@ -88,12 +154,12 @@ int MasterGuRenderer::guCallback(int, int, void *__this) {
MasterGuRenderer *_this = (MasterGuRenderer *)__this;
- sceGuSync(0, 0); // make sure we wait for GU to finish
+ sceGuSync(0, 0); // make sure we wait for GU to finish
sceDisplayWaitVblankStartCB(); // wait for v-blank without eating main thread cycles
sceGuSwapBuffers(); // swap the back and front buffers
_this->_renderFinished = true; // Only this thread can set the variable to true
-
+
return 0;
}
@@ -149,7 +215,7 @@ inline void MasterGuRenderer::guPreRender() {
DEBUG_ENTER_FUNC();
_renderFinished = false; // set to synchronize with callback thread
-
+
#ifdef ENABLE_RENDER_MEASURE
_lastRenderTime = g_system->getMillis();
#endif /* ENABLE_RENDER_MEASURE */
@@ -178,7 +244,7 @@ inline void MasterGuRenderer::guPostRender() {
else
sceKernelNotifyCallback(_callbackId, 0); // notify the callback. Nothing extra to pass
#else
- sceGuSync(0, 0);
+ sceGuSync(0, 0);
#ifdef ENABLE_RENDER_MEASURE
uint32 now = g_system->getMillis();
@@ -188,7 +254,7 @@ inline void MasterGuRenderer::guPostRender() {
sceDisplayWaitVblankStart();
sceGuSwapBuffers();
_renderFinished = true;
-#endif /* !USE_DISPLAY_CALLBACK */
+#endif /* !USE_DISPLAY_CALLBACK */
}
void MasterGuRenderer::guShutDown() {
@@ -216,7 +282,7 @@ void DisplayManager::init() {
#ifdef USE_DISPLAY_CALLBACK
_masterGuRenderer.setupCallbackThread();
#endif
-
+
}
void DisplayManager::setSizeAndPixelFormat(uint width, uint height, const Graphics::PixelFormat *format) {
@@ -286,10 +352,10 @@ void DisplayManager::calculateScaleParams() {
break;
case KEEP_ASPECT_RATIO: { // maximize the height while keeping aspect ratio
float aspectRatio = (float)_displayParams.screenSource.width / (float)_displayParams.screenSource.height;
-
+
_displayParams.screenOutput.height = PSP_SCREEN_HEIGHT; // always full height
_displayParams.screenOutput.width = (uint32)(PSP_SCREEN_HEIGHT * aspectRatio);
-
+
if (_displayParams.screenOutput.width > PSP_SCREEN_WIDTH) // we can't have wider than the screen
_displayParams.screenOutput.width = PSP_SCREEN_WIDTH;
}
@@ -301,7 +367,7 @@ void DisplayManager::calculateScaleParams() {
default:
PSP_ERROR("Unsupported graphics mode[%d].\n", _graphicsMode);
}
-
+
// calculate scale factors for X and Y
_displayParams.scaleX = ((float)_displayParams.screenOutput.width) / _displayParams.screenSource.width;
_displayParams.scaleY = ((float)_displayParams.screenOutput.height) / _displayParams.screenSource.height;
@@ -316,51 +382,54 @@ bool DisplayManager::renderAll() {
if (!_masterGuRenderer.isRenderFinished()) {
PSP_DEBUG_PRINT("Callback render not finished.\n");
return false; // didn't render
- }
+ }
#endif /* USE_DISPLAY_CALLBACK */
-
+
// This is cheaper than checking time, so we do it first
+ // Any one of these being dirty causes everything to draw
if (!_screen->isDirty() &&
- (!_overlay->isDirty()) &&
- (!_cursor->isDirty()) &&
- (!_keyboard->isDirty())) {
+ !_overlay->isDirty() &&
+ !_cursor->isDirty() &&
+ !_keyboard->isDirty() &&
+ !_imageViewer->isDirty()) {
PSP_DEBUG_PRINT("Nothing dirty\n");
return true; // nothing to render
}
- if (!isTimeToUpdate())
+ if (!isTimeToUpdate())
return false; // didn't render
- PSP_DEBUG_PRINT("screen[%s], overlay[%s], cursor[%s], keyboard[%s]\n",
+ PSP_DEBUG_PRINT("dirty: screen[%s], overlay[%s], cursor[%s], keyboard[%s], imageViewer[%s]\n",
_screen->isDirty() ? "true" : "false",
_overlay->isDirty() ? "true" : "false",
_cursor->isDirty() ? "true" : "false",
- _keyboard->isDirty() ? "true" : "false"
+ _keyboard->isDirty() ? "true" : "false",
+ _imageViewer->isDirty() ? "true" : "false",
);
_masterGuRenderer.guPreRender(); // Set up rendering
_screen->render();
-
_screen->setClean(); // clean out dirty bit
+
+ if (_imageViewer->isVisible())
+ _imageViewer->render();
+ _imageViewer->setClean();
if (_overlay->isVisible())
- _overlay->render();
-
+ _overlay->render();
_overlay->setClean();
if (_cursor->isVisible())
_cursor->render();
-
_cursor->setClean();
if (_keyboard->isVisible())
_keyboard->render();
-
_keyboard->setClean();
-
- _masterGuRenderer.guPostRender();
+ _masterGuRenderer.guPostRender();
+
return true; // rendered successfully
}
diff --git a/backends/platform/psp/display_manager.h b/backends/platform/psp/display_manager.h
index 626415696a..5c7d4c799a 100644
--- a/backends/platform/psp/display_manager.h
+++ b/backends/platform/psp/display_manager.h
@@ -27,6 +27,48 @@
#define PSP_DISPLAY_MAN_H
#include "backends/platform/psp/thread.h"
+#include "common/list.h"
+
+#define UNCACHED(x) ((byte *)(((uint32)(x)) | 0x40000000)) /* make an uncached access */
+#define CACHED(x) ((byte *)(((uint32)(x)) & 0xBFFFFFFF)) /* make an uncached access into a cached one */
+
+/**
+ * Class that allocates memory in the VRAM
+ */
+class VramAllocator : public Common::Singleton<VramAllocator> {
+public:
+ VramAllocator() : _bytesAllocated(0) {}
+ void *allocate(int32 size, bool smallAllocation = false); // smallAllocation e.g. palettes
+ void deallocate(void *pointer);
+
+ static inline bool isAddressInVram(void *address) {
+ if ((uint32)(CACHED(address)) >= VRAM_START_ADDRESS && (uint32)(CACHED(address)) < VRAM_END_ADDRESS)
+ return true;
+ return false;
+ }
+
+
+private:
+ /**
+ * Used to allocate in VRAM
+ */
+ struct Allocation {
+ byte *address;
+ uint32 size;
+ void *getEnd() { return address + size; }
+ Allocation(void *Address, uint32 Size) : address((byte *)Address), size(Size) {}
+ Allocation() : address(0), size(0) {}
+ };
+
+ enum {
+ VRAM_START_ADDRESS = 0x04000000,
+ VRAM_END_ADDRESS = 0x04200000,
+ VRAM_SMALL_ADDRESS = VRAM_END_ADDRESS - (4 * 1024) // 4K in the end for small allocations
+ };
+ Common::List <Allocation> _allocList; // List of allocations
+ uint32 _bytesAllocated;
+};
+
/**
* Class used only by DisplayManager to start/stop GU rendering
@@ -39,7 +81,7 @@ public:
void guPostRender();
void guShutDown();
bool isRenderFinished() { return _renderFinished; }
- void setupCallbackThread();
+ void setupCallbackThread();
private:
virtual void threadFunction(); // for the display callback thread
static uint32 _displayList[];
@@ -47,13 +89,14 @@ private:
void guProgramDisplayBufferSizes();
static int guCallback(int, int, void *__this); // for the display callback
bool _renderFinished; // for sync with render callback
- int _callbackId; // to keep track of render callback
+ int _callbackId; // to keep track of render callback
};
class Screen;
class Overlay;
class Cursor;
class PSPKeyboard;
+class ImageViewer;
/**
* Class that manages all display clients
@@ -65,7 +108,8 @@ public:
KEEP_ASPECT_RATIO,
STRETCHED_FULL_SCREEN
};
- DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0), _lastUpdateTime(0), _graphicsMode(0) {}
+ DisplayManager() : _screen(0), _cursor(0), _overlay(0), _keyboard(0),
+ _imageViewer(0), _lastUpdateTime(0), _graphicsMode(0) {}
~DisplayManager();
void init();
@@ -76,11 +120,13 @@ public:
uint32 getDefaultGraphicsMode() const { return STRETCHED_FULL_SCREEN; }
const OSystem::GraphicsMode* getSupportedGraphicsModes() const { return _supportedModes; }
- // Setters
+ // Setters for pointers
void setScreen(Screen *screen) { _screen = screen; }
void setCursor(Cursor *cursor) { _cursor = cursor; }
void setOverlay(Overlay *overlay) { _overlay = overlay; }
void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; }
+ void setImageViewer(ImageViewer *imageViewer) { _imageViewer = imageViewer; }
+
void setSizeAndPixelFormat(uint width, uint height, const Graphics::PixelFormat *format);
// Getters
@@ -106,6 +152,7 @@ private:
Cursor *_cursor;
Overlay *_overlay;
PSPKeyboard *_keyboard;
+ ImageViewer *_imageViewer;
MasterGuRenderer _masterGuRenderer;
uint32 _lastUpdateTime; // For limiting FPS
diff --git a/backends/platform/psp/dummy.cpp b/backends/platform/psp/dummy.cpp
new file mode 100644
index 0000000000..4236734d4b
--- /dev/null
+++ b/backends/platform/psp/dummy.cpp
@@ -0,0 +1,59 @@
+/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
+ * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ *
+ */
+
+ //#include "common/scummsys.h"
+ #include <time.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <png.h>
+ #include <sys/socket.h>
+
+//void userWriteFn(png_structp png_ptr, png_bytep data, png_size_t length) {
+//}
+
+//void userFlushFn(png_structp png_ptr) {
+//}
+
+ // Dummy functions are pulled in so that we don't need to build the plugins with certain libs
+
+ int dummyFunc() {
+
+ // For Broken Sword 2.5
+ volatile int i;
+ i = clock();
+ rename("dummyA", "dummyB");
+
+ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ png_set_write_fn(png_ptr, NULL, NULL, NULL);
+ png_infop info_ptr;
+ png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ // For lua's usage of libc: very heavy usage so it pulls in sockets?
+ setsockopt(0, 0, 0, NULL, 0);
+ getsockopt(0, 0, 0, NULL, NULL);
+
+ return i;
+} \ No newline at end of file
diff --git a/backends/platform/psp/image_viewer.cpp b/backends/platform/psp/image_viewer.cpp
new file mode 100644
index 0000000000..26b7f31c97
--- /dev/null
+++ b/backends/platform/psp/image_viewer.cpp
@@ -0,0 +1,327 @@
+/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
+ * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ *
+ */
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/archive.h"
+#include "common/events.h"
+#include "common/ptr.h"
+#include "gui/message.h"
+#include "engines/engine.h"
+#include "backends/platform/psp/input.h"
+#include "backends/platform/psp/display_manager.h"
+#include "backends/platform/psp/display_client.h"
+#include "backends/platform/psp/image_viewer.h"
+#include "backends/platform/psp/png_loader.h"
+#include "backends/platform/psp/thread.h"
+
+static const char *imageName = "psp_image";
+#define PSP_SCREEN_HEIGHT 272
+#define PSP_SCREEN_WIDTH 480
+
+bool ImageViewer::load(int imageNum) {
+ if (_init)
+ unload();
+
+ // build string
+ char number[8];
+ sprintf(number, "%d", imageNum);
+ Common::String imageNameStr(imageName);
+ Common::String specificImageName = imageNameStr + Common::String(number) + Common::String(".png");
+
+ // search for image file
+ if (!SearchMan.hasFile(specificImageName)) {
+ PSP_ERROR("file %s not found\n", specificImageName.c_str());
+ return false;
+ }
+
+ Common::ScopedPtr<Common::SeekableReadStream> file(SearchMan.createReadStreamForMember(specificImageName));
+
+ _buffer = new Buffer();
+ _palette = new Palette();
+ _renderer = new GuRenderer();
+
+ assert(_buffer);
+ assert(_palette);
+ assert(_renderer);
+
+ // Load a PNG into our buffer and palette. Size it by the actual size of the image
+ PngLoader image(file, *_buffer, *_palette, Buffer::kSizeBySourceSize);
+
+ PngLoader::Status status = image.allocate(); // allocate the buffers for the file
+
+ char error[100];
+ if (status == PngLoader::BAD_FILE) {
+ sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str());
+ GUI::TimedMessageDialog dialog(error, 4000);
+ dialog.runModal();
+ return false;
+ } else if (status == PngLoader::OUT_OF_MEMORY) {
+ sprintf(error, "Out of memory loading %s. Try making the image smaller", specificImageName.c_str());
+ GUI::TimedMessageDialog dialog(error, 4000);
+ dialog.runModal();
+ return false;
+ }
+ // try to load the image file
+ if (!image.load()) {
+ sprintf(error, "Cannot display %s. Not a proper PNG file", specificImageName.c_str());
+ GUI::TimedMessageDialog dialog(error, 4000);
+ dialog.runModal();
+ return false;
+ }
+
+ setConstantRendererOptions();
+ setFullScreenImageParams(); // prepare renderer for full screen view
+
+ _imageNum = imageNum; // now we can say we displayed this image
+ _init = true;
+
+ return true;
+}
+
+void ImageViewer::setConstantRendererOptions() {
+ _renderer->setBuffer(_buffer);
+ _renderer->setPalette(_palette);
+
+ _renderer->setAlphaBlending(false);
+ _renderer->setColorTest(false);
+ _renderer->setUseGlobalScaler(false);
+ _renderer->setStretch(true);
+ _renderer->setOffsetInBuffer(0, 0);
+ _renderer->setDrawWholeBuffer();
+}
+
+void ImageViewer::unload() {
+ _init = false;
+ delete _buffer;
+ delete _palette;
+ delete _renderer;
+ _buffer = 0;
+ _palette = 0;
+ _renderer = 0;
+}
+
+void ImageViewer::resetOnEngineDone() {
+ _imageNum = 0;
+}
+
+void ImageViewer::setVisible(bool visible) {
+ DEBUG_ENTER_FUNC();
+
+ if (_visible == visible)
+ return;
+
+ // from here on, we're making the loader visible
+ if (visible && g_engine) { // we can only run the image viewer when there's an engine
+ g_engine->pauseEngine(true);
+
+ load(_imageNum ? _imageNum : 1); // load the 1st image or the current
+ }
+
+ if (visible && _init) { // we managed to load
+ _visible = true;
+ setViewerButtons(true);
+
+ { // so dialog goes out of scope, destroying all allocations
+ GUI::TimedMessageDialog dialog("Image Viewer", 1000);
+ dialog.runModal();
+ }
+
+ runLoop(); // only listen to viewer events
+ } else { // we were asked to make invisible or failed to load
+ _visible = false;
+ unload();
+ setViewerButtons(false);
+
+ if (g_engine && g_engine->isPaused())
+ g_engine->pauseEngine(false);
+ }
+ setDirty();
+}
+
+// This is the only way we can truly pause the games
+// Sad but true.
+void ImageViewer::runLoop() {
+ while (_visible) {
+ Common::Event event;
+ PspThread::delayMillis(30);
+ _inputHandler->getAllInputs(event);
+ _displayManager->renderAll();
+ }
+}
+
+void ImageViewer::setViewerButtons(bool active) {
+ _inputHandler->setImageViewerMode(active);
+}
+
+void ImageViewer::loadNextImage() {
+ if (!load(_imageNum+1)) { // try to load the next image
+ if (!load(_imageNum)) // we failed, so reload the current image
+ setVisible(false); // just hide
+ }
+ setDirty();
+}
+
+void ImageViewer::loadLastImage() {
+ if (_imageNum - 1 > 0) {
+ if (!load(_imageNum-1))
+ if (!load(_imageNum))
+ setVisible(false); // we can't even show the old image so hide
+ }
+ setDirty();
+}
+
+void ImageViewer::setFullScreenImageParams() {
+ // we try to fit the image fullscreen at least in one dimension
+ uint32 width = _buffer->getSourceWidth();
+ uint32 height = _buffer->getSourceHeight();
+
+ _centerX = PSP_SCREEN_WIDTH / 2.0f;
+ _centerY = PSP_SCREEN_HEIGHT / 2.0f;
+
+ // see if we fit width wise
+ if (PSP_SCREEN_HEIGHT >= (int)((height * PSP_SCREEN_WIDTH) / (float)width)) {
+ setZoom(PSP_SCREEN_WIDTH / (float)width);
+ } else {
+ setZoom(PSP_SCREEN_HEIGHT / (float)height);
+ }
+}
+
+void ImageViewer::render() {
+ if (_init) {
+ assert(_buffer);
+ assert(_renderer);
+
+ // move the image slightly. Note that we count on the renderer's timing
+ switch (_movement) {
+ case EVENT_MOVE_LEFT:
+ moveImageX(-_visibleWidth / 100.0f);
+ break;
+ case EVENT_MOVE_UP:
+ moveImageY(-_visibleHeight / 100.0f);
+ break;
+ case EVENT_MOVE_RIGHT:
+ moveImageX(_visibleWidth / 100.0f);
+ break;
+ case EVENT_MOVE_DOWN:
+ moveImageY(_visibleHeight / 100.0f);
+ break;
+ default:
+ break;
+ }
+ _renderer->render();
+ }
+}
+
+void ImageViewer::modifyZoom(bool up) {
+ float factor = _zoomFactor;
+ if (up)
+ factor += 0.1f;
+ else // down
+ factor -= 0.1f;
+
+ setZoom(factor);
+}
+
+void ImageViewer::setZoom(float value) {
+ if (value <= 0.0f) // don't want 0 or negative zoom
+ return;
+
+ _zoomFactor = value;
+ _renderer->setStretchXY(value, value);
+ setOffsetParams();
+}
+
+void ImageViewer::moveImageX(float val) {
+ float newVal = _centerX + val;
+
+ if (newVal - (_visibleWidth / 2) > PSP_SCREEN_WIDTH - 4 || newVal + (_visibleWidth / 2) < 4)
+ return;
+ _centerX = newVal;
+ setOffsetParams();
+}
+
+void ImageViewer::moveImageY(float val) {
+ float newVal = _centerY + val;
+
+ if (newVal - (_visibleHeight / 2) > PSP_SCREEN_HEIGHT - 4 || newVal + (_visibleHeight / 2) < 4)
+ return;
+ _centerY = newVal;
+ setOffsetParams();
+}
+
+// Set the renderer with the proper offset on the screen
+//
+void ImageViewer::setOffsetParams() {
+ _visibleWidth = _zoomFactor * _buffer->getSourceWidth();
+ _visibleHeight = _zoomFactor * _buffer->getSourceHeight();
+
+ int offsetX = _centerX - (int)(_visibleWidth * 0.5f);
+ int offsetY = _centerY - (int)(_visibleHeight * 0.5f);
+
+ _renderer->setOffsetOnScreen(offsetX, offsetY);
+ setDirty();
+}
+
+// Handler events coming in from the inputHandler
+//
+void ImageViewer::handleEvent(uint32 event) {
+ DEBUG_ENTER_FUNC();
+
+ switch (event) {
+ case EVENT_HIDE:
+ setVisible(false);
+ break;
+ case EVENT_SHOW:
+ setVisible(true);
+ break;
+ case EVENT_ZOOM_IN:
+ modifyZoom(true);
+ break;
+ case EVENT_ZOOM_OUT:
+ modifyZoom(false);
+ break;
+ case EVENT_MOVE_LEFT:
+ case EVENT_MOVE_UP:
+ case EVENT_MOVE_RIGHT:
+ case EVENT_MOVE_DOWN:
+ case EVENT_MOVE_STOP:
+ _movement = (Event)event;
+ break;
+ case EVENT_NEXT_IMAGE:
+ loadNextImage();
+ break;
+ case EVENT_LAST_IMAGE:
+ loadLastImage();
+ break;
+ default:
+ PSP_ERROR("Unknown event %d\n", event);
+ break;
+ }
+} \ No newline at end of file
diff --git a/backends/platform/psp/image_viewer.h b/backends/platform/psp/image_viewer.h
new file mode 100644
index 0000000000..ef8b196dbe
--- /dev/null
+++ b/backends/platform/psp/image_viewer.h
@@ -0,0 +1,105 @@
+/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
+ * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ *
+ */
+
+#ifndef PSP_IMAGE_VIEWER_H
+#define PSP_IMAGE_VIEWER_H
+
+class InputHandler;
+
+class ImageViewer : public DisplayClient {
+public:
+ enum Event {
+ EVENT_NONE = -1,
+ EVENT_HIDE = 0,
+ EVENT_SHOW = 1,
+ EVENT_ZOOM_IN,
+ EVENT_ZOOM_OUT,
+ EVENT_MOVE_LEFT,
+ EVENT_MOVE_UP,
+ EVENT_MOVE_RIGHT,
+ EVENT_MOVE_DOWN,
+ EVENT_MOVE_STOP,
+ EVENT_NEXT_IMAGE,
+ EVENT_LAST_IMAGE,
+ };
+
+private:
+ Buffer *_buffer;
+ Palette *_palette;
+ GuRenderer *_renderer;
+ bool _visible;
+ bool _dirty;
+ bool _init;
+ uint32 _imageNum; // current image number
+ float _zoomFactor; // how much we're zooming in/out on the image
+ float _visibleHeight, _visibleWidth;
+ float _centerX, _centerY;
+ Event _movement;
+
+ InputHandler *_inputHandler;
+ DisplayManager *_displayManager;
+
+ void setFullScreenImageParams();
+ void loadNextImage();
+ void loadLastImage();
+ void setViewerButtons(bool active);
+ void setConstantRendererOptions();
+ void moveImageX(float val);
+ void moveImageY(float val);
+ bool load(int imageNum);
+ void unload();
+ void runLoop(); // to get total pausing we have to do our own loop
+
+ void setZoom(float value);
+ void setOffsetParams();
+ void modifyZoom(bool up); // up or down
+ void setVisible(bool visible);
+
+public:
+
+ ImageViewer() : _buffer(0), _palette(0), _visible(false),
+ _dirty(false), _init(false), _imageNum(0),
+ _zoomFactor(0.0f), _visibleHeight(0.0f), _visibleWidth(0.0f),
+ _centerX(0.0f), _centerY(0.0f), _movement(EVENT_MOVE_STOP),
+ _inputHandler(0), _displayManager(0) {}
+ ~ImageViewer() { unload(); } // deallocate images
+ bool load();
+ void render();
+ bool isVisible() { return _visible; }
+ bool isDirty() { return _dirty; }
+ void setDirty() { _dirty = true; }
+ void setClean() { if (!_visible) // otherwise we want to keep rendering
+ _dirty = false;
+ }
+ void resetOnEngineDone();
+
+ void handleEvent(uint32 event);
+
+ // pointer setters
+ void setInputHandler(InputHandler *inputHandler) { _inputHandler = inputHandler; }
+ void setDisplayManager(DisplayManager *displayManager) { _displayManager = displayManager; }
+};
+
+#endif /* PSP_IMAGE_VIEWER_H */ \ No newline at end of file
diff --git a/backends/platform/psp/input.cpp b/backends/platform/psp/input.cpp
index 2a91ce455a..665f41504f 100644
--- a/backends/platform/psp/input.cpp
+++ b/backends/platform/psp/input.cpp
@@ -23,238 +23,274 @@
*
*/
-// Todo: handle events that should fire because of shift going off
-// Solution: handle shift on a button-by-button basis, only allowing it when the button is up. Also a inputmap-wide button. At buttonup, shiftstate is inspected per button.
+#include <pspctrl.h>
+#include "gui/message.h"
+#include "backends/platform/psp/input.h"
//#define __PSP_DEBUG_FUNCS__ /* Uncomment for debugging the stack */
//#define __PSP_DEBUG_PRINT__ /* Uncomment for debug prints */
-
#include "backends/platform/psp/trace.h"
-#include "backends/platform/psp/psppixelformat.h"
-#include "backends/platform/psp/input.h"
-
// 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 DOWN(x) ((pad.Buttons & (x)) == (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)
#define PSP_TRIGGERS (PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER)
+#define PSP_ALL_BUTTONS (PSP_DPAD | PSP_4BUTTONS | PSP_TRIGGERS | PSP_CTRL_START | PSP_CTRL_SELECT)
#define PAD_CHECK_TIME 53
-void InputHandler::init() {
- sceCtrlSetSamplingCycle(0); // set sampling to vsync. n = n usecs
- sceCtrlSetSamplingMode(1); // analog
+Button::Button() {
+ clear();
}
-bool InputHandler::getAllInputs(Common::Event &event) {
- DEBUG_ENTER_FUNC();
+inline void Button::clear() {
+ _key = Common::KEYCODE_INVALID;
+ _ascii = 0;
+ _flag = 0;
+ _pspEventDown.clear();
+ _pspEventUp.clear();
+}
- uint32 time = g_system->getMillis(); // may not be necessary with read
- if (time - _lastPadCheckTime < PAD_CHECK_TIME) {
- return false;
+inline bool Button::getEvent(Common::Event &event, PspEvent &pspEvent, bool down) {
+ if (down) {
+ if (!_pspEventDown.isEmpty())
+ pspEvent = _pspEventDown;
+ } else { // up
+ if (!_pspEventUp.isEmpty())
+ pspEvent = _pspEventUp;
}
+ if (_key != Common::KEYCODE_INVALID) {
+ event.type = down ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP;
+ event.kbd.keycode = _key;
+ event.kbd.ascii = _ascii;
+ event.kbd.flags |= _flag;
+ return true;
+ } else if (_flag) { // handle flag only events
+ event.type = down ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP;
+ event.kbd.flags |= down ? _flag : 0;
+ return true;
+ }
+ return false;
+}
- _lastPadCheckTime = time;
- SceCtrlData pad;
-
- sceCtrlPeekBufferPositive(&pad, 1); // Peek ignores sleep. Read sleeps thread
-
- bool haveEvent;
-
- memset(&event, 0, sizeof(event));
+void Button::setPspEvent(PspEventType typeDown, uint32 dataDown, PspEventType typeUp, uint32 dataUp) {
+ _pspEventDown.type = typeDown;
+ _pspEventDown.data = dataDown;
+ _pspEventUp.type = typeUp;
+ _pspEventUp.data = dataUp;
+}
- if (_keyboard->isVisible())
- haveEvent = _keyboard->processInput(event, pad);
- else
- haveEvent = getEvent(event, pad);
+// Translates bitfields to our constants
+// We put combined bitfields first to make sure we pick up diagonals
+const uint32 ButtonPad::_buttonMap[] = {
+ PSP_CTRL_UP | PSP_CTRL_LEFT,
+ PSP_CTRL_UP | PSP_CTRL_RIGHT,
+ PSP_CTRL_DOWN | PSP_CTRL_RIGHT,
+ PSP_CTRL_DOWN | PSP_CTRL_LEFT,
+ PSP_CTRL_RIGHT, PSP_CTRL_DOWN, PSP_CTRL_LEFT, PSP_CTRL_UP,
+ PSP_CTRL_CROSS, PSP_CTRL_CIRCLE, PSP_CTRL_TRIANGLE, PSP_CTRL_SQUARE,
+ PSP_CTRL_LTRIGGER, PSP_CTRL_RTRIGGER, PSP_CTRL_START, PSP_CTRL_SELECT
+};
+
+ButtonPad::ButtonPad() : _prevButtonState(0), _shifted(UNSHIFTED), _padMode(PAD_MODE_NORMAL),
+ _comboMode(false), _combosEnabled(true) {
+ for (int i = UNSHIFTED; i < SHIFTED_MODE_LAST; i++)
+ _buttonsChanged[i] = 0;
+ clearButtons();
+}
- if (haveEvent) {
- PSP_DEBUG_PRINT("Have event[%s]\n", haveEvent ? "true" : "false");
- PSP_DEBUG_PRINT("event.type[%d]\n", event.type);
+void ButtonPad::clearButtons() {
+ for (int i = BTN_UP_LEFT; i < BTN_LAST; i++) {
+ _button[i][UNSHIFTED].clear();
+ _button[i][SHIFTED].clear();
}
+}
- return haveEvent;
+void ButtonPad::initButtons() {
+ switch (_padMode) {
+ case PAD_MODE_NORMAL:
+ initButtonsNormalMode();
+ break;
+ case PAD_MODE_LOL:
+ initButtonsLolMode();
+ break;
+ default:
+ break;
+ }
}
-bool InputHandler::getEvent(Common::Event &event, SceCtrlData &pad) {
+void ButtonPad::initButtonsNormalMode() {
DEBUG_ENTER_FUNC();
+ PSP_DEBUG_PRINT("initializing buttons for normal mode\n");
+ clearButtons();
+
+ // Dpad
+ _button[BTN_UP_LEFT][UNSHIFTED].setKey(Common::KEYCODE_KP7, '7');
+ _button[BTN_LEFT][SHIFTED].setKey(Common::KEYCODE_KP7, '7'); // same as up_left
+ _button[BTN_UP][UNSHIFTED].setKey(Common::KEYCODE_KP8, '8');
+ _button[BTN_UP_RIGHT][UNSHIFTED].setKey(Common::KEYCODE_KP9, '9');
+ _button[BTN_UP][SHIFTED].setKey(Common::KEYCODE_KP9, '9'); // same as up_right
+ _button[BTN_LEFT][UNSHIFTED].setKey(Common::KEYCODE_KP4, '4');
+ _button[BTN_RIGHT][UNSHIFTED].setKey(Common::KEYCODE_KP6, '6');
+ _button[BTN_DOWN_LEFT][UNSHIFTED].setKey(Common::KEYCODE_KP1, '1');
+ _button[BTN_DOWN][SHIFTED].setKey(Common::KEYCODE_KP1, '1'); // same as down_left
+ _button[BTN_DOWN][UNSHIFTED].setKey(Common::KEYCODE_KP2, '2');
+ _button[BTN_DOWN_RIGHT][UNSHIFTED].setKey(Common::KEYCODE_KP3, '3');
+ _button[BTN_RIGHT][SHIFTED].setKey(Common::KEYCODE_KP3, '3'); // same as down_right
+
+ // Other buttons
+ _button[BTN_CROSS][UNSHIFTED].setPspEvent(PSP_EVENT_LBUTTON, true, PSP_EVENT_LBUTTON, false);
+ _button[BTN_CIRCLE][UNSHIFTED].setPspEvent(PSP_EVENT_RBUTTON, true, PSP_EVENT_RBUTTON, false);
+ _button[BTN_TRIANGLE][UNSHIFTED].setKey(Common::KEYCODE_RETURN, '\r');
+ _button[BTN_SQUARE][UNSHIFTED].setKey(Common::KEYCODE_PERIOD, '.');
+ _button[BTN_SQUARE][SHIFTED].setKey(Common::KEYCODE_SPACE, ' ');
+ _button[BTN_LTRIGGER][UNSHIFTED].setKey(Common::KEYCODE_ESCAPE, 27);
+ _button[BTN_RTRIGGER][SHIFTED].setPspEvent(PSP_EVENT_SHIFT, true, PSP_EVENT_SHIFT, false);
+ _button[BTN_RTRIGGER][UNSHIFTED].setPspEvent(PSP_EVENT_SHIFT, true, PSP_EVENT_SHIFT, false);
+ _button[BTN_RTRIGGER][SHIFTED].setKey(Common::KEYCODE_INVALID, 0, Common::KBD_SHIFT);
+ _button[BTN_RTRIGGER][UNSHIFTED].setKey(Common::KEYCODE_INVALID, 0, Common::KBD_SHIFT);
+ _button[BTN_START][SHIFTED].setKey(Common::KEYCODE_F5, Common::ASCII_F5);
+ _button[BTN_START][UNSHIFTED].setKey(Common::KEYCODE_F5, Common::ASCII_F5, Common::KBD_CTRL);
+ _button[BTN_SELECT][UNSHIFTED].setPspEvent(PSP_EVENT_SHOW_VIRTUAL_KB, true, PSP_EVENT_NONE, 0);
+ _button[BTN_SELECT][SHIFTED].setPspEvent(PSP_EVENT_IMAGE_VIEWER, true, PSP_EVENT_NONE, 0);
+}
- _buttonsChanged = pad.Buttons ^ _prevButtons;
- bool haveEvent = false;
+void ButtonPad::initButtonsLolMode() {
+ DEBUG_ENTER_FUNC();
+ initButtonsNormalMode(); // set normal button configuration
+ PSP_DEBUG_PRINT("initializing buttons for LOL mode\n");
+
+ // Square is our new shift button
+ _button[BTN_SQUARE][UNSHIFTED].clear();
+ _button[BTN_SQUARE][UNSHIFTED].setPspEvent(PSP_EVENT_SHIFT, true, PSP_EVENT_SHIFT, false);
+ _button[BTN_SQUARE][SHIFTED].clear();
+ _button[BTN_SQUARE][SHIFTED].setPspEvent(PSP_EVENT_SHIFT, true, PSP_EVENT_SHIFT, false);
+
+ // Dpad
+ _button[BTN_LEFT][UNSHIFTED].clear();
+ _button[BTN_LEFT][UNSHIFTED].setKey(Common::KEYCODE_KP7, '7');
+ _button[BTN_LEFT][SHIFTED].clear();
+ _button[BTN_LEFT][SHIFTED].setKey(Common::KEYCODE_F1, Common::ASCII_F1);
+ _button[BTN_UP][SHIFTED].clear();
+ _button[BTN_UP][SHIFTED].setKey(Common::KEYCODE_F2, Common::ASCII_F2);
+ _button[BTN_RIGHT][UNSHIFTED].clear();
+ _button[BTN_RIGHT][UNSHIFTED].setKey(Common::KEYCODE_KP9, '9');
+ _button[BTN_RIGHT][SHIFTED].clear();
+ _button[BTN_RIGHT][SHIFTED].setKey(Common::KEYCODE_F3, Common::ASCII_F3);
+ _button[BTN_DOWN][SHIFTED].clear();
+ _button[BTN_DOWN][SHIFTED].setKey(Common::KEYCODE_F4, Common::ASCII_F4);
+
+ // Buttons
+ _button[BTN_LTRIGGER][UNSHIFTED].clear();
+ _button[BTN_LTRIGGER][SHIFTED].clear();
+ _button[BTN_LTRIGGER][UNSHIFTED].setKey(Common::KEYCODE_KP4, '4'); // Triggers turn
+ _button[BTN_RTRIGGER][UNSHIFTED].clear();
+ _button[BTN_RTRIGGER][SHIFTED].clear();
+ _button[BTN_RTRIGGER][UNSHIFTED].setKey(Common::KEYCODE_KP6, '6');
+ _button[BTN_START][SHIFTED].clear();
+ _button[BTN_START][SHIFTED].setKey(Common::KEYCODE_ESCAPE, 27);
+}
- // Collect events from different sources
- haveEvent = getDpadEvent(event, pad);
+bool ButtonPad::getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad) {
+ DEBUG_ENTER_FUNC();
- if (!haveEvent)
- haveEvent = getButtonEvent(event, pad);
+ //PSP_DEBUG_PRINT("buttons[%x]\n", pad.Buttons);
- if (!haveEvent)
- haveEvent = getNubEvent(event, pad);
+ uint32 curButtonState = PSP_ALL_BUTTONS & pad.Buttons; // we only care about these
- _prevButtons = pad.Buttons;
+ if (_combosEnabled)
+ modifyButtonsForCombos(pad); // change buttons for combos
- return haveEvent;
+ return getEventFromButtonState(event, pspEvent, curButtonState);
}
-bool InputHandler::getDpadEvent(Common::Event &event, SceCtrlData &pad) {
+bool ButtonPad::getEventFromButtonState(Common::Event &event, PspEvent &pspEvent, uint32 buttonState) {
DEBUG_ENTER_FUNC();
+ _buttonsChanged[_shifted] |= buttonState ^ _prevButtonState; // add any buttons that changed
+ _prevButtonState = buttonState;
+
+ for (int shiftState = UNSHIFTED; shiftState < SHIFTED_MODE_LAST; shiftState++) {
+ if (_buttonsChanged[shiftState]) { // any button to address?
+ PSP_DEBUG_PRINT("found changed buttons\n");
+ ButtonType buttonType = BTN_LAST;
+ bool buttonDown = false; // normally we release a button (as in when we're in a different shiftmode)
+
+ for (int i = BTN_UP_LEFT; i < BTN_LAST; i++) {
+ uint32 buttonCode = _buttonMap[i];
+ if ((_buttonsChanged[shiftState] & buttonCode) == buttonCode) { // check for this changed button
+ buttonType = (ButtonType)i; // we know which button changed
+ _buttonsChanged[shiftState] &= ~buttonCode; // save the fact that we treated this button
+ if (shiftState == _shifted)
+ buttonDown = buttonState & buttonCode ? true : false; // pressed or released?
+
+ PSP_DEBUG_PRINT("button[%i] pressed\n", i);
+ break;
+ }
+ }
- int newDpadX = 0, newDpadY = 0;
- bool haveEvent = false;
-
- if (DOWN(PSP_CTRL_UP)) {
- newDpadY++;
- if (DOWN(PSP_CTRL_RTRIGGER)) // Shifting causes diagonals
- newDpadX++;
- }
- if (DOWN(PSP_CTRL_RIGHT)) {
- newDpadX++;
- if (DOWN(PSP_CTRL_RTRIGGER))
- newDpadY--;
- }
- if (DOWN(PSP_CTRL_DOWN)) {
- newDpadY--;
- if (DOWN(PSP_CTRL_RTRIGGER))
- newDpadX--;
- }
- if (DOWN(PSP_CTRL_LEFT)) {
- newDpadX--;
- if (DOWN(PSP_CTRL_RTRIGGER))
- newDpadY++;
- }
-
- if (newDpadX != _dpadX || newDpadY != _dpadY) {
- if (_dpadX == 0 && _dpadY == 0) { // We were in the middle so we pressed dpad
- event.type = Common::EVENT_KEYDOWN;
- event.kbd.keycode = translateDpad(newDpadX, newDpadY);
- event.kbd.ascii = event.kbd.keycode - Common::KEYCODE_KP0 + '0'; // Get ascii
- _dpadX = newDpadX;
- _dpadY = newDpadY;
- } else if (newDpadX == 0 && newDpadY == 0) {// We're now centered so we unpressed dpad
- event.type = Common::EVENT_KEYUP;
- event.kbd.keycode = translateDpad(_dpadX, _dpadY);
- event.kbd.ascii = event.kbd.keycode - Common::KEYCODE_KP0 + '0';
- _dpadX = newDpadX;
- _dpadY = newDpadY;
- } else { // we moved from one pressed dpad direction to another one
- event.type = Common::EVENT_KEYUP; // first release the last dpad direction
- event.kbd.keycode = translateDpad(_dpadX, _dpadY);
- event.kbd.ascii = event.kbd.keycode - Common::KEYCODE_KP0 + '0';
- _dpadX = 0; // so that we'll pick up a new dpad movement the next round
- _dpadY = 0;
+ assert (buttonType < BTN_LAST);
+ bool haveEvent = _button[buttonType][shiftState].getEvent(event, pspEvent, buttonDown);
+ if (haveEvent)
+ PSP_DEBUG_PRINT("have event. key[%d] flag[%x] %s\n", event.kbd.ascii, event.kbd.flags, buttonDown ? "down" : "up");
+ return haveEvent;
}
-
- PSP_DEBUG_PRINT("Keypad event. DpadX[%d], DpadY[%d]\n", _dpadX, _dpadY);
- haveEvent = true;
}
- return haveEvent;
+ return false;
}
-inline Common::KeyCode InputHandler::translateDpad(int x, int y) {
- DEBUG_ENTER_FUNC();
- Common::KeyCode key;
-
- if (x == -1) {
- if (y == -1)
- key = Common::KEYCODE_KP1;
- else if (y == 0)
- key = Common::KEYCODE_KP4;
- else /* y == 1 */
- key = Common::KEYCODE_KP7;
- } else if (x == 0) {
- if (y == -1)
- key = Common::KEYCODE_KP2;
- else /* y == 1 */
- key = Common::KEYCODE_KP8;
- } else {/* x == 1 */
- if (y == -1)
- key = Common::KEYCODE_KP3;
- else if (y == 0)
- key = Common::KEYCODE_KP6;
- else /* y == 1 */
- key = Common::KEYCODE_KP9;
+void ButtonPad::modifyButtonsForCombos(SceCtrlData &pad) {
+ if (DOWN(PSP_CTRL_RTRIGGER | PSP_CTRL_LTRIGGER)) {
+ if (!_comboMode) { // we're entering combo mode
+ PSP_DEBUG_PRINT("entering combo mode\n");
+ _button[BTN_SQUARE][UNSHIFTED].clear();
+ _button[BTN_SQUARE][SHIFTED].clear();
+ _button[BTN_DOWN][SHIFTED].clear();
+ _button[BTN_DOWN][UNSHIFTED].clear();
+ _button[BTN_UP][SHIFTED].clear();
+ _button[BTN_UP][UNSHIFTED].clear();
+ _button[BTN_SQUARE][UNSHIFTED].setPspEvent(PSP_EVENT_MODE_SWITCH, true, PSP_EVENT_NONE, true);
+ _button[BTN_SQUARE][SHIFTED].setPspEvent(PSP_EVENT_MODE_SWITCH, true, PSP_EVENT_NONE, true);
+ _button[BTN_DOWN][UNSHIFTED].setPspEvent(PSP_EVENT_CHANGE_SPEED, false, PSP_EVENT_NONE, true);
+ _button[BTN_DOWN][SHIFTED].setPspEvent(PSP_EVENT_CHANGE_SPEED, false, PSP_EVENT_NONE, true);
+ _button[BTN_UP][UNSHIFTED].setPspEvent(PSP_EVENT_CHANGE_SPEED, true, PSP_EVENT_NONE, true);
+ _button[BTN_UP][SHIFTED].setPspEvent(PSP_EVENT_CHANGE_SPEED, true, PSP_EVENT_NONE, true);
+ _comboMode = true;
+ }
+ } else { // no combo buttons are pressed now
+ if (_comboMode) { // we have been running in combo mode
+ initButtons(); // reset the button configuration
+ _comboMode = false;
+ }
}
-
- return key;
}
-
-bool InputHandler::getButtonEvent(Common::Event &event, SceCtrlData &pad) {
+bool Nub::getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad) {
DEBUG_ENTER_FUNC();
- bool haveEvent = false;
-
- if (PRESSED(PSP_CTRL_SELECT))
- _keyboard->setVisible(true);
-
- else if (CHANGED(PSP_4BUTTONS | PSP_TRIGGERS | PSP_CTRL_START)) {
- if (CHANGED(PSP_CTRL_CROSS)) {
- event.type = DOWN(PSP_CTRL_CROSS) ? Common::EVENT_LBUTTONDOWN : Common::EVENT_LBUTTONUP;
- event.mouse.x = _cursor->getX(); // Could this have to do with SCI enter problem?
- event.mouse.y = _cursor->getY();
- PSP_DEBUG_PRINT("%s\n", event.type == Common::EVENT_LBUTTONDOWN ? "LButtonDown" : "LButtonUp");
- } else if (CHANGED(PSP_CTRL_CIRCLE)) {
- event.type = DOWN(PSP_CTRL_CIRCLE) ? Common::EVENT_RBUTTONDOWN : Common::EVENT_RBUTTONUP;
- event.mouse.x = _cursor->getX();
- event.mouse.y = _cursor->getY();
- PSP_DEBUG_PRINT("%s\n", event.type == Common::EVENT_LBUTTONDOWN ? "RButtonDown" : "RButtonUp");
- } else {
- //any of the other buttons.
- event.type = _buttonsChanged & pad.Buttons ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP;
- event.kbd.ascii = 0;
- event.kbd.flags = 0;
-
- if (CHANGED(PSP_CTRL_LTRIGGER)) {
- event.kbd.keycode = Common::KEYCODE_ESCAPE;
- event.kbd.ascii = 27;
- } else if (CHANGED(PSP_CTRL_START)) {
- event.kbd.keycode = Common::KEYCODE_F5;
- event.kbd.ascii = Common::ASCII_F5;
- if (DOWN(PSP_CTRL_RTRIGGER)) {
- event.kbd.flags |= Common::KBD_CTRL; // Main menu to allow RTL
- }
- } else if (CHANGED(PSP_CTRL_SQUARE)) {
- event.kbd.keycode = Common::KEYCODE_PERIOD;
- event.kbd.ascii = '.';
- } else if (CHANGED(PSP_CTRL_TRIANGLE)) {
- event.kbd.keycode = Common::KEYCODE_RETURN;
- event.kbd.ascii = '\r';
- } else if (DOWN(PSP_CTRL_RTRIGGER)) { // An event
- event.kbd.flags |= Common::KBD_SHIFT;
- }
- PSP_DEBUG_PRINT("Ascii[%d]. Key %s.\n", event.kbd.ascii, event.type == Common::EVENT_KEYDOWN ? "down" : "up");
- }
- haveEvent = true;
+ if (_dpadMode) { // Convert the nub to a D-Pad
+ uint32 buttonState;
+ translateToDpadState(pad.Lx, pad.Ly, buttonState);
+ return _buttonPad.getEventFromButtonState(event, pspEvent, buttonState);
}
- return haveEvent;
-}
-
-bool InputHandler::getNubEvent(Common::Event &event, SceCtrlData &pad) {
- DEBUG_ENTER_FUNC();
-
- bool haveEvent = false;
int32 analogStepX = pad.Lx; // Goes up to 255.
int32 analogStepY = pad.Ly;
- int32 oldX = _cursor->getX();
- int32 oldY = _cursor->getY();
-
analogStepX = modifyNubAxisMotion(analogStepX);
analogStepY = modifyNubAxisMotion(analogStepY);
+ int32 oldX = _cursor->getX();
+ int32 oldY = _cursor->getY();
+
if (analogStepX != 0 || analogStepY != 0) {
PSP_DEBUG_PRINT("raw x[%d], y[%d]\n", analogStepX, analogStepY);
// If no movement then this has no effect
- if (DOWN(PSP_CTRL_RTRIGGER)) {
+ if (_shifted) {
// Fine control mode for analog
if (analogStepX != 0) {
if (analogStepX > 0)
@@ -281,15 +317,29 @@ bool InputHandler::getNubEvent(Common::Event &event, SceCtrlData &pad) {
event.type = Common::EVENT_MOUSEMOVE;
event.mouse.x = newX;
event.mouse.y = newY;
- haveEvent = true;
-
PSP_DEBUG_PRINT("Nub event. X[%d], Y[%d]\n", newX, newY);
+ return true;
}
}
- return haveEvent;
+ return false;
+}
+
+void Nub::translateToDpadState(int dpadX, int dpadY, uint32 &buttonState) {
+ #define MIN_NUB_POSITION 70
+ buttonState = 0;
+
+ if (dpadX > 127 + MIN_NUB_POSITION)
+ buttonState |= PSP_CTRL_RIGHT;
+ else if (dpadX < 127 - MIN_NUB_POSITION)
+ buttonState |= PSP_CTRL_LEFT;
+
+ if (dpadY > 127 + MIN_NUB_POSITION)
+ buttonState |= PSP_CTRL_DOWN;
+ else if (dpadY < 127 - MIN_NUB_POSITION)
+ buttonState |= PSP_CTRL_UP;
}
-inline int32 InputHandler::modifyNubAxisMotion(int32 input) {
+inline int32 Nub::modifyNubAxisMotion(int32 input) {
DEBUG_ENTER_FUNC();
const int MIN_NUB_MOTION = 30;
@@ -304,3 +354,220 @@ inline int32 InputHandler::modifyNubAxisMotion(int32 input) {
return input;
}
+
+inline bool Nub::isButtonDown() {
+ if (_dpadMode) // only relevant in dpad mode
+ return _buttonPad.isButtonDown();
+ return false;
+}
+
+const char *InputHandler::_padModeText[] = {
+ "Normal Button Mode",
+ "1st Person RPG Button Mode"
+};
+
+void InputHandler::init() {
+ sceCtrlSetSamplingCycle(0); // set sampling to vsync. n = n usecs
+ sceCtrlSetSamplingMode(1); // analog
+
+ _buttonPad.initButtons();
+ _nub.init();
+}
+
+bool InputHandler::getAllInputs(Common::Event &event) {
+ DEBUG_ENTER_FUNC();
+
+ uint32 time = g_system->getMillis(); // may not be necessary with read
+ if (time - _lastPadCheckTime < PAD_CHECK_TIME) {
+ return false;
+ }
+
+ _lastPadCheckTime = time;
+ SceCtrlData pad;
+
+ sceCtrlPeekBufferPositive(&pad, 1); // Peek doesn't sleep. Read sleeps the thread
+
+ bool haveEvent;
+ //memset(&event, 0, sizeof(event));
+
+ haveEvent = getEvent(event, pad);
+
+ if (haveEvent) {
+ PSP_DEBUG_PRINT("Have event[%s]. Type[%d]\n", haveEvent ? "true" : "false", event.type);
+ }
+
+ return haveEvent;
+}
+
+bool InputHandler::getEvent(Common::Event &event, SceCtrlData &pad) {
+ DEBUG_ENTER_FUNC();
+
+ PspEvent pspEvent;
+ bool haveEvent = false;
+
+ if (_keyboard->isVisible()) {
+ haveEvent = _keyboard->processInput(event, pspEvent, pad);
+ } else { // only process buttonpad if keyboard invisible
+ haveEvent = _buttonPad.getEvent(event, pspEvent, pad);
+ }
+
+ if (!haveEvent && pspEvent.isEmpty())
+ haveEvent = _nub.getEvent(event, pspEvent, pad);
+
+ // handle any pending PSP events
+ if (!haveEvent && pspEvent.isEmpty()) {
+ if (!_pendingPspEvent.isEmpty()) {
+ pspEvent = _pendingPspEvent;
+ _pendingPspEvent.clear();
+ }
+ }
+
+ // handle any PSP events we might have
+ if (!pspEvent.isEmpty())
+ haveEvent |= handlePspEvent(event, pspEvent); // overrides any event we might have
+
+ return haveEvent;
+}
+
+bool InputHandler::handlePspEvent(Common::Event &event, PspEvent &pspEvent) {
+ bool haveEvent = false;
+
+ PSP_DEBUG_PRINT("have pspEvent[%d] data[%d]\n", pspEvent.type, pspEvent.data);
+
+ switch (pspEvent.type) {
+ case PSP_EVENT_SHIFT:
+ handleShiftEvent((ShiftMode)pspEvent.data);
+ break;
+ case PSP_EVENT_SHOW_VIRTUAL_KB:
+ _keyboard->setVisible((bool)pspEvent.data);
+ if ((pspEvent.data && _keyboard->isVisible()) || !pspEvent.data) // don't change mode if keyboard didn't load
+ _nub.setDpadMode((bool)pspEvent.data); // set nub to keypad/regular mode
+ break;
+ case PSP_EVENT_LBUTTON:
+ haveEvent = true;
+ if (pspEvent.data) // down
+ handleMouseEvent(event, Common::EVENT_LBUTTONDOWN, "LButtonDown");
+ else
+ handleMouseEvent(event, Common::EVENT_LBUTTONUP, "LButtonUp");
+ break;
+ case PSP_EVENT_RBUTTON:
+ haveEvent = true;
+ if (pspEvent.data) // down
+ handleMouseEvent(event, Common::EVENT_RBUTTONDOWN, "RButtonDown");
+ else
+ handleMouseEvent(event, Common::EVENT_RBUTTONUP, "RButtonUp");
+ break;
+ case PSP_EVENT_MODE_SWITCH:
+ handleModeSwitchEvent();
+ break;
+ /*case PSP_EVENT_CHANGE_SPEED:
+ handleSpeedChange(pspEvent.data);
+ break;*/
+ case PSP_EVENT_IMAGE_VIEWER:
+ _imageViewer->handleEvent(pspEvent.data);
+ break;
+ case PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS:
+ setImageViewerMode(pspEvent.data);
+ break;
+ default:
+ PSP_ERROR("Unhandled PSP Event[%d]\n", pspEvent.type);
+ break;
+ }
+
+ return haveEvent;
+}
+
+void InputHandler::handleMouseEvent(Common::Event &event, Common::EventType type, const char *string) {
+ event.type = type;
+ event.mouse.x = _cursor->getX();
+ event.mouse.y = _cursor->getY();
+ PSP_DEBUG_PRINT("%s event, x[%d], y[%d]\n", string, event.mouse.x, event.mouse.y);
+}
+
+void InputHandler::handleShiftEvent(ShiftMode shifted) {
+ _buttonPad.setShifted(shifted);
+ _nub.setShifted(shifted);
+}
+
+void InputHandler::handleModeSwitchEvent() {
+ // check if we can't switch modes right now
+ if (_buttonPad.isButtonDown() || _nub.isButtonDown()) { // can't switch yet
+ PSP_DEBUG_PRINT("postponing mode switch event\n");
+ _pendingPspEvent.type = PSP_EVENT_MODE_SWITCH; // queue it to be done later
+ } else { // we can switch
+ PSP_DEBUG_PRINT("mode switch event\n");
+ _padMode = (PspPadMode)(_padMode + 1);
+ if (_padMode >= PAD_MODE_LAST)
+ _padMode = PAD_MODE_NORMAL;
+
+ GUI::TimedMessageDialog dialog(_padModeText[_padMode], 1500);
+ dialog.runModal();
+
+ _buttonPad.setPadMode(_padMode);
+ _buttonPad.initButtons();
+ }
+}
+
+/*
+void InputHandler::handleSpeedChange(bool up) {
+ char *dialogMsg;
+
+ if (up) {
+ dialogMsg = "
+
+ GUI::TimedMessageDialog dialog(_padModeText[_padMode], 1500);
+ dialog.runModal();
+}*/
+
+void InputHandler::setImageViewerMode(bool active) {
+ if (_buttonPad.isButtonDown() || _nub.isButtonDown()) { // can't switch yet
+ PSP_DEBUG_PRINT("postponing image viewer on event\n");
+ _pendingPspEvent.type = PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS; // queue it to be done later
+ _pendingPspEvent.data = active;
+ } else if (active) {
+ _nub.setDpadMode(true);
+ _buttonPad.enableCombos(false); // disable combos
+ setButtonsForImageViewer();
+ } else { // deactivate
+ _nub.setDpadMode(false);
+ _nub.init();
+ _buttonPad.enableCombos(true); // re-enable combos
+ _buttonPad.initButtons();
+ }
+}
+
+void InputHandler::setButtonsForImageViewer() {
+ DEBUG_ENTER_FUNC();
+
+ // Dpad
+ _buttonPad.clearButtons();
+ _buttonPad.getButton(ButtonPad::BTN_UP, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_ZOOM_IN,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_DOWN, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_ZOOM_OUT,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_LEFT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_LAST_IMAGE,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_RIGHT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_NEXT_IMAGE,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_LTRIGGER, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_RTRIGGER, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_START, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE,
+ PSP_EVENT_NONE, false);
+ _buttonPad.getButton(ButtonPad::BTN_SELECT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_HIDE,
+ PSP_EVENT_NONE, false);
+
+ //Nub
+ _nub.getPad().clearButtons();
+ _nub.getPad().getButton(ButtonPad::BTN_UP, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_UP,
+ PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP);
+ _nub.getPad().getButton(ButtonPad::BTN_DOWN, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_DOWN,
+ PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP);
+ _nub.getPad().getButton(ButtonPad::BTN_LEFT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_LEFT,
+ PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP);
+ _nub.getPad().getButton(ButtonPad::BTN_RIGHT, UNSHIFTED).setPspEvent(PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_RIGHT,
+ PSP_EVENT_IMAGE_VIEWER, ImageViewer::EVENT_MOVE_STOP);
+}
+
+
diff --git a/backends/platform/psp/input.h b/backends/platform/psp/input.h
index cd686d9e02..9a1ab6faab 100644
--- a/backends/platform/psp/input.h
+++ b/backends/platform/psp/input.h
@@ -28,36 +28,175 @@
#include "common/scummsys.h"
#include "common/events.h"
-#include "backends/platform/psp/display_client.h"
-#include "backends/platform/psp/default_display_client.h"
#include "backends/platform/psp/pspkeyboard.h"
#include "backends/platform/psp/cursor.h"
+#include "backends/platform/psp/image_viewer.h"
#include <pspctrl.h>
+enum PspEventType {
+ PSP_EVENT_NONE = 0,
+ PSP_EVENT_SHIFT,
+ PSP_EVENT_SHOW_VIRTUAL_KB,
+ PSP_EVENT_LBUTTON,
+ PSP_EVENT_RBUTTON,
+ PSP_EVENT_MODE_SWITCH,
+ PSP_EVENT_CHANGE_SPEED,
+ PSP_EVENT_IMAGE_VIEWER,
+ PSP_EVENT_IMAGE_VIEWER_SET_BUTTONS,
+ PSP_EVENT_LAST
+};
+
+struct PspEvent {
+ PspEventType type;
+ uint32 data;
+ PspEvent() { clear(); }
+ void clear() {
+ type = PSP_EVENT_NONE;
+ data = 0;
+ }
+ bool isEmpty() { return type == PSP_EVENT_NONE; }
+};
+
+enum PspPadMode {
+ PAD_MODE_NORMAL,
+ PAD_MODE_LOL,
+ PAD_MODE_LAST
+};
+
+enum ShiftMode {
+ UNSHIFTED = 0,
+ SHIFTED = 1,
+ SHIFTED_MODE_LAST
+};
+
+
+class Button {
+private:
+ Common::KeyCode _key;
+ uint32 _ascii;
+ uint32 _flag;
+ PspEvent _pspEventDown; // event when we press
+ PspEvent _pspEventUp; // event when we release
+public:
+ Button();
+ void clear();
+ bool getEvent(Common::Event &event, PspEvent &pspEvent, bool buttonDown);
+ void setKey(Common::KeyCode key, uint32 ascii = 0, uint32 flag = 0) { _key = key; _ascii = ascii; _flag = flag; }
+ void setPspEvent(PspEventType typeDown, uint32 dataDown, PspEventType typeUp, uint32 dataUp);
+};
+
+class ButtonPad {
+public:
+ enum ButtonType { // must match the buttonMap
+ BTN_UP_LEFT,
+ BTN_UP_RIGHT,
+ BTN_DOWN_RIGHT,
+ BTN_DOWN_LEFT,
+ BTN_RIGHT,
+ BTN_DOWN,
+ BTN_LEFT,
+ BTN_UP,
+ BTN_CROSS,
+ BTN_CIRCLE,
+ BTN_TRIANGLE,
+ BTN_SQUARE,
+ BTN_LTRIGGER,
+ BTN_RTRIGGER,
+ BTN_START,
+ BTN_SELECT,
+ BTN_LAST
+ };
+
+private:
+ Button _button[BTN_LAST][SHIFTED_MODE_LAST];
+ uint32 _buttonsChanged[SHIFTED_MODE_LAST]; // normal and shifted
+ uint32 _prevButtonState;
+ ShiftMode _shifted;
+ PspPadMode _padMode;
+ bool _comboMode; // are we in the middle of combos
+ bool _combosEnabled; // can we do combos
+ static const uint32 _buttonMap[]; // maps the buttons to their values
+
+ void initButtonsNormalMode();
+ void initButtonsLolMode();
+ void modifyButtonsForCombos(SceCtrlData &pad);
+
+public:
+ ButtonPad();
+ void initButtons(); // set the buttons to the mode that's selected
+ void clearButtons(); // empty the buttons of all events
+
+ bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad);
+ bool getEventFromButtonState(Common::Event &event, PspEvent &pspEvent, uint32 buttonState);
+
+ void setShifted(ShiftMode shifted) { _shifted = shifted; }
+ void setPadMode(PspPadMode mode) { _padMode = mode; }
+ bool isButtonDown() { return _prevButtonState; }
+
+ void enableCombos(bool value) { _combosEnabled = value; }
+ Button &getButton(ButtonType type, ShiftMode mode) { return _button[type][mode]; }
+};
+
+class Nub {
+private:
+ Cursor *_cursor; // to enable changing/getting cursor position
+
+ ShiftMode _shifted;
+ bool _dpadMode;
+
+ ButtonPad _buttonPad; // private buttonpad for dpad mode
+
+ int32 modifyNubAxisMotion(int32 input);
+ void translateToDpadState(int dpadX, int dpadY, uint32 &buttonState); // convert nub data to dpad data
+public:
+ Nub() : _shifted(UNSHIFTED), _dpadMode(false) { }
+ void init() { _buttonPad.initButtons(); }
+
+ void setCursor(Cursor *cursor) { _cursor = cursor; }
+
+ // setters
+ void setDpadMode(bool active) { _dpadMode = active; }
+ void setShifted(ShiftMode shifted) { _shifted = shifted; }
+
+ // getters
+ bool isButtonDown();
+ bool getEvent(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad);
+ ButtonPad &getPad() { return _buttonPad; }
+};
+
class InputHandler {
public:
- InputHandler() : _cursor(0), _keyboard(0), _prevButtons(0), _lastPadCheckTime(0), _buttonsChanged(0), _dpadX(0), _dpadY(0) {}
+ InputHandler() : _keyboard(0), _cursor(0), _imageViewer(0), _padMode(PAD_MODE_NORMAL),
+ _lastPadCheckTime(0) {}
+ // pointer setters
+ void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; }
+ void setCursor(Cursor *cursor) { _cursor = cursor; _nub.setCursor(cursor); }
+ void setImageViewer(ImageViewer *imageViewer) { _imageViewer = imageViewer; }
void init();
bool getAllInputs(Common::Event &event);
- void setKeyboard(PSPKeyboard *keyboard) { _keyboard = keyboard; }
- void setCursor(Cursor *cursor) { _cursor = cursor; }
+ void setImageViewerMode(bool active);
private:
- Cursor *_cursor;
+ Nub _nub;
+ ButtonPad _buttonPad;
+
+ // Pointers to relevant other classes
PSPKeyboard *_keyboard;
- uint32 _prevButtons;
+ Cursor *_cursor;
+ ImageViewer *_imageViewer;
+
+ PspPadMode _padMode; // whice mode we're in
+ PspEvent _pendingPspEvent; // an event that can't be handled yet
uint32 _lastPadCheckTime;
- uint32 _buttonsChanged;
- int32 _dpadX, _dpadY;
- int32 _accelX, _accelY;
+ static const char *_padModeText[];
bool getEvent(Common::Event &event, SceCtrlData &pad);
- bool getDpadEvent(Common::Event &event, SceCtrlData &pad);
- bool getButtonEvent(Common::Event &event, SceCtrlData &pad);
- bool getNubEvent(Common::Event &event, SceCtrlData &pad);
- int32 modifyNubAxisMotion(int32 input);
- Common::KeyCode translateDpad(int x, int y);
+ bool handlePspEvent(Common::Event &event, PspEvent &pspEvent);
+ void handleMouseEvent(Common::Event &event, Common::EventType type, const char *string);
+ void handleShiftEvent(ShiftMode shifted);
+ void handleModeSwitchEvent();
+ void setButtonsForImageViewer();
};
#endif /* PSP_INPUT_H */
diff --git a/backends/platform/psp/memory.cpp b/backends/platform/psp/memory.cpp
index 29d0482d9a..924ab356e8 100644
--- a/backends/platform/psp/memory.cpp
+++ b/backends/platform/psp/memory.cpp
@@ -25,8 +25,8 @@
#include "common/scummsys.h"
#include "common/singleton.h"
-#include "common/list.h"
#include "backends/platform/psp/psppixelformat.h"
+#define PSP_INCLUDE_SWAP
#include "backends/platform/psp/memory.h"
// Class Copier --------------------------------------------------------------------------
@@ -37,23 +37,6 @@
//#define TEST_MEMORY_COPY
-extern "C" {
-
-#ifdef TEST_MEMORY_COPY /* we won't be able to run in this case b/c of printouts */
-extern void *__real_memcpy(void *dst, void *src, size_t bytes);
-#endif
-
-void *__wrap_memcpy(void *dst, void *src, size_t bytes) {
-#ifdef TEST_MEMORY_COPY /* we won't be able to run in this case */
- return __real_memcpy(dst, src, bytes);
-#else
- PspMemory::fastCopy((byte *)dst, (byte *)src, bytes);
- return dst;
-#endif
-}
-
-}
-
void PspMemory::copy(byte *dst, const byte *src, uint32 bytes) {
DEBUG_ENTER_FUNC();
@@ -66,29 +49,29 @@ void PspMemory::copy(byte *dst, const byte *src, uint32 bytes) {
// align the destination pointer first
uint32 prefixDst = (((uint32)dst) & 0x3);
-
+
if (prefixDst) {
- prefixDst = 4 - prefixDst; // prefix only if we have address % 4 != 0
+ prefixDst = 4 - prefixDst; // prefix only if we have address % 4 != 0
PSP_DEBUG_PRINT("prefixDst[%d]\n", prefixDst);
bytes -= prefixDst; // remember we assume bytes >= 4
-
+
if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) { // check if it's worthwhile to continue
copy8(dst, src, bytes + prefixDst);
#ifdef TEST_MEMORY_COPY
testCopy(debugDst, debugSrc, debugBytes);
-#endif
+#endif
return;
}
-
+
while (prefixDst--) {
*dst++ = *src++;
- }
+ }
}
-
+
// check the source pointer alignment now
uint32 alignSrc = (((uint32)src) & 0x3);
-
+
if (alignSrc) { // we'll need to realign our reads
copy32Misaligned((uint32 *)dst, src, bytes, alignSrc);
} else {
@@ -97,104 +80,14 @@ void PspMemory::copy(byte *dst, const byte *src, uint32 bytes) {
#ifdef TEST_MEMORY_COPY
testCopy(debugDst, debugSrc, debugBytes);
-#endif
-}
-
-void PspMemory::testCopy(const byte *debugDst, const byte *debugSrc, uint32 debugBytes) {
-
- bool mismatch = false;
- PSP_INFO_PRINT("testing fastCopy...");
-
- for (uint32 i = 0; i < debugBytes; i++) {
- if (debugDst[i] != debugSrc[i]) {
- if (!mismatch) {
- PSP_INFO_PRINT("**** mismatch in copy! ****\n");
- PSP_INFO_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes);
- mismatch = true;
- }
- PSP_INFO_PRINT("[%d]%x!=%x ", i, debugSrc[i], debugDst[i]);
- }
- }
- if (mismatch) {
- PSP_INFO_PRINT("\n");
- } else {
- PSP_INFO_PRINT("ok\n");
- }
-}
-
-//
-// used to swap red and blue
-void PspMemory::swap(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) {
- DEBUG_ENTER_FUNC();
-
-#ifdef TEST_MEMORY_COPY
- uint32 debugBytes = bytes;
- const uint16 *debugDst = dst16, *debugSrc = src16;
#endif
-
- // align the destination pointer first
- uint32 prefixDst = (((uint32)dst16) & 0x3); // for swap, we can only have 2 or 0 as our prefix
-
- if (prefixDst) {
- bytes -= prefixDst; // remember we assume bytes > 4
- *dst16++ = format.swapRedBlue16(*src16++);
-
- if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) { // check if it's worthwhile to continue
- swap16(dst16, src16, bytes, format);
-
-#ifdef TEST_MEMORY_COPY
- testSwap(debugDst, debugSrc, debugBytes, format);
-#endif
- return;
- }
- }
-
- // check the source pointer alignment now
- uint32 alignSrc = (((uint32)src16) & 0x3);
-
- if (alignSrc) { // we'll need to realign our reads
- PSP_DEBUG_PRINT("misaligned copy of %u bytes from %p to %p\n", bytes, src16, dst16);
- swap32Misaligned((uint32 *)dst16, src16, bytes, format);
- } else {
- swap32Aligned((uint32 *)dst16, (const uint32 *)src16, bytes, format);
- }
-
-#ifdef TEST_MEMORY_COPY
- testSwap(debugDst, debugSrc, debugBytes, format);
-#endif
-
-}
-
-void PspMemory::testSwap(const uint16 *debugDst, const uint16 *debugSrc, uint32 debugBytes, PSPPixelFormat &format) {
-
- bool mismatch = false;
- PSP_INFO_PRINT("testing fastSwap...");
-
- uint32 shorts = debugBytes >> 1;
-
- for (uint32 i = 0; i < shorts; i++) {
- if (debugDst[i] != format.swapRedBlue16(debugSrc[i])) {
- if (!mismatch) {
- PSP_INFO_PRINT("**** mismatch in swap! ****\n");
- PSP_INFO_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes);
- mismatch = true;
- }
- PSP_INFO_PRINT("[%d]%x!=%x ", i<<1, format.swapRedBlue16(debugSrc[i]), debugDst[i]);
- }
- }
- if (mismatch) {
- PSP_INFO_PRINT("\n");
- } else {
- PSP_INFO_PRINT("ok\n");
- }
}
-
void PspMemory::copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes) {
PSP_DEBUG_PRINT("copy32Aligned(): dst32[%p], src32[%p], bytes[%d]\n", dst32, src32, bytes);
int words8 = bytes >> 5;
-
+
// try blocks of 8 words at a time
if (words8) {
while (words8--) {
@@ -217,11 +110,11 @@ void PspMemory::copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes)
dst32[7] = d;
dst32 += 8;
src32 += 8;
- }
+ }
}
-
+
int words4 = (bytes & 0x1F) >> 4;
-
+
// try blocks of 4 words at a time
if (words4) {
uint32 a, b, c, d;
@@ -236,10 +129,10 @@ void PspMemory::copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes)
dst32 += 4;
src32 += 4;
}
-
+
int bytesLeft = (bytes & 0xF); // only look at bytes left after we did the above
int wordsLeft = bytesLeft >> 2;
-
+
// now just do single words
while (wordsLeft) {
*dst32++ = *src32++;
@@ -252,55 +145,20 @@ void PspMemory::copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes)
byte *dst = (byte *)dst32;
byte *src = (byte *)src32;
-
+
while (bytesLeft--) {
*dst++ = *src++;
}
}
-void PspMemory::swap32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes, PSPPixelFormat &format) {
- DEBUG_ENTER_FUNC();
- int words4 = bytes >> 4;
-
- // try blocks of 4 words at a time
- while (words4--) {
- uint32 a, b, c, d;
- a = format.swapRedBlue32(src32[0]);
- b = format.swapRedBlue32(src32[1]);
- c = format.swapRedBlue32(src32[2]);
- d = format.swapRedBlue32(src32[3]);
- dst32[0] = a;
- dst32[1] = b;
- dst32[2] = c;
- dst32[3] = d;
- dst32 += 4;
- src32 += 4;
- }
-
- uint32 bytesLeft = bytes & 0xF;
- uint32 words = bytesLeft >> 2;
-
- // now just do words
- while (words--) {
- *dst32++ = format.swapRedBlue32(*src32++);
- }
-
- bytesLeft = bytes & 0x3;
-
- if (bytesLeft) { // for swap, can only be 1 short left
- *((uint16 *)dst32) = format.swapRedBlue16(*((uint16 *)src32));
- }
-}
-
-
// More challenging -- need to shift
// Assume dst is aligned
void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, uint32 alignSrc) {
PSP_DEBUG_PRINT("copy32Misaligned: dst32[%p], src[%p], bytes[%d], alignSrc[%d]\n", dst32, src, bytes, alignSrc);
-
+
uint32 *src32 = (uint32 *)(((uint32)src) & 0xFFFFFFFC); // remove misalignment
uint32 shiftValue, lastShiftValue;
-
+
switch (alignSrc) {
case 1:
shiftValue = 8;
@@ -320,9 +178,9 @@ void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, u
// Try to do groups of 4 words
uint32 words4 = bytes >> 4;
-
+
srcWord = *src32; // preload 1st word so we read ahead
-
+
for (; words4; words4--) {
dstWord = srcWord >> shiftValue;
srcWord = src32[1];
@@ -343,12 +201,12 @@ void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, u
src32 += 4;
dst32 += 4;
}
-
+
uint32 words = (bytes & 0xF) >> 2; // now get remaining words
-
+
// we read one word ahead of what we write
// setup the first read
-
+
for (; words ;words--) {
dstWord = srcWord >> shiftValue;
srcWord = src32[1]; // we still go one ahead
@@ -356,9 +214,9 @@ void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, u
dstWord |= srcWord << lastShiftValue;
*dst32++ = dstWord;
}
-
+
uint32 bytesLeft = bytes & 3; // and remaining bytes
-
+
if (bytesLeft) {
byte *dst8 = (byte *)dst32;
byte *src8 = ((byte *)src32) + ((uint32)src & 0x3); // get exact location we should be at
@@ -369,14 +227,137 @@ void PspMemory::copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, u
}
}
+void PspMemory::testCopy(const byte *debugDst, const byte *debugSrc, uint32 debugBytes) {
+
+ bool mismatch = false;
+ PSP_INFO_PRINT("testing fastCopy...");
+
+ for (uint32 i = 0; i < debugBytes; i++) {
+ if (debugDst[i] != debugSrc[i]) {
+ if (!mismatch) {
+ PSP_INFO_PRINT("**** mismatch in copy! ****\n");
+ PSP_INFO_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes);
+ mismatch = true;
+ }
+ PSP_INFO_PRINT("[%d]%x!=%x ", i, debugSrc[i], debugDst[i]);
+ }
+ }
+ if (mismatch) {
+ PSP_INFO_PRINT("\n");
+ } else {
+ PSP_INFO_PRINT("ok\n");
+ }
+}
+
+//
+// used to swap red and blue
+void PspMemorySwap::swap(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) {
+ DEBUG_ENTER_FUNC();
+
+#ifdef TEST_MEMORY_COPY
+ uint32 debugBytes = bytes;
+ const uint16 *debugDst = dst16, *debugSrc = src16;
+#endif
+
+ // align the destination pointer first
+ uint32 prefixDst = (((uint32)dst16) & 0x3); // for swap, we can only have 2 or 0 as our prefix
+
+ if (prefixDst) {
+ bytes -= prefixDst; // remember we assume bytes > 4
+ *dst16++ = format.swapRedBlue16(*src16++);
+
+ if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) { // check if it's worthwhile to continue
+ swap16(dst16, src16, bytes, format);
+
+#ifdef TEST_MEMORY_COPY
+ testSwap(debugDst, debugSrc, debugBytes, format);
+#endif
+ return;
+ }
+ }
+
+ // check the source pointer alignment now
+ uint32 alignSrc = (((uint32)src16) & 0x3);
+
+ if (alignSrc) { // we'll need to realign our reads
+ PSP_DEBUG_PRINT("misaligned copy of %u bytes from %p to %p\n", bytes, src16, dst16);
+ swap32Misaligned((uint32 *)dst16, src16, bytes, format);
+ } else {
+ swap32Aligned((uint32 *)dst16, (const uint32 *)src16, bytes, format);
+ }
+
+#ifdef TEST_MEMORY_COPY
+ testSwap(debugDst, debugSrc, debugBytes, format);
+#endif
+
+}
+
+void PspMemorySwap::testSwap(const uint16 *debugDst, const uint16 *debugSrc, uint32 debugBytes, PSPPixelFormat &format) {
+
+ bool mismatch = false;
+ PSP_INFO_PRINT("testing fastSwap...");
+
+ uint32 shorts = debugBytes >> 1;
+
+ for (uint32 i = 0; i < shorts; i++) {
+ if (debugDst[i] != format.swapRedBlue16(debugSrc[i])) {
+ if (!mismatch) {
+ PSP_INFO_PRINT("**** mismatch in swap! ****\n");
+ PSP_INFO_PRINT("dst[%p], src[%p], bytes[%u]\n", debugDst, debugSrc, debugBytes);
+ mismatch = true;
+ }
+ PSP_INFO_PRINT("[%d]%x!=%x ", i<<1, format.swapRedBlue16(debugSrc[i]), debugDst[i]);
+ }
+ }
+ if (mismatch) {
+ PSP_INFO_PRINT("\n");
+ } else {
+ PSP_INFO_PRINT("ok\n");
+ }
+}
+
+void PspMemorySwap::swap32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes, PSPPixelFormat &format) {
+ DEBUG_ENTER_FUNC();
+ int words4 = bytes >> 4;
+
+ // try blocks of 4 words at a time
+ while (words4--) {
+ uint32 a, b, c, d;
+ a = format.swapRedBlue32(src32[0]);
+ b = format.swapRedBlue32(src32[1]);
+ c = format.swapRedBlue32(src32[2]);
+ d = format.swapRedBlue32(src32[3]);
+ dst32[0] = a;
+ dst32[1] = b;
+ dst32[2] = c;
+ dst32[3] = d;
+ dst32 += 4;
+ src32 += 4;
+ }
+
+ uint32 bytesLeft = bytes & 0xF;
+ uint32 words = bytesLeft >> 2;
+
+ // now just do words
+ while (words--) {
+ *dst32++ = format.swapRedBlue32(*src32++);
+ }
+
+ bytesLeft = bytes & 0x3;
+
+ if (bytesLeft) { // for swap, can only be 1 short left
+ *((uint16 *)dst32) = format.swapRedBlue16(*((uint16 *)src32));
+ }
+}
+
// More challenging -- need to shift
// We assume dst is aligned
-void PspMemory::swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) {
+void PspMemorySwap::swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) {
DEBUG_ENTER_FUNC();
const uint32 shiftValue = 16;
uint32 *src32 = (uint32 *)(((uint32)src16) & 0xFFFFFFFC); // remove misalignment
-
+
// Try to do groups of 4 words
uint32 words4 = bytes >> 4;
uint32 srcWord = src32[0]; // preload
@@ -401,15 +382,15 @@ void PspMemory::swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 byte
src32 += 4;
dst32 += 4;
}
-
+
uint32 words = (bytes & 0xF) >> 2;
-
+
// we read one word ahead of what we write
// setup the first read
if (words) {
//srcWord = *src32++; // don't need this. already loaded
src32++; // we already have the value loaded in
-
+
while (words--) {
uint32 dstWord = srcWord >> shiftValue;
srcWord = *src32++;
@@ -417,86 +398,10 @@ void PspMemory::swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 byte
*dst32++ = format.swapRedBlue32(dstWord);
}
}
-
+
uint32 bytesLeft = bytes & 3;
-
+
if (bytesLeft) { // for swap, can only be 1 short left
*((uint16 *)dst32) = format.swapRedBlue16((uint16)(srcWord >> shiftValue));
}
}
-
-inline void PspMemory::copy16(uint16 *dst16, const uint16 *src16, uint32 bytes) {
- PSP_DEBUG_PRINT("copy16(): dst16[%p], src16[%p], bytes[%d]\n", dst16, src16, bytes);
-
- uint32 shorts = bytes >> 1;
- uint32 remainingBytes = bytes & 1;
-
- for (; shorts > 0 ; shorts--) {
- *dst16++ = *src16++;
- }
- if (remainingBytes)
- *(byte *)dst16 = *(byte *)src16;
-}
-
-// Class VramAllocator -----------------------------------
-
-DECLARE_SINGLETON(VramAllocator)
-
-//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
-//#define __PSP_DEBUG_PRINT__
-
-#include "backends/platform/psp/trace.h"
-
-
-void *VramAllocator::allocate(int32 size, bool smallAllocation /* = false */) {
- DEBUG_ENTER_FUNC();
- assert(size > 0);
-
- byte *lastAddress = smallAllocation ? (byte *)VRAM_SMALL_ADDRESS : (byte *)VRAM_START_ADDRESS;
- Common::List<Allocation>::iterator i;
-
- // Find a block that fits, starting from the beginning
- for (i = _allocList.begin(); i != _allocList.end(); ++i) {
- byte *currAddress = (*i).address;
-
- if (currAddress - lastAddress >= size) // We found a match
- break;
-
- if ((*i).getEnd() > lastAddress)
- lastAddress = (byte *)(*i).getEnd();
- }
-
- if (lastAddress + size > (byte *)VRAM_END_ADDRESS) {
- PSP_DEBUG_PRINT("No space for allocation of %d bytes. %d bytes already allocated.\n",
- size, _bytesAllocated);
- return NULL;
- }
-
- _allocList.insert(i, Allocation(lastAddress, size));
- _bytesAllocated += size;
-
- PSP_DEBUG_PRINT("Allocated in VRAM, size %u at %p.\n", size, lastAddress);
- PSP_DEBUG_PRINT("Total allocated %u, remaining %u.\n", _bytesAllocated, (2 * 1024 * 1024) - _bytesAllocated);
-
- return lastAddress;
-}
-
-// Deallocate a block from VRAM
-void VramAllocator::deallocate(void *address) {
- DEBUG_ENTER_FUNC();
- address = (byte *)CACHED(address); // Make sure all addresses are the same
-
- Common::List<Allocation>::iterator i;
-
- // Find the Allocator to deallocate
- for (i = _allocList.begin(); i != _allocList.end(); ++i) {
- if ((*i).address == address) {
- _bytesAllocated -= (*i).size;
- _allocList.erase(i);
- PSP_DEBUG_PRINT("Deallocated address[%p], size[%u]\n", (*i).address, (*i).size);
- return;
- }
- }
-
- PSP_DEBUG_PRINT("Address[%p] not allocated.\n", address);
-}
diff --git a/backends/platform/psp/memory.h b/backends/platform/psp/memory.h
index 793bc94888..54e9225b2e 100644
--- a/backends/platform/psp/memory.h
+++ b/backends/platform/psp/memory.h
@@ -27,18 +27,24 @@
#ifndef PSP_MEMORY_H
#define PSP_MEMORY_H
-#include "backends/platform/psp/psppixelformat.h"
-#include "common/list.h"
-
-#define UNCACHED(x) ((byte *)(((uint32)(x)) | 0x40000000)) /* make an uncached access */
-#define CACHED(x) ((byte *)(((uint32)(x)) & 0xBFFFFFFF)) /* make an uncached access into a cached one */
-
#define MIN_AMOUNT_FOR_COMPLEX_COPY 8
#define MIN_AMOUNT_FOR_MISALIGNED_COPY 8
//#define __PSP_DEBUG_PRINT__
-#include "backends/platform/psp/trace.h"
+//#include "backends/platform/psp/trace.h"
+
+// These instructions don't generate automatically but are faster then copying byte by byte
+inline void lwl_copy(byte *dst, const byte *src) {
+ register uint32 data;
+ asm volatile ("lwr %0,0(%1)\n\t"
+ "lwl %0,3(%1)\n\t"
+ : "=&r" (data) : "r" (src), "m" (*src));
+
+ asm volatile ("swr %1,0(%2)\n\t"
+ "swl %1,3(%2)\n\t"
+ : "=m" (*dst) : "r" (data), "r" (dst));
+}
/**
* Class that does memory copying and swapping if needed
@@ -46,42 +52,69 @@
class PspMemory {
private:
static void testCopy(const byte *debugDst, const byte *debugSrc, uint32 debugBytes);
- static void testSwap(const uint16 *debugDst, const uint16 *debugSrc, uint32 debugBytes, PSPPixelFormat &format);
static void copy(byte *dst, const byte *src, uint32 bytes);
- static void swap(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format);
static void copy32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes);
- static void swap32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes, PSPPixelFormat &format);
static void copy32Misaligned(uint32 *dst32, const byte *src, uint32 bytes, uint32 alignSrc);
- static void swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 bytes, PSPPixelFormat &format);
- static void copy16(uint16 *dst, const uint16 *src, uint32 bytes);
-
- // For swapping, we know that we have multiples of 16 bits
- static void swap16(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) {
- PSP_DEBUG_PRINT("swap16 called with dst16[%p], src16[%p], bytes[%d]\n", dst16, src16, bytes);
- uint32 shorts = bytes >> 1;
- while (shorts--) {
- *dst16++ = format.swapRedBlue16(*src16++);
+ static inline void copy8(byte *dst, const byte *src, int32 bytes) {
+ //PSP_DEBUG_PRINT("copy8 called with dst[%p], src[%p], bytes[%d]\n", dst, src, bytes);
+ uint32 words = bytes >> 2;
+ for (; words; words--) {
+ lwl_copy(dst, src);
+ dst += 4;
+ src += 4;
}
- }
-
- static void copy8(byte *dst, const byte *src, uint32 bytes) {
- PSP_DEBUG_PRINT("copy8 called with dst[%p], src[%p], bytes[%d]\n", dst, src, bytes);
- while (bytes--) {
+
+ uint32 bytesLeft = bytes & 0x3;
+ for (; bytesLeft; bytesLeft--) {
*dst++ = *src++;
}
}
-public:
+public:
// This is the interface to the outside world
- static void fastCopy(byte *dst, const byte *src, uint32 bytes) {
+ static void *fastCopy(void *dstv, const void *srcv, int32 bytes) {
+ byte *dst = (byte *)dstv;
+ byte *src = (byte *)srcv;
+
if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY) {
copy8(dst, src, bytes);
} else { // go to more powerful copy
copy(dst, src, bytes);
}
+
+ return dstv;
}
+};
+
+inline void *psp_memcpy(void *dst, const void *src, int32 bytes) {
+ return PspMemory::fastCopy(dst, src, bytes);
+}
+
+#endif /* PSP_MEMORY_H */
+
+#if defined(PSP_INCLUDE_SWAP) && !defined(PSP_MEMORY_SWAP_H)
+#define PSP_MEMORY_SWAP_H
+//#include "backends/platform/psp/psppixelformat.h"
+
+class PspMemorySwap {
+private:
+ static void testSwap(const uint16 *debugDst, const uint16 *debugSrc, uint32 debugBytes, PSPPixelFormat &format);
+ static void swap(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format);
+ static void swap32Aligned(uint32 *dst32, const uint32 *src32, uint32 bytes, PSPPixelFormat &format);
+ static void swap32Misaligned(uint32 *dst32, const uint16 *src16, uint32 bytes, PSPPixelFormat &format);
+ // For swapping, we know that we have multiples of 16 bits
+ static void swap16(uint16 *dst16, const uint16 *src16, uint32 bytes, PSPPixelFormat &format) {
+ PSP_DEBUG_PRINT("swap16 called with dst16[%p], src16[%p], bytes[%d]\n", dst16, src16, bytes);
+ uint32 shorts = bytes >> 1;
+
+ while (shorts--) {
+ *dst16++ = format.swapRedBlue16(*src16++);
+ }
+}
+
+public:
static void fastSwap(byte *dst, const byte *src, uint32 bytes, PSPPixelFormat &format) {
if (bytes < MIN_AMOUNT_FOR_COMPLEX_COPY * 2) {
swap16((uint16 *)dst, (uint16 *)src, bytes, format);
@@ -91,41 +124,6 @@ public:
}
};
-/**
- * Class that allocates memory in the VRAM
- */
-class VramAllocator : public Common::Singleton<VramAllocator> {
-public:
- VramAllocator() : _bytesAllocated(0) {}
- void *allocate(int32 size, bool smallAllocation = false); // smallAllocation e.g. palettes
- void deallocate(void *pointer);
-
- static inline bool isAddressInVram(void *address) {
- if ((uint32)(CACHED(address)) >= VRAM_START_ADDRESS && (uint32)(CACHED(address)) < VRAM_END_ADDRESS)
- return true;
- return false;
- }
-
+#endif /* PSP_INCLUDE_SWAP */
-private:
- /**
- * Used to allocate in VRAM
- */
- struct Allocation {
- byte *address;
- uint32 size;
- void *getEnd() { return address + size; }
- Allocation(void *Address, uint32 Size) : address((byte *)Address), size(Size) {}
- Allocation() : address(0), size(0) {}
- };
-
- enum {
- VRAM_START_ADDRESS = 0x04000000,
- VRAM_END_ADDRESS = 0x04200000,
- VRAM_SMALL_ADDRESS = VRAM_END_ADDRESS - (4 * 1024) // 4K in the end for small allocations
- };
- Common::List <Allocation> _allocList; // List of allocations
- uint32 _bytesAllocated;
-};
-#endif /* PSP_MEMORY_H */
diff --git a/backends/platform/psp/module.mk b/backends/platform/psp/module.mk
index a854ec1252..e3eac153dd 100644
--- a/backends/platform/psp/module.mk
+++ b/backends/platform/psp/module.mk
@@ -16,7 +16,10 @@ MODULE_OBJS := powerman.o \
thread.o \
rtc.o \
mp3.o \
- tests.o
+ png_loader.o \
+ image_viewer.o \
+ tests.o \
+ dummy.o
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
diff --git a/backends/platform/psp/mp3.cpp b/backends/platform/psp/mp3.cpp
index 98e8a0404b..0e88418f13 100644
--- a/backends/platform/psp/mp3.cpp
+++ b/backends/platform/psp/mp3.cpp
@@ -38,13 +38,13 @@
#include <pspsysmem.h>
#include <pspmodulemgr.h>
#include <psputility_avmodules.h>
-#include <mad.h>
+#include <mad.h>
#include "backends/platform/psp/mp3.h"
//#define DISABLE_PSP_MP3 // to make us use the regular MAD decoder instead
//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
-//#define __PSP_DEBUG_PRINT__
+//#define __PSP_DEBUG_PRINT__
#include "backends/platform/psp/trace.h"
//#define PRINT_BUFFERS /* to debug MP3 buffers */
@@ -77,7 +77,7 @@ enum {
bool Mp3PspStream::initDecoder() {
DEBUG_ENTER_FUNC();
-
+
if (_decoderInit) {
PSP_ERROR("Already initialized!");
return true;
@@ -97,15 +97,15 @@ bool Mp3PspStream::initDecoder() {
PSP_ERROR("failed to load audiocodec.prx. ME cannot start.\n");
_decoderFail = true;
return false;
- }
- } else {
+ }
+ } else {
if (sceUtilityLoadAvModule(PSP_AV_MODULE_AVCODEC) < 0) {
PSP_ERROR("failed to load AVCODEC module. ME cannot start.\n");
_decoderFail = true;
return false;
}
}
-
+
PSP_DEBUG_PRINT("Using PSP's ME for MP3\n"); // important to know this is happening
_decoderInit = true;
@@ -114,10 +114,10 @@ bool Mp3PspStream::initDecoder() {
bool Mp3PspStream::stopDecoder() {
DEBUG_ENTER_FUNC();
-
+
if (!_decoderInit)
return true;
-
+
// Based on PSP firmware version, we need to do different things to do Media Engine processing
if (sceKernelDevkitVersion() == 0x01050001){ // TODO: how do we unload?
/* if (!unloadAudioModule("flash0:/kd/me_for_vsh.prx", PSP_MEMORY_PARTITION_KERNEL) ||
@@ -130,10 +130,10 @@ bool Mp3PspStream::stopDecoder() {
if (sceUtilityUnloadModule(PSP_MODULE_AV_AVCODEC) < 0) {
PSP_ERROR("failed to unload avcodec module\n");
return false;
- }
+ }
}
-
- _decoderInit = false;
+
+ _decoderInit = false;
return true;
}
@@ -176,26 +176,27 @@ Mp3PspStream::Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse
_length(0, 1000),
_sampleRate(0),
_totalTime(mad_timer_zero) {
-
+
DEBUG_ENTER_FUNC();
assert(_decoderInit); // must be initialized by now
-
+
// let's leave the buffer guard -- who knows, it may be good?
memset(_buf, 0, sizeof(_buf));
memset(_codecInBuffer, 0, sizeof(_codecInBuffer));
-
+
initStream(); // init needed stuff for the stream
findValidHeader(); // get a first header so we can read basic stuff
-
+
_sampleRate = _header.samplerate; // copy it before it gets destroyed
-
+ _stereo = (MAD_NCHANNELS(&_header) == 2);
+
while (_state != MP3_STATE_EOS)
findValidHeader(); // get a first header so we can read basic stuff
-
+
_length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate());
-
+
deinitStream();
_state = MP3_STATE_INIT;
@@ -221,7 +222,7 @@ int Mp3PspStream::initStream() {
// Read the first few sample bytes into the buffer
readMP3DataIntoBuffer();
-
+
return true;
}
@@ -229,7 +230,7 @@ bool Mp3PspStream::initStreamME() {
// The following will eventually go into the thread
memset(_codecParams, 0, sizeof(_codecParams));
-
+
// Init the MP3 hardware
int ret = 0;
ret = sceAudiocodecCheckNeedMem(_codecParams, 0x1002);
@@ -244,22 +245,22 @@ bool Mp3PspStream::initStreamME() {
return false;
}
PSP_DEBUG_PRINT("sceAudioCodecGetEDRAM returned %d\n", ret);
-
+
PSP_DEBUG_PRINT("samplerate[%d]\n", _sampleRate);
_codecParams[10] = _sampleRate;
-
+
ret = sceAudiocodecInit(_codecParams, 0x1002);
if (ret < 0) {
PSP_ERROR("failed to init MP3 ME module. sceAudiocodecInit returned 0x%x.\n", ret);
return false;
}
-
+
return true;
}
Mp3PspStream::~Mp3PspStream() {
DEBUG_ENTER_FUNC();
-
+
deinitStream();
releaseStreamME(); // free the memory used for this stream
@@ -276,17 +277,17 @@ void Mp3PspStream::deinitStream() {
// Deinit MAD
mad_header_finish(&_header);
mad_stream_finish(&_stream);
-
+
_state = MP3_STATE_EOS;
}
void Mp3PspStream::releaseStreamME() {
sceAudiocodecReleaseEDRAM(_codecParams);
-}
+}
void Mp3PspStream::decodeMP3Data() {
DEBUG_ENTER_FUNC();
-
+
do {
if (_state == MP3_STATE_INIT) {
initStream();
@@ -295,17 +296,17 @@ void Mp3PspStream::decodeMP3Data() {
if (_state == MP3_STATE_EOS)
return;
-
+
findValidHeader(); // seach for next valid header
while (_state == MP3_STATE_READY) { // not a real 'while'. Just for easy flow
_stream.error = MAD_ERROR_NONE;
uint32 frame_size = _stream.next_frame - _stream.this_frame;
-
- updatePcmLength(); // Retrieve the number of PCM samples.
+
+ updatePcmLength(); // Retrieve the number of PCM samples.
// We seem to change this, so it needs to be dynamic
-
+
PSP_DEBUG_PRINT("MP3 frame size[%d]. pcmLength[%d]\n", frame_size, _pcmLength);
memcpy(_codecInBuffer, _stream.this_frame, frame_size); // we need it aligned
@@ -315,7 +316,7 @@ void Mp3PspStream::decodeMP3Data() {
_codecParams[8] = (unsigned long)_pcmSamples;
_codecParams[7] = frame_size;
_codecParams[9] = _pcmLength * 2; // x2 for stereo, though this one's not so important
-
+
// debug
#ifdef PRINT_BUFFERS
PSP_DEBUG_PRINT("mp3 frame:\n");
@@ -415,10 +416,13 @@ bool Mp3PspStream::seek(const Timestamp &where) {
mad_timer_t destination;
mad_timer_set(&destination, time / 1000, time % 1000, 1000);
+ // Important to release and re-init the ME
+ releaseStreamME();
+ initStreamME();
+
// Check if we need to rewind
if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0) {
initStream();
- initStreamME();
}
// Skip ahead
@@ -469,38 +473,38 @@ int Mp3PspStream::readBuffer(int16 *buffer, const int numSamples) {
DEBUG_ENTER_FUNC();
int samples = 0;
-#ifdef PRINT_BUFFERS
+#ifdef PRINT_BUFFERS
int16 *debugBuffer = buffer;
-#endif
-
+#endif
+
// Keep going as long as we have input available
while (samples < numSamples && _state != MP3_STATE_EOS) {
const int len = MIN(numSamples, samples + (int)(_pcmLength - _posInFrame) * MAD_NCHANNELS(&_header));
-
+
while (samples < len) {
*buffer++ = _pcmSamples[_posInFrame << 1];
samples++;
if (MAD_NCHANNELS(&_header) == 2) {
*buffer++ = _pcmSamples[(_posInFrame << 1) + 1];
samples++;
- }
+ }
_posInFrame++; // always skip an extra sample since ME always outputs stereo
}
-
+
if (_posInFrame >= _pcmLength) {
// We used up all PCM data in the current frame -- read & decode more
decodeMP3Data();
}
}
-
+
#ifdef PRINT_BUFFERS
PSP_INFO_PRINT("buffer:\n");
for (int i = 0; i<numSamples; i++)
PSP_INFO_PRINT("%d ", debugBuffer[i]);
PSP_INFO_PRINT("\n\n");
-#endif
-
+#endif
+
return samples;
}
-} // End of namespace Audio \ No newline at end of file
+} // End of namespace Audio
diff --git a/backends/platform/psp/mp3.h b/backends/platform/psp/mp3.h
index 983f4cb7f4..1d2fe5ec2f 100644
--- a/backends/platform/psp/mp3.h
+++ b/backends/platform/psp/mp3.h
@@ -53,29 +53,30 @@ protected:
Common::SeekableReadStream *_inStream;
DisposeAfterUse::Flag _disposeAfterUse;
-
+
uint32 _pcmLength; // how many pcm samples we have for this type of file (x2 this for stereo)
-
+
uint _posInFrame; // position in frame
State _state; // what state the stream is in
Timestamp _length;
uint32 _sampleRate;
+ bool _stereo;
mad_timer_t _totalTime;
mad_stream _stream; //
mad_header _header; // This is all we need from libmad
-
+
static bool _decoderInit; // has the decoder been initialized
static bool _decoderFail; // has the decoder failed to load
-
+
enum {
BUFFER_SIZE = 5 * 8192
};
// This buffer contains a slab of input data
byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD];
-
+
void decodeMP3Data();
void readMP3DataIntoBuffer();
@@ -84,19 +85,19 @@ protected:
void findValidHeader();
void deinitStream();
void updatePcmLength();
-
+
// to init and uninit ME decoder
static bool initDecoder();
static bool stopDecoder();
-
+
// ME functions for stream
bool initStreamME();
void releaseStreamME();
-
+
public:
Mp3PspStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose);
~Mp3PspStream();
-
+
// This function avoids having to create streams when it's not possible
static inline bool isOkToCreateStream() {
if (_decoderFail) // fatal failure
@@ -104,13 +105,13 @@ public:
if (!_decoderInit) // if we're not initialized
if (!initDecoder()) // check if we failed init
return false;
- return true;
+ return true;
}
int readBuffer(int16 *buffer, const int numSamples);
bool endOfData() const { return _state == MP3_STATE_EOS; }
- bool isStereo() const { return MAD_NCHANNELS(&_header) == 2; }
+ bool isStereo() const { return _stereo; }
int getRate() const { return _sampleRate; }
bool seek(const Timestamp &where);
diff --git a/backends/platform/psp/osys_psp.cpp b/backends/platform/psp/osys_psp.cpp
index b09d9c0c00..40c074ae00 100644
--- a/backends/platform/psp/osys_psp.cpp
+++ b/backends/platform/psp/osys_psp.cpp
@@ -67,7 +67,7 @@ void OSystem_PSP::initBackend() {
// Instantiate real time clock
PspRtc::instance();
-
+
_cursor.enableCursorPalette(false);
_cursor.setXY(PSP_SCREEN_WIDTH >> 1, PSP_SCREEN_HEIGHT >> 1); // Mouse in the middle of the screen
@@ -76,12 +76,18 @@ void OSystem_PSP::initBackend() {
_displayManager.setScreen(&_screen);
_displayManager.setOverlay(&_overlay);
_displayManager.setKeyboard(&_keyboard);
+ _displayManager.setImageViewer(&_imageViewer);
_displayManager.init();
// Set pointers for input handler
_inputHandler.setCursor(&_cursor);
_inputHandler.setKeyboard(&_keyboard);
+ _inputHandler.setImageViewer(&_imageViewer);
_inputHandler.init();
+
+ // Set pointers for image viewer
+ _imageViewer.setInputHandler(&_inputHandler);
+ _imageViewer.setDisplayManager(&_displayManager);
_savefile = new PSPSaveFileManager;
@@ -97,6 +103,12 @@ void OSystem_PSP::initBackend() {
OSystem::initBackend();
}
+// Let's us know an engine
+void OSystem_PSP::engineDone() {
+ // for now, all we need is to reset the image number on the viewer
+ _imageViewer.resetOnEngineDone();
+}
+
bool OSystem_PSP::hasFeature(Feature f) {
return (f == kFeatureOverlaySupportsAlpha || f == kFeatureCursorHasPalette);
}
@@ -148,7 +160,7 @@ Common::List<Graphics::PixelFormat> OSystem_PSP::getSupportedFormats() const {
void OSystem_PSP::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
_displayManager.setSizeAndPixelFormat(width, height, format);
_cursor.setVisible(false);
@@ -167,7 +179,7 @@ int16 OSystem_PSP::getHeight() {
void OSystem_PSP::setPalette(const byte *colors, uint start, uint num) {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
_screen.setPartialPalette(colors, start, num);
_cursor.setScreenPalette(colors, start, num);
_cursor.clearKeyColor();
@@ -175,7 +187,7 @@ void OSystem_PSP::setPalette(const byte *colors, uint start, uint num) {
void OSystem_PSP::setCursorPalette(const byte *colors, uint start, uint num) {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
_cursor.setCursorPalette(colors, start, num);
_cursor.enableCursorPalette(true);
_cursor.clearKeyColor(); // Do we need this?
@@ -183,25 +195,25 @@ void OSystem_PSP::setCursorPalette(const byte *colors, uint start, uint num) {
void OSystem_PSP::disableCursorPalette(bool disable) {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
_cursor.enableCursorPalette(!disable);
}
void OSystem_PSP::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
_screen.copyFromRect(buf, pitch, x, y, w, h);
}
Graphics::Surface *OSystem_PSP::lockScreen() {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
return _screen.lockAndGetForEditing();
}
void OSystem_PSP::unlockScreen() {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
// The screen is always completely updated anyway, so we don't have to force a full update here.
_screen.unlock();
}
@@ -219,7 +231,7 @@ void OSystem_PSP::setShakePos(int shakeOffset) {
void OSystem_PSP::showOverlay() {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
_overlay.setVisible(true);
_cursor.setLimits(_overlay.getWidth(), _overlay.getHeight());
_cursor.useGlobalScaler(false); // mouse with overlay is 1:1
@@ -227,7 +239,7 @@ void OSystem_PSP::showOverlay() {
void OSystem_PSP::hideOverlay() {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
_overlay.setVisible(false);
_cursor.setLimits(_screen.getWidth(), _screen.getHeight());
_cursor.useGlobalScaler(true); // mouse needs to be scaled with screen
@@ -235,7 +247,7 @@ void OSystem_PSP::hideOverlay() {
void OSystem_PSP::clearOverlay() {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
_overlay.clearBuffer();
}
@@ -246,7 +258,7 @@ void OSystem_PSP::grabOverlay(OverlayColor *buf, int pitch) {
void OSystem_PSP::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
_overlay.copyFromRect(buf, pitch, x, y, w, h);
}
@@ -266,7 +278,7 @@ void OSystem_PSP::grabPalette(byte *colors, uint start, uint num) {
bool OSystem_PSP::showMouse(bool v) {
DEBUG_ENTER_FUNC();
_pendingUpdate = false;
-
+
PSP_DEBUG_PRINT("%s\n", v ? "true" : "false");
bool last = _cursor.isVisible();
_cursor.setVisible(v);
@@ -276,14 +288,14 @@ bool OSystem_PSP::showMouse(bool v) {
void OSystem_PSP::warpMouse(int x, int y) {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
+ _pendingUpdate = false;
_cursor.setXY(x, y);
}
void OSystem_PSP::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) {
DEBUG_ENTER_FUNC();
- _pendingUpdate = false;
-
+ _pendingUpdate = false;
+
PSP_DEBUG_PRINT("pbuf[%p], w[%u], h[%u], hotspot:X[%d], Y[%d], keycolor[%d], scale[%d], pformat[%p]\n", buf, w, h, hotspotX, hotspotY, keycolor, cursorTargetScale, format);
if (format) {
PSP_DEBUG_PRINT("format: bpp[%d], rLoss[%d], gLoss[%d], bLoss[%d], aLoss[%d], rShift[%d], gShift[%d], bShift[%d], aShift[%d]\n", format->bytesPerPixel, format->rLoss, format->gLoss, format->bLoss, format->aLoss, format->rShift, format->gShift, format->bShift, format->aShift);
@@ -310,16 +322,16 @@ bool OSystem_PSP::pollEvent(Common::Event &event) {
// Time between event polls is usually 5-10ms, so waiting for 4 calls before checking to update the screen should be fine
if (_pendingUpdate) {
_pendingUpdateCounter++;
-
+
if (_pendingUpdateCounter >= 4) {
PSP_DEBUG_PRINT("servicing pending update\n");
updateScreen();
if (!_pendingUpdate) // we handled the update
- _pendingUpdateCounter = 0;
+ _pendingUpdateCounter = 0;
}
- } else
+ } else
_pendingUpdateCounter = 0; // reset the counter, no pending
-
+
return _inputHandler.getAllInputs(event);
}
diff --git a/backends/platform/psp/osys_psp.h b/backends/platform/psp/osys_psp.h
index 5721296c94..52b8f4e887 100644
--- a/backends/platform/psp/osys_psp.h
+++ b/backends/platform/psp/osys_psp.h
@@ -32,10 +32,12 @@
#include "sound/mixer_intern.h"
#include "backends/base-backend.h"
#include "backends/fs/psp/psp-fs-factory.h"
+
#include "backends/platform/psp/display_client.h"
#include "backends/platform/psp/default_display_client.h"
#include "backends/platform/psp/cursor.h"
#include "backends/platform/psp/pspkeyboard.h"
+#include "backends/platform/psp/image_viewer.h"
#include "backends/platform/psp/display_manager.h"
#include "backends/platform/psp/input.h"
#include "backends/platform/psp/audio.h"
@@ -60,6 +62,7 @@ private:
InputHandler _inputHandler;
PspAudio _audio;
PspTimer _pspTimer;
+ ImageViewer _imageViewer;
public:
OSystem_PSP() : _savefile(0), _mixer(0), _timer(0), _pendingUpdate(false), _pendingUpdateCounter(0) {}
@@ -146,6 +149,7 @@ public:
Common::SaveFileManager *getSavefileManager() { return _savefile; }
FilesystemFactory *getFilesystemFactory() { return &PSPFilesystemFactory::instance(); }
void getTimeAndDate(TimeDate &t) const;
+ virtual void engineDone();
void quit();
diff --git a/backends/platform/psp/png_loader.cpp b/backends/platform/psp/png_loader.cpp
new file mode 100644
index 0000000000..08f370f36d
--- /dev/null
+++ b/backends/platform/psp/png_loader.cpp
@@ -0,0 +1,210 @@
+/* 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$
+ *
+ */
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+#include "backends/platform/psp/psppixelformat.h"
+#include "backends/platform/psp/display_client.h"
+#include "backends/platform/psp/png_loader.h"
+
+//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
+//#define __PSP_DEBUG_PRINT__ /* For debug printouts */
+
+#include "backends/platform/psp/trace.h"
+
+PngLoader::Status PngLoader::allocate() {
+ DEBUG_ENTER_FUNC();
+
+ if (!findImageDimensions()) {
+ PSP_ERROR("failed to get image dimensions\n");
+ return BAD_FILE;
+ }
+
+ _buffer->setSize(_width, _height, _sizeBy);
+
+ uint32 bitsPerPixel = _bitDepth * _channels;
+
+ if (_paletteSize) { // 8 or 4-bit image
+ if (bitsPerPixel == 4) {
+ _buffer->setPixelFormat(PSPPixelFormat::Type_Palette_4bit);
+ _palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_4bit);
+ _paletteSize = 16; // round up
+ } else if (bitsPerPixel == 8) { // 8-bit image
+ _buffer->setPixelFormat(PSPPixelFormat::Type_Palette_8bit);
+ _palette->setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_8bit);
+ _paletteSize = 256; // round up
+ } else {
+ PSP_ERROR("too many bits per pixel[%d] for a palette\n", bitsPerPixel);
+ return BAD_FILE;
+ }
+
+ } else { // 32-bit image
+ _buffer->setPixelFormat(PSPPixelFormat::Type_8888);
+ }
+
+ if (!_buffer->allocate()) {
+ PSP_ERROR("failed to allocate buffer\n");
+ return OUT_OF_MEMORY;
+ }
+ if (_buffer->hasPalette() && !_palette->allocate()) {
+ PSP_ERROR("failed to allocate palette\n");
+ return OUT_OF_MEMORY;
+ }
+ return OK;
+}
+
+bool PngLoader::load() {
+ DEBUG_ENTER_FUNC();
+ // Try to load the image
+ _file->seek(0); // Go back to start
+
+ if (!loadImageIntoBuffer()) {
+ PSP_DEBUG_PRINT("failed to load image\n");
+ return false;
+ }
+
+ PSP_DEBUG_PRINT("succeded in loading image\n");
+
+ if (_paletteSize == 16) // 4-bit
+ _buffer->flipNibbles(); // required because of PNG 4-bit format
+ return true;
+}
+
+void PngLoader::warningFn(png_structp png_ptr, png_const_charp warning_msg) {
+ // ignore PNG warnings
+}
+
+// Read function for png library to be able to read from our SeekableReadStream
+//
+void PngLoader::libReadFunc(png_structp pngPtr, png_bytep data, png_size_t length) {
+ Common::SeekableReadStream *file;
+
+ file = (Common::SeekableReadStream *)pngPtr->io_ptr;
+
+ file->read(data, length);
+}
+
+bool PngLoader::basicImageLoad() {
+ DEBUG_ENTER_FUNC();
+ _pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!_pngPtr)
+ return false;
+
+ png_set_error_fn(_pngPtr, (png_voidp) NULL, (png_error_ptr) NULL, warningFn);
+
+ _infoPtr = png_create_info_struct(_pngPtr);
+ if (!_infoPtr) {
+ png_destroy_read_struct(&_pngPtr, png_infopp_NULL, png_infopp_NULL);
+ return false;
+ }
+ // Set the png lib to use our read function
+ png_set_read_fn(_pngPtr, (void *)_file, libReadFunc);
+
+ unsigned int sig_read = 0;
+
+ png_set_sig_bytes(_pngPtr, sig_read);
+ png_read_info(_pngPtr, _infoPtr);
+ int interlaceType;
+ png_get_IHDR(_pngPtr, _infoPtr, (png_uint_32 *)&_width, (png_uint_32 *)&_height, &_bitDepth,
+ &_colorType, &interlaceType, int_p_NULL, int_p_NULL);
+ _channels = png_get_channels(_pngPtr, _infoPtr);
+
+ if (_colorType & PNG_COLOR_MASK_PALETTE)
+ _paletteSize = _infoPtr->num_palette;
+
+ return true;
+}
+
+/* Get the width and height of a png image */
+bool PngLoader::findImageDimensions() {
+ DEBUG_ENTER_FUNC();
+
+ bool status = basicImageLoad();
+
+ PSP_DEBUG_PRINT("width[%d], height[%d], paletteSize[%d], bitDepth[%d], channels[%d], rowBytes[%d]\n", _width, _height, _paletteSize, _bitDepth, _channels, _infoPtr->rowbytes);
+ png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL);
+ return status;
+}
+
+//
+// Load a texture from a png image
+//
+bool PngLoader::loadImageIntoBuffer() {
+ DEBUG_ENTER_FUNC();
+
+ if (!basicImageLoad()) {
+ png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL);
+ return false;
+ }
+ png_set_strip_16(_pngPtr); // Strip off 16 bit channels in case they occur
+
+ if (_paletteSize) {
+ // Copy the palette
+ png_colorp srcPal = _infoPtr->palette;
+ for (int i = 0; i < _infoPtr->num_palette; i++) {
+ unsigned char alphaVal = (i < _infoPtr->num_trans) ? _infoPtr->trans[i] : 0xFF; // Load alpha if it's there
+ _palette->setSingleColorRGBA(i, srcPal->red, srcPal->green, srcPal->blue, alphaVal);
+ srcPal++;
+ }
+ } else { // Not a palettized image
+ if (_colorType == PNG_COLOR_TYPE_GRAY && _bitDepth < 8)
+ png_set_gray_1_2_4_to_8(_pngPtr); // Round up grayscale images
+ if (png_get_valid(_pngPtr, _infoPtr, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha(_pngPtr); // Convert trans channel to alpha for 32 bits
+
+ png_set_add_alpha(_pngPtr, 0xff, PNG_FILLER_AFTER); // Filler for alpha if none exists
+ }
+
+ uint32 rowBytes = png_get_rowbytes(_pngPtr, _infoPtr);
+
+ // there seems to be a bug in libpng where it doesn't increase the rowbytes or the
+ // channel even after we add the alpha channel
+ if (_channels == 3 && (rowBytes / _width) == 3) {
+ _channels = 4;
+ rowBytes = _width * _channels;
+ }
+
+ PSP_DEBUG_PRINT("rowBytes[%d], channels[%d]\n", rowBytes, _channels);
+
+ unsigned char *line = (unsigned char*) malloc(rowBytes);
+ if (!line) {
+ png_destroy_read_struct(&_pngPtr, png_infopp_NULL, png_infopp_NULL);
+ PSP_ERROR("Couldn't allocate line\n");
+ return false;
+ }
+
+ for (size_t y = 0; y < _height; y++) {
+ png_read_row(_pngPtr, line, png_bytep_NULL);
+ _buffer->copyFromRect(line, rowBytes, 0, y, _width, 1); // Copy into buffer
+ }
+ free(line);
+ png_read_end(_pngPtr, _infoPtr);
+ png_destroy_read_struct(&_pngPtr, &_infoPtr, png_infopp_NULL);
+
+ return true;
+}
diff --git a/backends/platform/psp/png_loader.h b/backends/platform/psp/png_loader.h
new file mode 100644
index 0000000000..4119bfef2b
--- /dev/null
+++ b/backends/platform/psp/png_loader.h
@@ -0,0 +1,74 @@
+/* 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$
+ *
+ */
+
+#ifndef PSP_PNG_IMAGE_H
+#define PSP_PNG_IMAGE_H
+
+#include <png.h>
+
+class PngLoader {
+private:
+ bool basicImageLoad(); // common operation
+ bool findImageDimensions(); // find dimensions of a given PNG file
+ bool loadImageIntoBuffer();
+
+ static void warningFn(png_structp png_ptr, png_const_charp warning_msg);
+ static void libReadFunc(png_structp pngPtr, png_bytep data, png_size_t length);
+
+ Common::SeekableReadStream *_file;
+ Buffer *_buffer;
+ Palette *_palette;
+
+ uint32 _width;
+ uint32 _height;
+ uint32 _paletteSize;
+ Buffer::HowToSize _sizeBy;
+
+ // PNG lib values
+ int _bitDepth;
+ png_structp _pngPtr;
+ png_infop _infoPtr;
+ int _colorType;
+ uint32 _channels;
+
+public:
+ enum Status {
+ OK,
+ OUT_OF_MEMORY,
+ BAD_FILE
+ };
+
+ PngLoader(Common::SeekableReadStream *file, Buffer &buffer, Palette &palette,
+ Buffer::HowToSize sizeBy = Buffer::kSizeByTextureSize) :
+ _file(file), _buffer(&buffer), _palette(&palette),
+ _width(0), _height(0), _paletteSize(0),
+ _bitDepth(0), _sizeBy(sizeBy), _pngPtr(0),
+ _infoPtr(0), _colorType(0), _channels(0) {}
+
+ PngLoader::Status allocate();
+ bool load();
+};
+
+#endif /* PSP_PNG_IMAGE_H */
diff --git a/backends/platform/psp/powerman.cpp b/backends/platform/psp/powerman.cpp
index eaadad16c5..869d9b3023 100644
--- a/backends/platform/psp/powerman.cpp
+++ b/backends/platform/psp/powerman.cpp
@@ -84,7 +84,7 @@ bool PowerManager::unregisterForSuspend(Suspendable *item) {
// Unregister from stream list
_listMutex.lock();
-
+
_suspendList.remove(item);
_listCounter--;
@@ -114,11 +114,11 @@ PowerManager::~PowerManager() {
********************************************/
void PowerManager::pollPauseEngine() {
DEBUG_ENTER_FUNC();
-
-
+
+
bool pause = _pauseFlag; // We copy so as not to have multiple values
- if (pause != _pauseFlagOld) {
+ if (pause != _pauseFlagOld) {
if (g_engine) { // Check to see if we have an engine
if (pause && _pauseClientState == UNPAUSED) {
_pauseClientState = PAUSING; // Tell PM we're in the middle of pausing
@@ -147,7 +147,7 @@ bool PowerManager::beginCriticalSection() {
DEBUG_ENTER_FUNC();
bool ret = false;
-
+
_flagMutex.lock();
// Check the access flag
@@ -156,7 +156,7 @@ bool PowerManager::beginCriticalSection() {
PSP_DEBUG_PRINT("I got blocked. ThreadId[%x]\n", sceKernelGetThreadId());
debugPM();
-
+
_threadSleep.wait(_flagMutex);
PSP_DEBUG_PRINT_FUNC("I got released. ThreadId[%x]\n", sceKernelGetThreadId());
@@ -184,11 +184,11 @@ void PowerManager::endCriticalSection() {
if (_suspendFlag) { // If the PM is sleeping, this flag must be set
PSP_DEBUG_PRINT_FUNC("PM is asleep. Waking it up.\n");
debugPM();
-
+
_pmSleep.releaseAll();
-
+
PSP_DEBUG_PRINT_FUNC("Woke up the PM\n");
-
+
debugPM();
}
@@ -198,7 +198,7 @@ void PowerManager::endCriticalSection() {
}
}
- _flagMutex.unlock();
+ _flagMutex.unlock();
}
/*******************************************
@@ -209,7 +209,7 @@ void PowerManager::endCriticalSection() {
void PowerManager::suspend() {
DEBUG_ENTER_FUNC();
- if (_pauseFlag)
+ if (_pauseFlag)
return; // Very important - make sure we only suspend once
scePowerLock(0); // Also critical to make sure PSP doesn't suspend before we're done
@@ -232,9 +232,9 @@ void PowerManager::suspend() {
PspThread::delayMicros(50000); // We wait 50 msec at a time
}
- // It's possible that the polling thread missed our pause event, but there's
+ // It's possible that the polling thread missed our pause event, but there's
// nothing we can do about that.
- // We can't know if there's polling going on or not.
+ // We can't know if there's polling going on or not.
// It's usually not a critical thing anyway.
_PMStatus = kGettingFlagMutexSuspend;
@@ -249,12 +249,12 @@ void PowerManager::suspend() {
// Check if anyone is in a critical section. If so, we'll wait for them
if (_criticalCounter > 0) {
_PMStatus = kWaitCritSectionSuspend;
-
+
_pmSleep.wait(_flagMutex);
-
+
_PMStatus = kDoneWaitingCritSectionSuspend;
- }
-
+ }
+
_flagMutex.unlock();
_PMStatus = kGettingListMutexSuspend;
@@ -275,7 +275,7 @@ void PowerManager::suspend() {
_PMStatus = kDoneSuspend;
scePowerUnlock(0); // Allow the PSP to go to sleep now
-
+
_PMStatus = kDonePowerUnlock;
}
@@ -286,22 +286,22 @@ void PowerManager::suspend() {
********************************************/
void PowerManager::resume() {
DEBUG_ENTER_FUNC();
-
+
_PMStatus = kBeginResume;
// Make sure we can't get another suspend
scePowerLock(0);
_PMStatus = kCheckingPauseFlag;
-
- if (!_pauseFlag)
+
+ if (!_pauseFlag)
return; // Make sure we can only resume once
_PMStatus = kGettingListMutexResume;
// First we notify our Suspendables. Loop over list, calling resume()
_listMutex.lock();
-
+
_PMStatus = kIteratingListResume;
// Iterate
@@ -314,12 +314,12 @@ void PowerManager::resume() {
_PMStatus = kDoneIteratingListResume;
_listMutex.unlock();
-
+
_PMStatus = kGettingFlagMutexResume;
// Now we set the suspend flag to false
_flagMutex.lock();
-
+
_PMStatus = kGotFlagMutexResume;
_suspendFlag = false;
@@ -328,11 +328,11 @@ void PowerManager::resume() {
// Signal the threads to wake up
_threadSleep.releaseAll();
-
+
_PMStatus = kDoneSignallingSuspendedThreadsResume;
_flagMutex.unlock();
-
+
_PMStatus = kDoneResume;
_pauseFlag = false; // Signal engine to unpause -- no mutex needed
diff --git a/backends/platform/psp/psp.spec b/backends/platform/psp/psp.spec
index ac325b7fd6..7177413373 100644
--- a/backends/platform/psp/psp.spec
+++ b/backends/platform/psp/psp.spec
@@ -1,3 +1,3 @@
%rename lib old_lib
*lib:
-%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel
+%(old_lib) -lz -lstdc++ -lc -lm -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk -lpsputility -lpspuser -lpsppower -lpsphprm -lpsprtc -lpspaudio -lpspaudiocodec -lpspkernel -lpspnet_inet
diff --git a/backends/platform/psp/psp_main.cpp b/backends/platform/psp/psp_main.cpp
index 41cf451323..019f6c12d1 100644
--- a/backends/platform/psp/psp_main.cpp
+++ b/backends/platform/psp/psp_main.cpp
@@ -103,7 +103,7 @@ int exit_callback(void) {
#ifdef ENABLE_PROFILING
gprof_cleanup();
-#endif
+#endif
sceKernelExitGame();
return 0;
@@ -170,12 +170,12 @@ int main(void) {
#endif
/* unit/speed tests */
-#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS)
+#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS)
PSP_INFO_PRINT("running tests\n");
psp_tests();
sceKernelSleepThread(); // that's it. That's all we're doing
#endif
-
+
int res = scummvm_main(argc, argv);
g_system->quit(); // TODO: Consider removing / replacing this!
diff --git a/backends/platform/psp/pspkeyboard.cpp b/backends/platform/psp/pspkeyboard.cpp
index eb081fc5f4..f210726692 100644
--- a/backends/platform/psp/pspkeyboard.cpp
+++ b/backends/platform/psp/pspkeyboard.cpp
@@ -23,19 +23,23 @@
*
*/
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
//#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-solid/" /* path to kbd.zip */
+#define PSP_KB_SHELL_PATH "ms0:/psp/game5xx/scummvm-solid/" /* path to kbd.zip */
#endif
#include <malloc.h>
#include <pspkernel.h>
-#include <png.h>
#include "backends/platform/psp/psppixelformat.h"
#include "backends/platform/psp/pspkeyboard.h"
+#include "backends/platform/psp/png_loader.h"
+#include "backends/platform/psp/input.h"
#include "common/keyboard.h"
#include "common/fs.h"
#include "common/unzip.h"
@@ -77,9 +81,9 @@ short PSPKeyboard::_modeChar[MODE_COUNT][5][6] = {
},
{ //numbers
{ K('1'), K('2'), K('3'), K('4'), K(0), K(0) },
- { C(F5), C(F8), C(F7), C(F6), C(F9), C(F10) },
+ { C(F5), C(F6), C(F7), C(F8), C(F9), C(F10) },
{ K('5'), K('6'), K('7'), K('8'), K(0), K(0) },
- { C(F1), C(F4), C(F3), C(F2), K(0), K(0) },
+ { C(F1), C(F2), C(F3), C(F4), K(0), K(0) },
{ K('\b'), K('0'), K(' '), K('9'), K(0), K(0) }
},
{ //symbols
@@ -91,16 +95,6 @@ short PSPKeyboard::_modeChar[MODE_COUNT][5][6] = {
}
};
-// Read function for png library to be able to read from our SeekableReadStream
-//
-void pngReadStreamRead(png_structp png_ptr, png_bytep data, png_size_t length) {
- Common::SeekableReadStream *file;
-
- file = (Common::SeekableReadStream *)png_ptr->io_ptr;
-
- file->read(data, length);
-}
-
// Array with file names
const char *PSPKeyboard::_guiStrings[] = {
"keys4.png", "keys_s4.png",
@@ -281,8 +275,6 @@ bool PSPKeyboard::load() {
// Loop through all png images
for (i = 0; i < guiStringsSize; i++) {
- uint32 height = 0, width = 0, paletteSize = 0;
-
PSP_DEBUG_PRINT("Opening %s.\n", _guiStrings[i]);
// Look for the file in the kbd directory
@@ -309,49 +301,18 @@ bool PSPKeyboard::load() {
goto ERROR;
}
- if (getPngImageSize(file, &width, &height, &paletteSize) == 0) { // Check image size and palette size
- // Allocate memory for image
- 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
- if (paletteSize <= 16) { // 4 bit
- _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;
- _buffers[i].setPixelFormat(PSPPixelFormat::Type_Palette_8bit);
- _palettes[i].setPixelFormats(PSPPixelFormat::Type_4444, PSPPixelFormat::Type_Palette_8bit);
- } else {
- PSP_ERROR("palette of %d too big!\n", paletteSize);
- goto ERROR;
- }
-
- } else { // 32-bit image
- _buffers[i].setPixelFormat(PSPPixelFormat::Type_8888);
- }
+ PngLoader image(file, _buffers[i], _palettes[i]);
- _buffers[i].allocate();
- _palettes[i].allocate();
-
- // Try to load the image
- file->seek(0); // Go back to start
-
- if (loadPngImage(file, _buffers[i], _palettes[i]) != 0)
- goto ERROR;
- else { // Success
- PSP_DEBUG_PRINT("Managed to load the image\n");
-
- if (paletteSize == 16) // 4-bit
- _buffers[i].flipNibbles();
-
- delete file;
- }
- } else {
- PSP_ERROR("couldn't obtain PNG image size\n");
+ if (image.allocate() != PngLoader::OK) {
+ PSP_ERROR("Failed to allocate memory for keyboard image %s\n", _guiStrings[i]);
goto ERROR;
}
+ if (!image.load()) {
+ PSP_ERROR("Failed to load image from file %s\n", _guiStrings[i]);
+ goto ERROR;
+ }
+
+ delete file;
} /* for loop */
_init = true;
@@ -376,124 +337,6 @@ ERROR:
return false;
}
-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::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;
- png_uint_32 width, height;
- int bit_depth, color_type, interlace_type;
-
- png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (png_ptr == NULL) {
- 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);
- return -1;
- }
- // Set the png lib to use our read function
- png_set_read_fn(png_ptr, (void *)file, pngReadStreamRead);
-
- png_set_sig_bytes(png_ptr, sig_read);
- png_read_info(png_ptr, info_ptr);
- png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL);
- if (color_type & PNG_COLOR_MASK_PALETTE)
- *paletteSize = info_ptr->num_palette;
- else
- *paletteSize = 0;
-
- png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
-
- *png_width = width;
- *png_height = height;
-
- return 0;
-}
-
-// Load a texture from a png image
-//
-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 y;
-
- png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (png_ptr == NULL) {
- PSP_ERROR("Couldn't create read struct to load keyboard\n");
- return -1;
- }
- // Use dummy error function
- 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) {
- PSP_ERROR("Couldn't create info struct to load keyboard\n");
- png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
- return -1;
- }
-
- // 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);
- png_read_info(png_ptr, info_ptr);
- png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL);
-
- // Strip off 16 bit channels. Not really needed but whatever
- png_set_strip_16(png_ptr);
-
- if (color_type == PNG_COLOR_TYPE_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
- palette.setSingleColorRGBA(i, srcPal->red, srcPal->green, srcPal->blue, alphaVal);
- srcPal++;
- }
- } 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);
- }
-
- 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");
- return -1;
- }
-
- 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);
-
- return 0;
-}
-
// Defines for working with PSP buttons
#define CHANGED(x) (_buttonsChanged & (x))
#define PRESSED(x) ((_buttonsChanged & (x)) && (pad.Buttons & (x)))
@@ -508,10 +351,11 @@ int PSPKeyboard::loadPngImage(Common::SeekableReadStream *file, Buffer &buffer,
* Uses the state machine.
* returns whether we have an event
*/
-bool PSPKeyboard::processInput(Common::Event &event, SceCtrlData &pad) {
+bool PSPKeyboard::processInput(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad) {
DEBUG_ENTER_FUNC();
bool haveEvent = false; // Whether we have an event for the event manager to process
+ bool havePspEvent = false;
event.kbd.flags = 0;
_buttonsChanged = _prevButtons ^ pad.Buttons;
@@ -530,11 +374,11 @@ bool PSPKeyboard::processInput(Common::Event &event, SceCtrlData &pad) {
haveEvent = true;
_dirty = true;
if (UP(PSP_CTRL_START))
- _state = kInvisible; // Make us invisible if unpressed
+ havePspEvent = true;
}
// Check for being in state of moving the keyboard onscreen or pressing select
else if (_state == kMove)
- handleMoveState(pad);
+ havePspEvent = handleMoveState(pad);
else if (_state == kDefault)
haveEvent = handleDefaultState(event, pad);
else if (_state == kCornersSelected)
@@ -544,12 +388,16 @@ bool PSPKeyboard::processInput(Common::Event &event, SceCtrlData &pad) {
else if (_state == kLTriggerDown)
handleLTriggerDownState(pad); // Deal with trigger states
+ if (havePspEvent) {
+ pspEvent.type = PSP_EVENT_SHOW_VIRTUAL_KB; // tell the input handler we're off
+ pspEvent.data = false;
+ }
_prevButtons = pad.Buttons;
return haveEvent;
}
-void PSPKeyboard::handleMoveState(SceCtrlData &pad) {
+bool PSPKeyboard::handleMoveState(SceCtrlData &pad) {
DEBUG_ENTER_FUNC();
if (UP(PSP_CTRL_SELECT)) {
// Toggle between visible and invisible
@@ -560,6 +408,9 @@ void PSPKeyboard::handleMoveState(SceCtrlData &pad) {
_state = kDefault;
_moved = false; // reset moved flag
}
+ if (_state == kInvisible) {
+ return true; // we become invisible
+ }
} else if (DOWN(PSP_DPAD)) { // How we move the KB onscreen
_moved = true;
_dirty = true;
@@ -573,6 +424,7 @@ void PSPKeyboard::handleMoveState(SceCtrlData &pad) {
else /* DOWN(PSP_CTRL_RIGHT) */
increaseKeyboardLocationX(5);
}
+ return false;
}
bool PSPKeyboard::handleDefaultState(Common::Event &event, SceCtrlData &pad) {
diff --git a/backends/platform/psp/pspkeyboard.h b/backends/platform/psp/pspkeyboard.h
index a30e7d0f32..ebf21cfd54 100644
--- a/backends/platform/psp/pspkeyboard.h
+++ b/backends/platform/psp/pspkeyboard.h
@@ -29,12 +29,15 @@
#include "common/events.h"
#include "common/stream.h"
#include "backends/platform/psp/display_client.h"
+//#include "backends/platform/psp/input.h"
#include <pspctrl.h>
//number of modes
#define MODE_COUNT 4
#define guiStringsSize 8 /* size of guistrings array */
+class PspEvent;
+
class PSPKeyboard : public DisplayClient {
private:
@@ -58,10 +61,9 @@ public:
void setClean() { _dirty = false; }
bool isVisible() const { return _state != kInvisible; } // Check if visible
void setVisible(bool val);
- bool processInput(Common::Event &event, SceCtrlData &pad); // Process input
+ bool processInput(Common::Event &event, PspEvent &pspEvent, SceCtrlData &pad); // Process input
void moveTo(const int newX, const int newY); // Move keyboard
void render(); // Draw the keyboard onscreen
-
private:
enum CursorDirections {
kUp = 0,
@@ -75,14 +77,11 @@ private:
Palette _palettes[guiStringsSize];
GuRenderer _renderer;
- int loadPngImage(Common::SeekableReadStream *file, Buffer &buffer, Palette &palette);
- int getPngImageSize(Common::SeekableReadStream *, uint32 *png_width, uint32 *png_height, uint32 *paletteSize);
- uint32 convert_pow2(uint32 size);
void increaseKeyboardLocationX(int amount); // Move keyboard onscreen
void increaseKeyboardLocationY(int amount);
void convertCursorToXY(CursorDirections cur, int &x, int &y);
- void handleMoveState(SceCtrlData &pad);
+ bool handleMoveState(SceCtrlData &pad);
bool handleDefaultState(Common::Event &event, SceCtrlData &pad);
bool handleCornersSelectedState(Common::Event &event, SceCtrlData &pad);
bool getInputChoice(Common::Event &event, SceCtrlData &pad);
diff --git a/backends/platform/psp/rtc.cpp b/backends/platform/psp/rtc.cpp
index 57edea7e49..f26e5770a6 100644
--- a/backends/platform/psp/rtc.cpp
+++ b/backends/platform/psp/rtc.cpp
@@ -23,13 +23,13 @@
*
*/
-#include <time.h>
+#include <time.h>
#include <psptypes.h>
#include <psprtc.h>
-
-#include "common/scummsys.h"
-#include "backends/platform/psp/rtc.h"
-
+
+#include "common/scummsys.h"
+#include "backends/platform/psp/rtc.h"
+
//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
//#define __PSP_DEBUG_PRINT__ /* For debug printouts */
@@ -51,13 +51,13 @@ void PspRtc::init() { // init our starting ticks
#define MS_LOOP_AROUND 4294967 /* We loop every 2^32 / 1000 = 71 minutes */
#define MS_LOOP_CHECK 60000 /* Threading can cause weird mixups without this */
-// Note that after we fill up 32 bits ie 50 days we'll loop back to 0, which may cause
+// Note that after we fill up 32 bits ie 50 days we'll loop back to 0, which may cause
// unpredictable results
uint32 PspRtc::getMillis() {
uint32 ticks[2];
-
+
sceRtcGetCurrentTick((u64 *)ticks); // can introduce weird thread delays
-
+
uint32 millis = ticks[0]/1000;
millis -= _startMillis; // get ms since start of program
@@ -66,22 +66,22 @@ uint32 PspRtc::getMillis() {
_looped = true;
_milliOffset += MS_LOOP_AROUND; // add the needed offset
PSP_DEBUG_PRINT("looping around. last ms[%d], curr ms[%d]\n", _lastMillis, millis);
- }
+ }
} else {
_looped = false;
}
-
- _lastMillis = millis;
-
+
+ _lastMillis = millis;
+
return millis + _milliOffset;
}
uint32 PspRtc::getMicros() {
uint32 ticks[2];
-
+
sceRtcGetCurrentTick((u64 *)ticks);
ticks[0] -= _startMicros;
-
- return ticks[0];
+
+ return ticks[0];
}
diff --git a/backends/platform/psp/rtc.h b/backends/platform/psp/rtc.h
index 7c1a28474d..841d636e2b 100644
--- a/backends/platform/psp/rtc.h
+++ b/backends/platform/psp/rtc.h
@@ -27,7 +27,7 @@
#define _PSP_RTC_H_
#include "common/singleton.h"
-
+
class PspRtc : public Common::Singleton<PspRtc> {
private:
uint32 _startMillis;
@@ -47,4 +47,4 @@ public:
uint32 getMicros();
};
-#endif \ No newline at end of file
+#endif
diff --git a/backends/platform/psp/tests.cpp b/backends/platform/psp/tests.cpp
index f65c13ae83..4064ee1d98 100644
--- a/backends/platform/psp/tests.cpp
+++ b/backends/platform/psp/tests.cpp
@@ -23,13 +23,13 @@
*
*/
-// PSP speed and unit tests. Activate in tests.h
-// You may also want to build without any engines.
-
+// PSP speed and unit tests. Activate in tests.h
+// You may also want to build without any engines.
+
#include "backends/platform/psp/tests.h"
-#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS)
-
+#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS)
+
#include "common/scummsys.h"
#include <pspiofilemgr_fcntl.h>
#include <pspiofilemgr_stat.h>
@@ -49,16 +49,16 @@
#define UNCACHED(x) ((byte *)(((uint32)(x)) | 0x40000000)) /* make an uncached access */
#define CACHED(x) ((byte *)(((uint32)(x)) & 0xBFFFFFFF)) /* make an uncached access into a cached one */
-
+
//#define __PSP_DEBUG_FUNCS__
//#define __PSP_DEBUG_PRINT__
-
+
// Results: (333Mhz/222Mhz)
// Getting a tick: 1-2 us
// Getting a time structure: 9/14us
// ie. using a tick and just dividing by 1000 saves us time.
-
-#include "backends/platform/psp/trace.h"
+
+#include "backends/platform/psp/trace.h"
class PspSpeedTests {
public:
@@ -67,11 +67,11 @@ public:
void seekSpeed();
void msReadSpeed();
void threadFunctionsSpeed();
- void semaphoreSpeed();
+ void semaphoreSpeed();
static int threadFunc(SceSize args, void *argp);
void semaphoreManyThreadSpeed();
void fastCopySpeed();
-
+
private:
enum {
MEMCPY_BUFFER_SIZE = 8192
@@ -95,16 +95,16 @@ void PspSpeedTests::tickSpeed() {
uint32 currentTicks1[2];
uint32 currentTicks2[2];
-
+
sceRtcGetCurrentTick((u64 *)currentTicks1);
sceRtcGetCurrentTick((u64 *)currentTicks2);
PSP_INFO_PRINT("current tick[%x %x][%u %u]\n", currentTicks1[0], currentTicks1[1], currentTicks1[0], currentTicks1[1]);
PSP_INFO_PRINT("current tick[%x %x][%u %u]\n", currentTicks2[0], currentTicks2[1], currentTicks2[0], currentTicks2[1]);
-
+
pspTime time;
sceRtcSetTick(&time, (u64 *)currentTicks2);
- PSP_INFO_PRINT("current tick in time, year[%d] month[%d] day[%d] hour[%d] minutes[%d] seconds[%d] us[%d]\n", time.year, time.month, time.day, time.hour, time.minutes, time.seconds, time.microseconds);
-
+ PSP_INFO_PRINT("current tick in time, year[%d] month[%d] day[%d] hour[%d] minutes[%d] seconds[%d] us[%d]\n", time.year, time.month, time.day, time.hour, time.minutes, time.seconds, time.microseconds);
+
pspTime time1;
pspTime time2;
sceRtcGetCurrentClockLocalTime(&time1);
@@ -119,7 +119,7 @@ void PspSpeedTests::getMicrosSpeed() {
time2 = PspRtc::instance().getMicros();
time3 = PspRtc::instance().getMicros();
time4 = PspRtc::instance().getMicros();
-
+
PSP_INFO_PRINT("getMicros() times: %d, %d, %d\n", time4-time3, time3-time2, time2-time1);
}
@@ -128,8 +128,8 @@ void PspSpeedTests::readAndTime(uint32 bytes, char *buffer, FILE *file) {
// test minimal read
fread(buffer, bytes, 1, file);
uint32 time2 = PspRtc::instance().getMicros();
-
- PSP_INFO_PRINT("Reading %d byte takes %dus\n", bytes, time2-time1);
+
+ PSP_INFO_PRINT("Reading %d byte takes %dus\n", bytes, time2-time1);
}
/*
@@ -158,7 +158,7 @@ void PspSpeedTests::msReadSpeed() {
file = fopen("ms0:/psp/music/track1.mp3", "r");
char *buffer = (char *)malloc(2 * 1024 * 1024);
-
+
readAndTime(1, buffer, file);
readAndTime(10, buffer, file);
readAndTime(50, buffer, file);
@@ -170,32 +170,32 @@ void PspSpeedTests::msReadSpeed() {
readAndTime(6000, buffer, file);
readAndTime(7000, buffer, file);
readAndTime(8000, buffer, file);
- readAndTime(9000, buffer, file);
+ readAndTime(9000, buffer, file);
readAndTime(10000, buffer, file);
readAndTime(30000, buffer, file);
readAndTime(50000, buffer, file);
readAndTime(80000, buffer, file);
readAndTime(100000, buffer, file);
-
+
fclose(file);
- free(buffer);
+ free(buffer);
}
-
+
void PspSpeedTests::seekAndTime(int bytes, int origin, FILE *file) {
char buffer[1000];
-
+
uint32 time1 = PspRtc::instance().getMicros();
// test minimal read
fseek(file, bytes, origin);
uint32 time2 = PspRtc::instance().getMicros();
-
+
PSP_INFO_PRINT("Seeking %d byte from %d took %dus\n", bytes, origin, time2-time1);
time1 = PspRtc::instance().getMicros();
// test minimal read
fread(buffer, 1000, 1, file);
time2 = PspRtc::instance().getMicros();
-
+
PSP_INFO_PRINT("Reading 1000 bytes took %dus\n", time2-time1);
}
@@ -246,9 +246,9 @@ int PspSpeedTests::getThreadIdSpeed() {
uint32 time1 = PspRtc::instance().getMicros();
int threadId = sceKernelGetThreadId();
uint32 time2 = PspRtc::instance().getMicros();
-
+
PSP_INFO_PRINT("Getting thread ID %d took %dus\n", threadId, time2-time1);
-
+
return threadId;
}
@@ -257,7 +257,7 @@ void PspSpeedTests::getPrioritySpeed() {
uint32 time1 = PspRtc::instance().getMicros();
int priority = sceKernelGetThreadCurrentPriority();
uint32 time2 = PspRtc::instance().getMicros();
-
+
PSP_INFO_PRINT("Getting thread priority %d took %dus\n", priority, time2-time1);
}
@@ -266,7 +266,7 @@ void PspSpeedTests::changePrioritySpeed(int id, int priority) {
uint32 time1 = PspRtc::instance().getMicros();
sceKernelChangeThreadPriority(id, priority);
uint32 time2 = PspRtc::instance().getMicros();
-
+
PSP_INFO_PRINT("Changing thread priority to %d for id %d took %dus\n", priority, id, time2-time1);
}
@@ -280,53 +280,53 @@ void PspSpeedTests::threadFunctionsSpeed() {
changePrioritySpeed(id, 30);
changePrioritySpeed(id, 35);
changePrioritySpeed(id, 25);
-
+
// test context switch time
for (int i=0; i<10; i++) {
uint time1 = PspRtc::instance().getMicros();
PspThread::delayMicros(0);
uint time2 = PspRtc::instance().getMicros();
- PSP_INFO_PRINT("poll %d. context switch Time = %dus\n", i, time2-time1); // 10-15us
- }
+ PSP_INFO_PRINT("poll %d. context switch Time = %dus\n", i, time2-time1); // 10-15us
+ }
}
-
-void PspSpeedTests::semaphoreSpeed() {
+
+void PspSpeedTests::semaphoreSpeed() {
PspSemaphore sem(1);
-
+
uint32 time1 = PspRtc::instance().getMicros();
-
+
sem.take();
-
+
uint32 time2 = PspRtc::instance().getMicros();
-
+
PSP_INFO_PRINT("taking semaphore took %d us\n", time2-time1); // 10us
-
+
uint32 time3 = PspRtc::instance().getMicros();
-
+
sem.give();
-
+
uint32 time4 = PspRtc::instance().getMicros();
PSP_INFO_PRINT("releasing semaphore took %d us\n", time4-time3); //10us-55us
}
int PspSpeedTests::threadFunc(SceSize args, void *argp) {
PSP_INFO_PRINT("thread %x created.\n", sceKernelGetThreadId());
-
+
_sem.take();
-
+
PSP_INFO_PRINT("grabbed semaphore. Quitting thread\n");
-
+
return 0;
}
-void PspSpeedTests::semaphoreManyThreadSpeed() {
-
+void PspSpeedTests::semaphoreManyThreadSpeed() {
+
// create 4 threads
for (int i=0; i<4; i++) {
int thid = sceKernelCreateThread("my_thread", PspSpeedTests::threadFunc, 0x18, 0x10000, THREAD_ATTR_USER, NULL);
sceKernelStartThread(thid, 0, 0);
}
-
+
PSP_INFO_PRINT("main thread. created threads\n");
uint32 threads = _sem.numOfWaitingThreads();
@@ -334,10 +334,10 @@ void PspSpeedTests::semaphoreManyThreadSpeed() {
threads = _sem.numOfWaitingThreads();
PSP_INFO_PRINT("main thread: waiting threads[%d]\n", threads);
}
-
+
PSP_INFO_PRINT("main: semaphore value[%d]\n", _sem.getValue());
PSP_INFO_PRINT("main thread: waiting threads[%d]\n", _sem.numOfWaitingThreads());
-
+
_sem.give(4);
}
@@ -346,31 +346,31 @@ void PspSpeedTests::fastCopySpecificSize(byte *dst, byte *src, uint32 bytes) {
uint32 fastcopyTime, memcpyTime;
const int iterations = 2000;
int intc;
-
+
intc = pspSdkDisableInterrupts();
-
+
time1 = PspRtc::instance().getMicros();
for (int i=0; i<iterations; i++) {
PspMemory::fastCopy(dst, src, bytes);
- }
+ }
time2 = PspRtc::instance().getMicros();
-
+
pspSdkEnableInterrupts(intc);
-
+
fastcopyTime = time2-time1;
-
+
intc = pspSdkDisableInterrupts();
-
+
time1 = PspRtc::instance().getMicros();
for (int i=0; i<iterations; i++) {
memcpy(dst, src, bytes);
- }
+ }
time2 = PspRtc::instance().getMicros();
-
+
pspSdkEnableInterrupts(intc);
-
+
memcpyTime = time2-time1;
-
+
PSP_INFO_PRINT("%d bytes. memcpy[%d], fastcopy[%d]\n", bytes, memcpyTime, fastcopyTime);
}
@@ -397,16 +397,16 @@ void PspSpeedTests::fastCopySpeed() {
uint32 *bufferSrc32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);
uint32 *bufferDst32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);
-
+
// fill buffer 1
for (int i=0; i<MEMCPY_BUFFER_SIZE/4; i++)
bufferSrc32[i] = i | (((MEMCPY_BUFFER_SIZE/4)-i)<<16);
-
+
// print buffer
for (int i=0; i<50; i++)
PSP_INFO_PRINT("%x ", bufferSrc32[i]);
PSP_INFO_PRINT("\n");
-
+
byte *bufferSrc = ((byte *)bufferSrc32);
byte *bufferDst = ((byte *)bufferDst32);
@@ -415,7 +415,7 @@ void PspSpeedTests::fastCopySpeed() {
fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
fastCopyDifferentSizes(bufferDst, bufferSrc+1);
fastCopyDifferentSizes(bufferDst+1, bufferSrc);
-
+
PSP_INFO_PRINT("\n\ndst cached, src uncached: -----------------\n");
bufferSrc = UNCACHED(bufferSrc);
fastCopyDifferentSizes(bufferDst, bufferSrc);
@@ -429,7 +429,7 @@ void PspSpeedTests::fastCopySpeed() {
fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
fastCopyDifferentSizes(bufferDst, bufferSrc+1);
fastCopyDifferentSizes(bufferDst+1, bufferSrc);
-
+
PSP_INFO_PRINT("\n\ndst uncached, src cached: -------------------\n");
bufferSrc = CACHED(bufferSrc);
fastCopyDifferentSizes(bufferDst, bufferSrc);
@@ -437,7 +437,7 @@ void PspSpeedTests::fastCopySpeed() {
fastCopyDifferentSizes(bufferDst, bufferSrc+1);
fastCopyDifferentSizes(bufferDst+1, bufferSrc);
-
+
free(bufferSrc32);
free(bufferDst32);
}
@@ -453,11 +453,11 @@ private:
enum {
MEMCPY_BUFFER_SIZE = 8192
};
-
+
void fastCopySpecificSize(byte *dst, byte *src, uint32 bytes, bool swap = false);
void fastCopyDifferentSizes(byte *dst, byte *src, bool swap = false);
-
-};
+
+};
void PspUnitTests::testFastCopy() {
PSP_INFO_PRINT("running fastcopy unit test ***********\n");
@@ -465,19 +465,19 @@ void PspUnitTests::testFastCopy() {
uint32 *bufferSrc32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);
uint32 *bufferDst32 = (uint32 *)memalign(16, MEMCPY_BUFFER_SIZE);
-
+
// fill buffer 1
for (int i=0; i<MEMCPY_BUFFER_SIZE/4; i++)
bufferSrc32[i] = i | (((MEMCPY_BUFFER_SIZE/4)-i)<<16);
-
+
// print buffer
for (int i=0; i<50; i++)
PSP_INFO_PRINT("%x ", bufferSrc32[i]);
PSP_INFO_PRINT("\n");
-
+
byte *bufferSrc = ((byte *)bufferSrc32);
byte *bufferDst = ((byte *)bufferDst32);
-
+
fastCopyDifferentSizes(bufferDst, bufferSrc, true);
fastCopyDifferentSizes(bufferDst+1, bufferSrc+1);
fastCopyDifferentSizes(bufferDst+2, bufferSrc+2, true);
@@ -491,12 +491,12 @@ void PspUnitTests::testFastCopy() {
fastCopyDifferentSizes(bufferDst+2, bufferSrc+1);
fastCopyDifferentSizes(bufferDst+2, bufferSrc+3);
fastCopyDifferentSizes(bufferDst+3, bufferSrc+1);
- fastCopyDifferentSizes(bufferDst+3, bufferSrc+2);
-
+ fastCopyDifferentSizes(bufferDst+3, bufferSrc+2);
+
free(bufferSrc32);
free(bufferDst32);
}
-
+
void PspUnitTests::fastCopyDifferentSizes(byte *dst, byte *src, bool swap) {
fastCopySpecificSize(dst, src, 1);
fastCopySpecificSize(dst, src, 2, swap);
@@ -509,7 +509,7 @@ void PspUnitTests::fastCopyDifferentSizes(byte *dst, byte *src, bool swap) {
fastCopySpecificSize(dst, src, 12, swap);
fastCopySpecificSize(dst, src, 13);
fastCopySpecificSize(dst, src, 14, swap);
- fastCopySpecificSize(dst, src, 15);
+ fastCopySpecificSize(dst, src, 15);
fastCopySpecificSize(dst, src, 16, swap);
fastCopySpecificSize(dst, src, 17);
fastCopySpecificSize(dst, src, 18, swap);
@@ -529,16 +529,16 @@ void PspUnitTests::fastCopyDifferentSizes(byte *dst, byte *src, bool swap) {
void PspUnitTests::fastCopySpecificSize(byte *dst, byte *src, uint32 bytes, bool swap) {
memset(dst, 0, bytes);
PspMemory::fastCopy(dst, src, bytes);
-
+
if (swap) { // test swap also
memset(dst, 0, bytes);
-
+
// pixelformat for swap
PSPPixelFormat format;
format.set(PSPPixelFormat::Type_4444, true);
-
+
PspMemory::fastSwap(dst, src, bytes, format);
- }
+ }
}
// This function leaks. For now I don't care
@@ -549,23 +549,23 @@ bool PspUnitTests::testFileSystem() {
int i;
Common::WriteStream *wrStream;
Common::SeekableReadStream *rdStream;
-
+
PSP_INFO_PRINT("testing fileSystem...\n");
-
+
// fill buffer
for (i=0; i<(int)BufSize; i += 4) {
buffer[i] = 'A';
buffer[i + 1] = 'B';
buffer[i + 2] = 'C';
buffer[i + 3] = 'D';
- }
-
+ }
+
// create a file
const char *path = "./file.test";
Common::FSNode file(path);
-
+
PSP_INFO_PRINT("creating write stream...\n");
-
+
wrStream = file.createWriteStream();
if (!wrStream) {
PSP_ERROR("%s couldn't be created.\n", path);
@@ -576,9 +576,9 @@ bool PspUnitTests::testFileSystem() {
char* index = buffer;
int32 totalLength = BufSize;
int32 curLength = 50;
-
+
PSP_INFO_PRINT("writing...\n");
-
+
while(totalLength - curLength > 0) {
if ((int)wrStream->write(index, curLength) != curLength) {
PSP_ERROR("couldn't write %d bytes\n", curLength);
@@ -595,22 +595,22 @@ bool PspUnitTests::testFileSystem() {
PSP_ERROR("couldn't write %d bytes\n", curLength);
return false;
}
-
+
delete wrStream;
-
+
PSP_INFO_PRINT("reading...\n");
-
+
rdStream = file.createReadStream();
if (!rdStream) {
PSP_ERROR("%s couldn't be created.\n", path);
return false;
}
-
+
// seek to beginning
if (!rdStream->seek(0, SEEK_SET)) {
PSP_ERROR("couldn't seek to the beginning after writing the file\n");
return false;
- }
+ }
// read the contents
char *readBuffer = new char[BufSize + 4];
@@ -619,96 +619,96 @@ bool PspUnitTests::testFileSystem() {
while (rdStream->read(index, 100) == 100) {
index += 100;
}
-
+
if (!rdStream->eos()) {
PSP_ERROR("didn't find EOS at end of stream\n");
- return false;
+ return false;
}
-
+
// compare
for (i=0; i<(int)BufSize; i++)
if (buffer[i] != readBuffer[i]) {
PSP_ERROR("reading/writing mistake at %x. Got %x instead of %x\n", i, readBuffer[i], buffer[i]);
return false;
}
-
+
// Check for exceeding limit
for (i=0; i<4; i++) {
if (readBuffer[BufSize + i]) {
PSP_ERROR("read exceeded limits. %d = %x\n", BufSize + i, readBuffer[BufSize + i]);
}
- }
-
+ }
+
delete rdStream;
-
+
PSP_INFO_PRINT("writing...\n");
-
+
wrStream = file.createWriteStream();
if (!wrStream) {
PSP_ERROR("%s couldn't be created.\n", path);
return false;
}
-
+
const char *phrase = "Jello is really fabulous";
uint32 phraseLen = strlen(phrase);
-
+
int ret;
if ((ret = wrStream->write(phrase, phraseLen)) != (int)phraseLen) {
PSP_ERROR("couldn't write phrase. Got %d instead of %d\n", ret, phraseLen);
return false;
}
-
+
PSP_INFO_PRINT("reading...\n");
-
+
delete wrStream;
rdStream = file.createReadStream();
if (!rdStream) {
PSP_ERROR("%s couldn't be created.\n", path);
return false;
}
-
+
char *readPhrase = new char[phraseLen + 2];
memset(readPhrase, 0, phraseLen + 2);
-
+
if ((ret = rdStream->read(readPhrase, phraseLen) != phraseLen)) {
PSP_ERROR("read error on phrase. Got %d instead of %d\n", ret, phraseLen);
return false;
}
-
+
for (i=0; i<(int)phraseLen; i++) {
if (readPhrase[i] != phrase[i]) {
PSP_ERROR("bad read/write in phrase. At %d, %x != %x\n", i, readPhrase[i], phrase[i]);
return false;
}
- }
-
+ }
+
// check for exceeding
if (readPhrase[i] != 0) {
PSP_ERROR("found excessive copy in phrase. %c at %d\n", readPhrase[i], i);
return false;
}
-
+
PSP_INFO_PRINT("trying to read end...\n");
-
+
// seek to end
if (!rdStream->seek(0, SEEK_END)) {
PSP_ERROR("couldn't seek to end for append\n");
return false;
};
-
+
// try to read
if (rdStream->read(readPhrase, 2) || !rdStream->eos()) {
PSP_ERROR("was able to read at end of file\n");
return false;
}
-
+
PSP_INFO_PRINT("ok\n");
return true;
}
void psp_tests() {
PSP_INFO_PRINT("in tests\n");
-
+
#ifdef PSP_ENABLE_SPEED_TESTS
// Speed tests
PspSpeedTests speedTests;
@@ -718,18 +718,18 @@ void psp_tests() {
speedTests.seekSpeed();
speedTests.msReadSpeed();
speedTests.threadFunctionsSpeed();
- speedTests.semaphoreSpeed();
+ speedTests.semaphoreSpeed();
speedTests.semaphoreManyThreadSpeed();
speedTests.fastCopySpeed();
-#endif
-
+#endif
+
#ifdef PSP_ENABLE_UNIT_TESTS
// Unit tests
PspUnitTests unitTests;
-
+
//unitTests.testFastCopy();
unitTests.testFileSystem();
-#endif
-}
+#endif
+}
-#endif /* (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) */ \ No newline at end of file
+#endif /* (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS) */
diff --git a/backends/platform/psp/tests.h b/backends/platform/psp/tests.h
index 1518acfb4c..9af7ba8d7d 100644
--- a/backends/platform/psp/tests.h
+++ b/backends/platform/psp/tests.h
@@ -23,14 +23,14 @@
*
*/
-#ifndef _PSP_TESTS_H_
+#ifndef _PSP_TESTS_H_
#define _PSP_TESTS_H_
//#define PSP_ENABLE_UNIT_TESTS // run unit tests
//#define PSP_ENABLE_SPEED_TESTS // run speed tests
-#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS)
+#if defined (PSP_ENABLE_UNIT_TESTS) || defined (PSP_ENABLE_SPEED_TESTS)
void psp_tests();
#endif
-#endif /* _PSP_TESTS_H_ */ \ No newline at end of file
+#endif /* _PSP_TESTS_H_ */
diff --git a/backends/platform/psp/thread.cpp b/backends/platform/psp/thread.cpp
index e757c2f575..3e1303a4e6 100644
--- a/backends/platform/psp/thread.cpp
+++ b/backends/platform/psp/thread.cpp
@@ -23,12 +23,12 @@
*
*/
-#include <pspthreadman.h>
+#include <pspthreadman.h>
#include "backends/platform/psp/thread.h"
#include "backends/platform/psp/trace.h"
-
-// Class PspThreadable --------------------------------------------------
+
+// Class PspThreadable --------------------------------------------------
// Inherit this to create C++ threads easily
bool PspThreadable::threadCreateAndStart(const char *threadName, int priority, int stackSize, bool useVfpu /*= false*/) {
@@ -38,41 +38,41 @@ bool PspThreadable::threadCreateAndStart(const char *threadName, int priority, i
PSP_ERROR("thread already created!\n");
return false;
}
-
+
_threadId = sceKernelCreateThread(threadName, __threadCallback, priority, stackSize, THREAD_ATTR_USER, 0); // add VFPU support
if (_threadId < 0) {
PSP_ERROR("failed to create %s thread. Error code %d\n", threadName, _threadId);
return false;
}
-
+
// We want to pass the pointer to this, but we'll have to take address of this so use a little trick
PspThreadable *_this = this;
-
+
if (sceKernelStartThread(_threadId, sizeof(uint32 *), &_this) < 0) {
PSP_ERROR("failed to start %s thread id[%d]\n", threadName, _threadId);
return false;
}
-
- PSP_DEBUG_PRINT("Started %s thread with id[%x]\n", threadName, _threadId);
-
+
+ PSP_DEBUG_PRINT("Started %s thread with id[%x]\n", threadName, _threadId);
+
return true;
}
// Callback function to be called by PSP kernel
int PspThreadable::__threadCallback(SceSize, void *__this) {
DEBUG_ENTER_FUNC();
-
+
PspThreadable *_this = *(PspThreadable **)__this; // Dereference the copied value which was 'this'
-
+
_this->threadFunction(); // call the virtual function
-
+
return 0;
}
// PspThread class
// Utilities to access general thread functions
-
+
void PspThread::delayMillis(uint32 ms) {
sceKernelDelayThread(ms * 1000);
}
@@ -90,8 +90,8 @@ void PspThread::delayMicros(uint32 us) {
PspSemaphore::PspSemaphore(int initialValue, int maxValue/*=255*/) {
DEBUG_ENTER_FUNC();
_handle = 0;
- _handle = (uint32)sceKernelCreateSema("ScummVM Sema", 0 /* attr */,
- initialValue, maxValue,
+ _handle = (uint32)sceKernelCreateSema("ScummVM Sema", 0 /* attr */,
+ initialValue, maxValue,
0 /*option*/);
if (!_handle)
PSP_ERROR("failed to create semaphore.\n");
@@ -108,10 +108,10 @@ int PspSemaphore::numOfWaitingThreads() {
DEBUG_ENTER_FUNC();
SceKernelSemaInfo info;
info.numWaitThreads = 0;
-
+
if (sceKernelReferSemaStatus((SceUID)_handle, &info) < 0)
PSP_ERROR("failed to retrieve semaphore info for handle %d\n", _handle);
-
+
return info.numWaitThreads;
}
@@ -119,10 +119,10 @@ int PspSemaphore::getValue() {
DEBUG_ENTER_FUNC();
SceKernelSemaInfo info;
info.currentCount = 0;
-
+
if (sceKernelReferSemaStatus((SceUID)_handle, &info) < 0)
PSP_ERROR("failed to retrieve semaphore info for handle %d\n", _handle);
-
+
return info.currentCount;
}
@@ -130,18 +130,18 @@ bool PspSemaphore::pollForValue(int value) {
DEBUG_ENTER_FUNC();
if (sceKernelPollSema((SceUID)_handle, value) < 0)
return false;
-
+
return true;
}
// false: timeout or error
bool PspSemaphore::takeWithTimeOut(uint32 timeOut) {
DEBUG_ENTER_FUNC();
-
+
uint32 *pTimeOut = 0;
- if (timeOut)
+ if (timeOut)
pTimeOut = &timeOut;
-
+
if (sceKernelWaitSema(_handle, 1, pTimeOut) < 0) // we always wait for 1
return false;
return true;
@@ -149,9 +149,9 @@ bool PspSemaphore::takeWithTimeOut(uint32 timeOut) {
bool PspSemaphore::give(int num /*=1*/) {
DEBUG_ENTER_FUNC();
-
+
if (sceKernelSignalSema((SceUID)_handle, num) < 0)
- return false;
+ return false;
return true;
}
@@ -161,7 +161,7 @@ bool PspMutex::lock() {
DEBUG_ENTER_FUNC();
int threadId = sceKernelGetThreadId();
bool ret = true;
-
+
if (_ownerId == threadId) {
_recursiveCount++;
} else {
@@ -176,19 +176,19 @@ bool PspMutex::unlock() {
DEBUG_ENTER_FUNC();
int threadId = sceKernelGetThreadId();
bool ret = true;
-
+
if (_ownerId != threadId) {
PSP_ERROR("attempt to unlock mutex by thread[%x] as opposed to owner[%x]\n",
threadId, _ownerId);
return false;
}
-
+
if (_recursiveCount) {
_recursiveCount--;
} else {
_ownerId = 0;
ret = _semaphore.give(1);
- }
+ }
return ret;
}
@@ -200,7 +200,7 @@ void PspCondition::releaseAll() {
if (_waitingThreads > _signaledThreads) { // we have signals to issue
int numWaiting = _waitingThreads - _signaledThreads; // threads we haven't signaled
_signaledThreads = _waitingThreads;
-
+
_waitSem.give(numWaiting);
_mutex.unlock();
for (int i=0; i<numWaiting; i++) // wait for threads to tell us they're awake
diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h
index 44394af40a..1ca6ef5c42 100644
--- a/backends/platform/psp/thread.h
+++ b/backends/platform/psp/thread.h
@@ -34,7 +34,7 @@ class PspThreadable {
protected:
int _threadId;
virtual void threadFunction() = 0; // this function will be called when the thread starts
-public:
+public:
PspThreadable() : _threadId(-1) {} // constructor
virtual ~PspThreadable() {} // destructor
static int __threadCallback(SceSize, void *__this); // used to get called by sceKernelStartThread() Don't override
@@ -43,7 +43,7 @@ public:
// class for thread utils
class PspThread {
-public:
+public:
// static functions
static void delayMillis(uint32 ms); // delay the current thread
static void delayMicros(uint32 us);
@@ -106,7 +106,7 @@ enum StackSizes {
STACK_DISPLAY_THREAD = 2 * 1024,
STACK_POWER_THREAD = 4 * 1024
};
-
+
#endif /* PSP_THREADS_H */