aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sandulenko2006-10-06 19:01:39 +0000
committerEugene Sandulenko2006-10-06 19:01:39 +0000
commit3d84f1104688db0b23b6fe9ccc86b587ac597837 (patch)
treedf9c7c4fdbfbbb8c1aa67d6e5f4ffc9bcdac9fb4
parente75bea0c8f454bbeac842414a7ab8c4c77321801 (diff)
downloadscummvm-rg350-3d84f1104688db0b23b6fe9ccc86b587ac597837.tar.gz
scummvm-rg350-3d84f1104688db0b23b6fe9ccc86b587ac597837.tar.bz2
scummvm-rg350-3d84f1104688db0b23b6fe9ccc86b587ac597837.zip
Patch #1432376: "Very basic GP2X Backend"
svn-id: r24144
-rw-r--r--backends/intern.h3
-rw-r--r--backends/platform/gp2x/build.rules5
-rw-r--r--backends/platform/gp2x/build/README-GP2X114
-rw-r--r--backends/platform/gp2x/build/README-GP2X.html114
-rw-r--r--backends/platform/gp2x/build/build.sh19
-rw-r--r--backends/platform/gp2x/build/bundle.sh30
-rw-r--r--backends/platform/gp2x/build/clean.sh17
-rw-r--r--backends/platform/gp2x/build/config.sh22
-rw-r--r--backends/platform/gp2x/build/scummvm.pngbin0 -> 2810 bytes
-rw-r--r--backends/platform/gp2x/events.cpp657
-rw-r--r--backends/platform/gp2x/gp2x-common.h402
-rw-r--r--backends/platform/gp2x/gp2x-hw.cpp248
-rw-r--r--backends/platform/gp2x/gp2x-hw.h74
-rw-r--r--backends/platform/gp2x/gp2x-mem.c300
-rw-r--r--backends/platform/gp2x/gp2x-mem.h57
-rw-r--r--backends/platform/gp2x/gp2x.cpp298
-rw-r--r--backends/platform/gp2x/graphics.cpp1722
-rw-r--r--backends/platform/gp2x/module.mk15
-rw-r--r--common/config-manager.cpp8
-rwxr-xr-xconfigure29
-rw-r--r--sound/fmopl.cpp10
21 files changed, 4134 insertions, 10 deletions
diff --git a/backends/intern.h b/backends/intern.h
index f6304fb7b5..8a20e45702 100644
--- a/backends/intern.h
+++ b/backends/intern.h
@@ -43,6 +43,9 @@
#elif defined(__PSP__)
#define SAMPLES_PER_SEC 44100
+#elif defined(__GP2X__)
+#define SAMPLES_PER_SEC 11025
+
#elif defined(PALMOS_MODE)
# ifdef PALMOS_ARM
# ifdef COMPILE_ZODIAC
diff --git a/backends/platform/gp2x/build.rules b/backends/platform/gp2x/build.rules
new file mode 100644
index 0000000000..1a1134d2ac
--- /dev/null
+++ b/backends/platform/gp2x/build.rules
@@ -0,0 +1,5 @@
+# Build settings for the GP2X backend
+MODULES += backends/gp2x
+DEFINES += -DUNIX -DGP2X
+INCLUDES += `sdl-config --cflags`
+LIBS += `sdl-config --libs`
diff --git a/backends/platform/gp2x/build/README-GP2X b/backends/platform/gp2x/build/README-GP2X
new file mode 100644
index 0000000000..acc3d0d140
--- /dev/null
+++ b/backends/platform/gp2x/build/README-GP2X
@@ -0,0 +1,114 @@
+$URL$
+$Id$
+
+DO NOT USE THIS FOR ANYTHING OTHER THEN TO TEST A USB MOUSE.
+IT'S BUGGY AND ANYTHING OTHER THEN THE 320*2xx LucasArts GAMES
+WILL MOST LIGHTLY CRASH YOUR GP2X.
+
+THE README IS BELOW JUST FOR REFERANCE.
+
+ScummVM for the GP2X - UNSTABLE MOUSE TEST - 0.10.0 SVN
+-------------------------------------------------------
+
+This is a test release of ScummVM for the GP2X, it would be appreciated if this alpha test distribution was not mirrored and that people be directed to http://www.distant-earth.com/scummvm instead, until the port is a little more mature, to ensure people download the most recent builds.
+
+This build is still in a very heavy state of development and as such no ‘expected’ behaviour can be guaranteed ;).
+I tested with firmware 1.2.1 for reference.
+
+INCLUDED ENGINES:
+
+Scumm - (All games supported by ScummVM should work to some extent, using the hardware scalar if needed)
+
+// Simon - (Simon the Sorcerer one and two)
+// Sky - (Beneath a Steel Sky)
+// Sword - (Broken Sword 1) - This engine uses the hardware scalar to downsize the graphics to fix on the GP2X. It is NOT very nice to look at.
+// Sword2 - (Broken Sword 2) - This engine uses the hardware scalar to downsize the graphics to fix on the GP2X. It is NOT very nice to look at.
+// Gob - (Goblins one)
+// Queen - Flight of the Amazon Queen
+// Kyra - (The Legend of Kyrandia) - This engine is still under heavy development in ScummVM, however the game is playable.
+// Lure - (Lure of the Temptress) - This engine is still under heavy development in ScummVM, the game is not yet really playable.
+
+
+All other game engines are disabled in this release.
+
+SUPPORTED AUDIO OPTIONS:
+
+Raw audio.
+MP3 audio.
+OGG Vorbis audio (this may be problematic, I just made some big changes to my Tremor code).
+
+RECENT CHANGES:
+
+Refined audio hacks to reduce audio delay a little more.
+Enabled hardware scalar code.
+Now built using SDL 1.2.9 for the parts of the port that use SDL (some parts now hit the hardware directly).
+Enabled new launcher - (Ensure defaulttheme.zip is in the same folder as the executable).
+Aspect Ratio Correction can now be disabled ‘per game’. When adding a game you can find this option on the GFX tab.
+Note: This will cause the game to run with a black border at the bottom as it will be rendered to a 320*200 frame.
+
+HOW TO SAVE:
+
+NOTE: Everything is saved to the SD card, saves are stored in the game folder, and the config file for ScummVM (.scummvmrc) is stored in the same place as the GPE.
+
+Ok, this is for Scumm engine games but the principle is the same for all.
+
+In Game.
+
+1. Right Trigger
+2. Select SAVE with B
+3. Select a position with B
+4. Right trigger puts ? in the name box for some text.
+5. Press B to save
+
+Basically the emulated keys you have are what I mapped the buttons to,
+I have a virtual keyboard like the GP32 one (left/right on the stick to pick chars) to add in at some point ;-)
+
+CONTROLLER MAPPING:
+
+NOTE: The controller mappings have recently changed somewhat so please review the new setup.
+This is subject to change; it still does not ‘feel’ quite right.
+
+Mouse Emulation:
+
+Stick: Move Pointer
+Stick Click: ‘light’ Left Click
+B: Left click
+X: Right click
+
+Keyboard Emulation:
+
+Start: Return
+Select: Escape
+Y: Space Bar (Pause)
+Right Trigger: Game Menu (Save, Load, Quit etc.)
+Volume Buttons: Increase and Decrease volume (5% per press)
+
+Fancy button combos:
+
+NOTE: To use button combos press and hold the Left Trigger then...
+
+Volume Buttons: Increase and Decrease subtitle speed (In SCUMM games)
+Right Trigger: 0 (For skipping the copy protection in Monkey Island 2)
+Select: Exit ScummVM completely
+(More to add, ideas please)
+
+KNOWN ISSUES:
+
+Possible random crash (well SegFault). I have had this happen twice and have not tracked down the cause.
+It happens very infrequently, both times it was in the DOTT CD intro. Saving often is never a bad idea anyhow.
+
+Volume level changes can be a little inconsistent at times.
+
+MAJOR TODOS:
+
+Fix save support when using the Sky engine (Beneath a Steel Sky) - You CAN'T save at the moment but auto save works.
+Look into inconsistencies with Simon engine and map Y key to a button combination to allow clean quitting (Simon 1/2).
+Add splash-screen and pre-ScummVM config menu (CPU speed, LCD timings etc.) - Partly done.
+Fix TV out, maybe make it an option in the pre-ScummVM config menu.
+Any help appreciated :).
+
+SOURCE:
+
+Port source is available on request. Note this is development code (and VERY messy).
+
+John Willis \ No newline at end of file
diff --git a/backends/platform/gp2x/build/README-GP2X.html b/backends/platform/gp2x/build/README-GP2X.html
new file mode 100644
index 0000000000..acc3d0d140
--- /dev/null
+++ b/backends/platform/gp2x/build/README-GP2X.html
@@ -0,0 +1,114 @@
+$URL$
+$Id$
+
+DO NOT USE THIS FOR ANYTHING OTHER THEN TO TEST A USB MOUSE.
+IT'S BUGGY AND ANYTHING OTHER THEN THE 320*2xx LucasArts GAMES
+WILL MOST LIGHTLY CRASH YOUR GP2X.
+
+THE README IS BELOW JUST FOR REFERANCE.
+
+ScummVM for the GP2X - UNSTABLE MOUSE TEST - 0.10.0 SVN
+-------------------------------------------------------
+
+This is a test release of ScummVM for the GP2X, it would be appreciated if this alpha test distribution was not mirrored and that people be directed to http://www.distant-earth.com/scummvm instead, until the port is a little more mature, to ensure people download the most recent builds.
+
+This build is still in a very heavy state of development and as such no ‘expected’ behaviour can be guaranteed ;).
+I tested with firmware 1.2.1 for reference.
+
+INCLUDED ENGINES:
+
+Scumm - (All games supported by ScummVM should work to some extent, using the hardware scalar if needed)
+
+// Simon - (Simon the Sorcerer one and two)
+// Sky - (Beneath a Steel Sky)
+// Sword - (Broken Sword 1) - This engine uses the hardware scalar to downsize the graphics to fix on the GP2X. It is NOT very nice to look at.
+// Sword2 - (Broken Sword 2) - This engine uses the hardware scalar to downsize the graphics to fix on the GP2X. It is NOT very nice to look at.
+// Gob - (Goblins one)
+// Queen - Flight of the Amazon Queen
+// Kyra - (The Legend of Kyrandia) - This engine is still under heavy development in ScummVM, however the game is playable.
+// Lure - (Lure of the Temptress) - This engine is still under heavy development in ScummVM, the game is not yet really playable.
+
+
+All other game engines are disabled in this release.
+
+SUPPORTED AUDIO OPTIONS:
+
+Raw audio.
+MP3 audio.
+OGG Vorbis audio (this may be problematic, I just made some big changes to my Tremor code).
+
+RECENT CHANGES:
+
+Refined audio hacks to reduce audio delay a little more.
+Enabled hardware scalar code.
+Now built using SDL 1.2.9 for the parts of the port that use SDL (some parts now hit the hardware directly).
+Enabled new launcher - (Ensure defaulttheme.zip is in the same folder as the executable).
+Aspect Ratio Correction can now be disabled ‘per game’. When adding a game you can find this option on the GFX tab.
+Note: This will cause the game to run with a black border at the bottom as it will be rendered to a 320*200 frame.
+
+HOW TO SAVE:
+
+NOTE: Everything is saved to the SD card, saves are stored in the game folder, and the config file for ScummVM (.scummvmrc) is stored in the same place as the GPE.
+
+Ok, this is for Scumm engine games but the principle is the same for all.
+
+In Game.
+
+1. Right Trigger
+2. Select SAVE with B
+3. Select a position with B
+4. Right trigger puts ? in the name box for some text.
+5. Press B to save
+
+Basically the emulated keys you have are what I mapped the buttons to,
+I have a virtual keyboard like the GP32 one (left/right on the stick to pick chars) to add in at some point ;-)
+
+CONTROLLER MAPPING:
+
+NOTE: The controller mappings have recently changed somewhat so please review the new setup.
+This is subject to change; it still does not ‘feel’ quite right.
+
+Mouse Emulation:
+
+Stick: Move Pointer
+Stick Click: ‘light’ Left Click
+B: Left click
+X: Right click
+
+Keyboard Emulation:
+
+Start: Return
+Select: Escape
+Y: Space Bar (Pause)
+Right Trigger: Game Menu (Save, Load, Quit etc.)
+Volume Buttons: Increase and Decrease volume (5% per press)
+
+Fancy button combos:
+
+NOTE: To use button combos press and hold the Left Trigger then...
+
+Volume Buttons: Increase and Decrease subtitle speed (In SCUMM games)
+Right Trigger: 0 (For skipping the copy protection in Monkey Island 2)
+Select: Exit ScummVM completely
+(More to add, ideas please)
+
+KNOWN ISSUES:
+
+Possible random crash (well SegFault). I have had this happen twice and have not tracked down the cause.
+It happens very infrequently, both times it was in the DOTT CD intro. Saving often is never a bad idea anyhow.
+
+Volume level changes can be a little inconsistent at times.
+
+MAJOR TODOS:
+
+Fix save support when using the Sky engine (Beneath a Steel Sky) - You CAN'T save at the moment but auto save works.
+Look into inconsistencies with Simon engine and map Y key to a button combination to allow clean quitting (Simon 1/2).
+Add splash-screen and pre-ScummVM config menu (CPU speed, LCD timings etc.) - Partly done.
+Fix TV out, maybe make it an option in the pre-ScummVM config menu.
+Any help appreciated :).
+
+SOURCE:
+
+Port source is available on request. Note this is development code (and VERY messy).
+
+John Willis \ No newline at end of file
diff --git a/backends/platform/gp2x/build/build.sh b/backends/platform/gp2x/build/build.sh
new file mode 100644
index 0000000000..55395cb73c
--- /dev/null
+++ b/backends/platform/gp2x/build/build.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+echo Quick script to make building all the time less painful.
+
+# Set the paths up here to support the build.
+
+export PATH=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/arm-open2x-linux/bin:$PATH
+export PATH=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/bin:$PATH
+export CXX=arm-open2x-linux-g++
+export CC=arm-open2x-linux-gcc
+export CXXFLAGS=-march=armv4t
+export LDFLAGS=-static
+
+cd ../../../..
+
+echo Building ScummVM for GP2X.
+make
+
+echo Build for GP2X - SDL - complete - Please check build logs.
diff --git a/backends/platform/gp2x/build/bundle.sh b/backends/platform/gp2x/build/bundle.sh
new file mode 100644
index 0000000000..93efa63a83
--- /dev/null
+++ b/backends/platform/gp2x/build/bundle.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+echo Quick script to make building a distribution of the GP2X port more consistent.
+
+PATH=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/arm-open2x-linux/bin:$PATH
+PATH=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/bin:$PATH
+export CXX=arm-open2x-linux-g++
+export CXXFLAGS=-march=armv4t
+export CPPFLAGS=-I/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/include
+export LDFLAGS=-L/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/lib
+
+echo Collecting files.
+mkdir "scummvm-gp2x-`date '+%Y-%m-%d'`"
+
+cp ./scummvm.png ./scummvm-gp2x-`date '+%Y-%m-%d'`/
+cp ./README-GP2X.html ./scummvm-gp2x-`date '+%Y-%m-%d'`/
+cp ./README-GP2X ./scummvm-gp2x-`date '+%Y-%m-%d'`/
+cp ../../../../scummvm.gpe ./scummvm-gp2x-`date '+%Y-%m-%d'`/
+cp ../../../../AUTHORS ./scummvm-gp2x-`date '+%Y-%m-%d'`/
+cp ../../../../README ./scummvm-gp2x-`date '+%Y-%m-%d'`/
+cp ../../../../COPYING ./scummvm-gp2x-`date '+%Y-%m-%d'`/
+cp ../../../../gui/themes/modern.ini ./scummvm-gp2x-`date '+%Y-%m-%d'`/
+cp ../../../../gui/themes/modern.zip ./scummvm-gp2x-`date '+%Y-%m-%d'`/
+
+
+echo Making Stripped GPE.
+arm-open2x-linux-strip ./scummvm-gp2x-`date '+%Y-%m-%d'`/scummvm.gpe
+
+echo Building ZIP bundle.
+echo You should have a "scummvm-gp2x-`date '+%Y-%m-%d'`.zip" for the GP2X port ready to go. \ No newline at end of file
diff --git a/backends/platform/gp2x/build/clean.sh b/backends/platform/gp2x/build/clean.sh
new file mode 100644
index 0000000000..c603d95f83
--- /dev/null
+++ b/backends/platform/gp2x/build/clean.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+echo Quick script to make building all the time less painful.
+
+# Set the paths up here to support the build.
+
+export PATH=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/arm-open2x-linux/bin:$PATH
+export PATH=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/bin:$PATH
+export CXX=arm-open2x-linux-g++
+export CC=arm-open2x-linux-gcc
+export CXXFLAGS=-march=armv4t
+export LDFLAGS=-static
+
+cd ../../../..
+
+echo Cleaning ScummVM for GP2X.
+make clean
diff --git a/backends/platform/gp2x/build/config.sh b/backends/platform/gp2x/build/config.sh
new file mode 100644
index 0000000000..b1d23b03fc
--- /dev/null
+++ b/backends/platform/gp2x/build/config.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+echo Quick script to make running configure all the time less painful
+echo and let all the build work be done from the backend/build folder.
+
+# Set the paths up here to generate the config.
+
+PATH=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/arm-open2x-linux/bin:$PATH
+PATH=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/bin:$PATH
+
+# Export the tool names for cross-compiling
+export CXX=arm-open2x-linux-g++
+export CXXFLAGS=-march=armv4t
+export CPPFLAGS=-I/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/include
+export LDFLAGS=-L/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/lib
+export DEFINES=-DNDEBUG
+
+# Edit the configure line to suit.
+cd ../../../..
+./configure --backend=gp2x --disable-mt32emu --host=gp2x --disable-mpeg2 --disable-flac --disable-nasm --disable-hq-scalers --with-sdl-prefix=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux/bin --enable-tremor --with-tremor-prefix=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux --enable-zlib --with-zlib-prefix=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux --enable-mad --with-mad-prefix=/tools/open2x_gcc/gcc-4.0.2-glibc-2.3.5/arm-open2x-linux
+
+echo Generating config for GP2X complete. Check for errors. \ No newline at end of file
diff --git a/backends/platform/gp2x/build/scummvm.png b/backends/platform/gp2x/build/scummvm.png
new file mode 100644
index 0000000000..ede14b07e7
--- /dev/null
+++ b/backends/platform/gp2x/build/scummvm.png
Binary files differ
diff --git a/backends/platform/gp2x/events.cpp b/backends/platform/gp2x/events.cpp
new file mode 100644
index 0000000000..f3d5ef0d58
--- /dev/null
+++ b/backends/platform/gp2x/events.cpp
@@ -0,0 +1,657 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ * Copyright (C) 2005-2006 John Willis (Portions of the GP2X Backend)
+ *
+ * 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$
+ *
+ */
+
+/*
+ * GP2X: Event Handling.
+ *
+ */
+
+#include "backends/platform/gp2x/gp2x-common.h"
+#include "backends/platform/gp2x/gp2x-hw.h"
+#include "common/util.h"
+
+// FIXME move joystick defines out and replace with confile file options
+// we should really allow users to map any key to a joystick button
+#define JOY_DEADZONE 2200
+
+// #define JOY_INVERT_Y
+#define JOY_XAXIS 0
+#define JOY_YAXIS 1
+
+// GP2X Stick Buttons (Note: The Stick is read as a set of buttons not a HAT type of setup).
+#define JOY_BUT_LMOUSE 0x0D
+#define JOY_BUT_RMOUSE 0x0E
+
+#define JOY_BUT_RETURN 0x08
+#define JOY_BUT_ESCAPE 0x09
+#define JOY_BUT_F5 0x0B
+#define JOY_BUT_SPACE 0x0F
+#define JOY_BUT_TALKUP 0x10
+#define JOY_BUT_TALKDN 0x11
+#define JOY_BUT_ZERO 0x12
+
+#define JOY_BUT_COMB 0x0A
+#define JOY_BUT_EXIT 0x12
+#define JOY_BUT_PERIOD 0x0C
+
+
+//TODO: Quick hack 101 ;-) Clean this up,
+#define TRUE 1
+#define FALSE 0
+
+static int mapKey(SDLKey key, SDLMod mod, Uint16 unicode)
+{
+ if (key >= SDLK_F1 && key <= SDLK_F9) {
+ return key - SDLK_F1 + 315;
+ } else if (key >= SDLK_KP0 && key <= SDLK_KP9) {
+ return key - SDLK_KP0 + '0';
+ } else if (key >= SDLK_UP && key <= SDLK_PAGEDOWN) {
+ return key;
+ } else if (unicode) {
+ return unicode;
+ } else if (key >= 'a' && key <= 'z' && mod & KMOD_SHIFT) {
+ return key & ~0x20;
+ } else if (key >= SDLK_NUMLOCK && key <= SDLK_EURO) {
+ return 0;
+ }
+ return key;
+}
+
+void OSystem_GP2X::fillMouseEvent(Event &event, int x, int y) {
+ event.mouse.x = x;
+ event.mouse.y = y;
+
+ // Update the "keyboard mouse" coords
+ _km.x = x;
+ _km.y = y;
+
+ // Adjust for the screen scaling
+ if (!_overlayVisible) {
+ event.mouse.x /= _scaleFactor;
+ event.mouse.y /= _scaleFactor;
+ if (_adjustAspectRatio)
+ event.mouse.y = aspect2Real(event.mouse.y);
+ }
+}
+
+void OSystem_GP2X::handleKbdMouse() {
+ uint32 curTime = getMillis();
+ if (curTime >= _km.last_time + _km.delay_time) {
+ _km.last_time = curTime;
+ if (_km.x_down_count == 1) {
+ _km.x_down_time = curTime;
+ _km.x_down_count = 2;
+ }
+ if (_km.y_down_count == 1) {
+ _km.y_down_time = curTime;
+ _km.y_down_count = 2;
+ }
+
+ if (_km.x_vel || _km.y_vel) {
+ if (_km.x_down_count) {
+ if (curTime > _km.x_down_time + _km.delay_time * 12) {
+ if (_km.x_vel > 0)
+ _km.x_vel++;
+ else
+ _km.x_vel--;
+ } else if (curTime > _km.x_down_time + _km.delay_time * 8) {
+ if (_km.x_vel > 0)
+ _km.x_vel = 5;
+ else
+ _km.x_vel = -5;
+ }
+ }
+ if (_km.y_down_count) {
+ if (curTime > _km.y_down_time + _km.delay_time * 12) {
+ if (_km.y_vel > 0)
+ _km.y_vel++;
+ else
+ _km.y_vel--;
+ } else if (curTime > _km.y_down_time + _km.delay_time * 8) {
+ if (_km.y_vel > 0)
+ _km.y_vel = 5;
+ else
+ _km.y_vel = -5;
+ }
+ }
+
+ _km.x += _km.x_vel;
+ _km.y += _km.y_vel;
+
+ if (_km.x < 0) {
+ _km.x = 0;
+ _km.x_vel = -1;
+ _km.x_down_count = 1;
+ } else if (_km.x > _km.x_max) {
+ _km.x = _km.x_max;
+ _km.x_vel = 1;
+ _km.x_down_count = 1;
+ }
+
+ if (_km.y < 0) {
+ _km.y = 0;
+ _km.y_vel = -1;
+ _km.y_down_count = 1;
+ } else if (_km.y > _km.y_max) {
+ _km.y = _km.y_max;
+ _km.y_vel = 1;
+ _km.y_down_count = 1;
+ }
+
+ SDL_WarpMouse(_km.x, _km.y);
+ }
+ }
+}
+
+static byte SDLModToOSystemKeyFlags(SDLMod mod) {
+ byte b = 0;
+#ifdef LINUPY
+ // Yopy has no ALT key, steal the SHIFT key
+ // (which isn't used much anyway)
+ if (mod & KMOD_SHIFT)
+ b |= OSystem::KBD_ALT;
+#else
+ if (mod & KMOD_SHIFT)
+ b |= OSystem::KBD_SHIFT;
+ if (mod & KMOD_ALT)
+ b |= OSystem::KBD_ALT;
+#endif
+ if (mod & KMOD_CTRL)
+ b |= OSystem::KBD_CTRL;
+
+ return b;
+}
+
+void OSystem_GP2X::moveStick() {
+ bool stickBtn[32];
+
+ memcpy(stickBtn, _stickBtn, sizeof(stickBtn));
+
+ if((stickBtn[0])||(stickBtn[2])||(stickBtn[4])||(stickBtn[6]))
+ stickBtn[1] = stickBtn[3] = stickBtn[5] = stickBtn[7] = 0;
+
+ if((stickBtn[1])||(stickBtn[2])||(stickBtn[3])){
+ if(_km.x_down_count!=2){
+ _km.x_vel = -1;
+ _km.x_down_count = 1;
+ }else
+ _km.x_vel = -4;
+ } else if((stickBtn[5])||(stickBtn[6])||(stickBtn[7])){
+ if(_km.x_down_count!=2){
+ _km.x_vel = 1;
+ _km.x_down_count = 1;
+ }else
+ _km.x_vel = 4;
+ }
+ else{
+ _km.x_vel = 0;
+ _km.x_down_count = 0;
+ }
+
+
+ if((stickBtn[0])||(stickBtn[1])||(stickBtn[7])){
+ if(_km.y_down_count!=2){
+ _km.y_vel = -1;
+ _km.y_down_count = 1;
+ }else
+ _km.y_vel = -4;
+ } else if((stickBtn[3])||(stickBtn[4])||(stickBtn[5])){
+ if(_km.y_down_count!=2){
+ _km.y_vel = 1;
+ _km.y_down_count = 1;
+ }else
+ _km.y_vel = 4;
+ }
+ else{
+ _km.y_vel = 0;
+ _km.y_down_count = 0;
+ }
+}
+
+ //Quick default button states for modifier.
+
+ //int GP2X_BUTTON_STATE_UP = FALSE;
+ //int GP2X_BUTTON_STATE_DOWN = FALSE;
+ //int GP2X_BUTTON_STATE_LEFT = FALSE;
+ //int GP2X_BUTTON_STATE_RIGHT = FALSE;
+ //int GP2X_BUTTON_STATE_UPLEFT = FALSE;
+ //int GP2X_BUTTON_STATE_UPRIGHT = FALSE;
+ //int GP2X_BUTTON_STATE_DOWNLEFT = FALSE;
+ //int GP2X_BUTTON_STATE_DOWNRIGHT = FALSE;
+ //int GP2X_BUTTON_STATE_CLICK = FALSE;
+ //int GP2X_BUTTON_STATE_A = FALSE;
+ //int GP2X_BUTTON_STATE_B = FALSE;
+ //int GP2X_BUTTON_STATE_Y = FALSE;
+ //int GP2X_BUTTON_STATE_X = FALSE;
+ int GP2X_BUTTON_STATE_L = FALSE;
+ //int GP2X_BUTTON_STATE_R = FALSE;
+ //int GP2X_BUTTON_STATE_START = FALSE;
+ //int GP2X_BUTTON_STATE_SELECT = FALSE;
+ //int GP2X_BUTTON_STATE_VOLUP = FALSE;
+ //int GP2X_BUTTON_STATE_VOLDOWN = FALSE;
+
+bool OSystem_GP2X::pollEvent(Event &event) {
+ SDL_Event ev;
+ int axis;
+ byte b = 0;
+
+ handleKbdMouse();
+
+ // If the screen mode changed, send an EVENT_SCREEN_CHANGED
+ if (_modeChanged) {
+ _modeChanged = false;
+ event.type = EVENT_SCREEN_CHANGED;
+ _screenChangeCount++;
+ return true;
+ }
+
+ // GP2X Input mappings.
+
+ /*
+ Single Button
+
+ Movement:
+
+ GP2X_BUTTON_UP Cursor Up
+ GP2X_BUTTON_DOWN Cursor Down
+ GP2X_BUTTON_LEFT Cursor Left
+ GP2X_BUTTON_RIGHT Cursor Right
+
+ TODO: Add extra directions to cursor mappings.
+
+ GP2X_BUTTON_UPLEFT Cursor Up Left
+ GP2X_BUTTON_UPRIGHT Cursor Up Right
+ GP2X_BUTTON_DOWNLEFT Cursor Down Left
+ GP2X_BUTTON_DOWNRIGHT Cursor Down Right
+
+ Button Emulation:
+
+ GP2X_BUTTON_CLICK Left Mouse Click
+ GP2X_BUTTON_A . (Period)
+ GP2X_BUTTON_B Left Mouse Click
+ GP2X_BUTTON_Y Space Bar
+ GP2X_BUTTON_X Right Mouse Click
+ GP2X_BUTTON_L Combo Modifier (Left Trigger)
+ GP2X_BUTTON_R F5 (Right Trigger)
+ GP2X_BUTTON_START Return
+ GP2X_BUTTON_SELECT Escape
+ GP2X_BUTTON_VOLUP /dev/mixer Global Volume Up
+ GP2X_BUTTON_VOLDOWN /dev/mixer Global Volume Down
+
+ Combos:
+
+ GP2X_BUTTON_VOLUP & GP2X_BUTTON_VOLDOWN 0 (For Monkey 2 CP)
+ GP2X_BUTTON_L & GP2X_BUTTON_SELECT EVENT_QUIT (Calls Sync() to make sure SD is flushed)
+ GP2X_BUTTON_L & GP2X_BUTTON_Y Toggles setZoomOnMouse() for larger then 320*240 games to scale to the point + raduis.
+ */
+
+ while(SDL_PollEvent(&ev)) {
+
+ switch(ev.type) {
+ case SDL_KEYDOWN:{
+ b = event.kbd.flags = SDLModToOSystemKeyFlags(SDL_GetModState());
+
+ // Alt-Return and Alt-Enter toggle full screen mode
+ if (b == KBD_ALT && (ev.key.keysym.sym == SDLK_RETURN
+ || ev.key.keysym.sym == SDLK_KP_ENTER)) {
+ setFullscreenMode(!_fullscreen);
+ break;
+ }
+
+ // Alt-S: Create a screenshot
+ if (b == KBD_ALT && ev.key.keysym.sym == 's') {
+ char filename[20];
+
+ for (int n = 0;; n++) {
+ SDL_RWops *file;
+
+ sprintf(filename, "scummvm%05d.bmp", n);
+ file = SDL_RWFromFile(filename, "r");
+ if (!file)
+ break;
+ SDL_RWclose(file);
+ }
+ if (saveScreenshot(filename))
+ printf("Saved '%s'\n", filename);
+ else
+ printf("Could not save screenshot!\n");
+ break;
+ }
+
+ // Ctrl-m toggles mouse capture
+ //if (b == KBD_CTRL && ev.key.keysym.sym == 'm') {
+ // toggleMouseGrab();
+ // break;
+ //}
+
+//#ifdef MACOSX
+// // On Macintosh', Cmd-Q quits
+// if ((ev.key.keysym.mod & KMOD_META) && ev.key.keysym.sym == 'q') {
+// event.type = EVENT_QUIT;
+// return true;
+// }
+//#elif defined(UNIX)
+// // On other unices, Control-Q quits
+// if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'q') {
+// event.type = EVENT_QUIT;
+// return true;
+// }
+//#else
+// // Ctrl-z and Alt-X quit
+// if ((b == KBD_CTRL && ev.key.keysym.sym == 'z') || (b == KBD_ALT && ev.key.keysym.sym == 'x')) {
+// event.type = EVENT_QUIT;
+// return true;
+// }
+//#endif
+//
+// // Ctrl-Alt-<key> will change the GFX mode
+// if ((b & (KBD_CTRL|KBD_ALT)) == (KBD_CTRL|KBD_ALT)) {
+//
+// handleScalerHotkeys(ev.key);
+// break;
+// }
+ const bool event_complete = remapKey(ev,event);
+
+ if (event_complete)
+ return true;
+
+ event.type = EVENT_KEYDOWN;
+ event.kbd.keycode = ev.key.keysym.sym;
+ event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode);
+
+ return true;
+ }
+ case SDL_KEYUP:
+ {
+ const bool event_complete = remapKey(ev,event);
+
+ if (event_complete)
+ return true;
+
+ event.type = EVENT_KEYUP;
+ event.kbd.keycode = ev.key.keysym.sym;
+ event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode);
+ b = event.kbd.flags = SDLModToOSystemKeyFlags(SDL_GetModState());
+
+ // Ctrl-Alt-<key> will change the GFX mode
+ if ((b & (KBD_CTRL|KBD_ALT)) == (KBD_CTRL|KBD_ALT)) {
+ // Swallow these key up events
+ break;
+ }
+
+ return true;
+ }
+ case SDL_MOUSEMOTION:
+ event.type = EVENT_MOUSEMOVE;
+ fillMouseEvent(event, ev.motion.x, ev.motion.y);
+
+ setMousePos(event.mouse.x, event.mouse.y);
+ return true;
+
+ case SDL_MOUSEBUTTONDOWN:
+ if (ev.button.button == SDL_BUTTON_LEFT)
+ event.type = EVENT_LBUTTONDOWN;
+ else if (ev.button.button == SDL_BUTTON_RIGHT)
+ event.type = EVENT_RBUTTONDOWN;
+#if defined(SDL_BUTTON_WHEELUP) && defined(SDL_BUTTON_WHEELDOWN)
+ else if (ev.button.button == SDL_BUTTON_WHEELUP)
+ event.type = EVENT_WHEELUP;
+ else if (ev.button.button == SDL_BUTTON_WHEELDOWN)
+ event.type = EVENT_WHEELDOWN;
+#endif
+ else
+ break;
+
+ fillMouseEvent(event, ev.button.x, ev.button.y);
+
+ return true;
+
+ case SDL_MOUSEBUTTONUP:
+ if (ev.button.button == SDL_BUTTON_LEFT)
+ event.type = EVENT_LBUTTONUP;
+ else if (ev.button.button == SDL_BUTTON_RIGHT)
+ event.type = EVENT_RBUTTONUP;
+ else
+ break;
+ fillMouseEvent(event, ev.button.x, ev.button.y);
+
+ return true;
+
+ // GP2X Button mapings. Main code
+
+ case SDL_JOYBUTTONDOWN:
+ _stickBtn[ev.jbutton.button] = 1;
+ if (ev.jbutton.button == JOY_BUT_LMOUSE) {
+ event.type = EVENT_LBUTTONDOWN;
+ fillMouseEvent(event, _km.x, _km.y);
+ } else if (ev.jbutton.button == GP2X_BUTTON_CLICK) {
+ event.type = EVENT_LBUTTONDOWN;
+ fillMouseEvent(event, _km.x, _km.y);
+ } else if (ev.jbutton.button == JOY_BUT_RMOUSE) {
+ event.type = EVENT_RBUTTONDOWN;
+ fillMouseEvent(event, _km.x, _km.y);
+ } else if (_stickBtn[JOY_BUT_COMB] && (ev.jbutton.button == JOY_BUT_EXIT)) {
+ event.type = EVENT_QUIT;
+ } else if (ev.jbutton.button < 8) {
+ moveStick();
+ event.type = EVENT_MOUSEMOVE;
+ fillMouseEvent(event, _km.x, _km.y);
+ } else {
+ event.type = EVENT_KEYDOWN;
+ event.kbd.flags = 0;
+ switch (ev.jbutton.button) {
+ case GP2X_BUTTON_L:
+ GP2X_BUTTON_STATE_L = TRUE;
+ break;
+ case GP2X_BUTTON_R:
+ if (GP2X_BUTTON_STATE_L == TRUE) {
+ event.kbd.keycode = SDLK_0;
+ event.kbd.ascii = mapKey(SDLK_0, ev.key.keysym.mod, 0);
+ } else {
+ event.kbd.keycode = SDLK_F5;
+ event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0);
+ }
+ break;
+ case GP2X_BUTTON_SELECT:
+ if (GP2X_BUTTON_STATE_L == TRUE) {
+ event.type = EVENT_QUIT;
+ } else {
+ event.kbd.keycode = SDLK_ESCAPE;
+ event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0);
+ }
+ break;
+ case GP2X_BUTTON_A:
+ event.kbd.keycode = SDLK_PERIOD;
+ event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0);
+ break;
+ case GP2X_BUTTON_Y:
+ if (GP2X_BUTTON_STATE_L == TRUE) {
+ setZoomOnMouse();
+ } else {
+ event.kbd.keycode = SDLK_SPACE;
+ event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0);
+ }
+ break;
+ case JOY_BUT_RETURN:
+ event.kbd.keycode = SDLK_RETURN;
+ event.kbd.ascii = mapKey(SDLK_RETURN, ev.key.keysym.mod, 0);
+ break;
+ case JOY_BUT_ZERO:
+ event.kbd.keycode = SDLK_0;
+ event.kbd.ascii = mapKey(SDLK_0, ev.key.keysym.mod, 0);
+ break;
+
+ //case GP2X_BUTTON_R:
+ // if ((ev.jbutton.button == GP2X_BUTTON_L) && (ev.jbutton.button == GP2X_BUTTON_R)) {
+ // displayMessageOnOSD("Exiting ScummVM");
+ // //Sync();
+ // event.type = EVENT_QUIT;
+ // break;
+ // } else if ((ev.jbutton.button == GP2X_BUTTON_L) && (ev.jbutton.button != GP2X_BUTTON_R)) {
+ // displayMessageOnOSD("Left Trigger Pressed");
+ // break;
+ // } else if ((ev.jbutton.button == GP2X_BUTTON_R) && (ev.jbutton.button != GP2X_BUTTON_L)) {
+ // event.kbd.keycode = SDLK_F5;
+ // event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0);
+ // break;
+ // } else {
+ // break;
+ // }
+ // break;
+ case GP2X_BUTTON_VOLUP:
+ if (GP2X_BUTTON_STATE_L == TRUE) {
+ displayMessageOnOSD("Setting CPU Speed at 230MHz");
+ GP2X_setCpuspeed(200);
+ //event.kbd.keycode = SDLK_PLUS;
+ //event.kbd.ascii = mapKey(SDLK_PLUS, ev.key.keysym.mod, 0);
+ } else {
+ GP2X_mixer_move_volume(1);
+ displayMessageOnOSD("Increasing Volume");
+ }
+ break;
+ case GP2X_BUTTON_VOLDOWN:
+ if (GP2X_BUTTON_STATE_L == TRUE) {
+ displayMessageOnOSD("Setting CPU Speed at 60MHz");
+ GP2X_setCpuspeed(60);
+ //event.kbd.keycode = SDLK_MINUS;
+ //event.kbd.ascii = mapKey(SDLK_MINUS, ev.key.keysym.mod, 0);
+ } else {
+ GP2X_mixer_move_volume(0);
+ displayMessageOnOSD("Decreasing Volume");
+ }
+ break;
+ }
+ }
+ return true;
+
+ case SDL_JOYBUTTONUP:
+ _stickBtn[ev.jbutton.button] = 0;
+ if (ev.jbutton.button == JOY_BUT_LMOUSE) {
+ event.type = EVENT_LBUTTONUP;
+ fillMouseEvent(event, _km.x, _km.y);
+ } else if (ev.jbutton.button == JOY_BUT_RMOUSE) {
+ event.type = EVENT_RBUTTONUP;
+ fillMouseEvent(event, _km.x, _km.y);
+ } else if (ev.jbutton.button < 8) {
+ moveStick();
+ event.type = EVENT_MOUSEMOVE;
+ fillMouseEvent(event, _km.x, _km.y);
+ } else {
+ event.type = EVENT_KEYUP;
+ event.kbd.flags = 0;
+ switch (ev.jbutton.button) {
+ case GP2X_BUTTON_SELECT:
+ event.kbd.keycode = SDLK_ESCAPE;
+ event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0);
+ break;
+ case GP2X_BUTTON_A:
+ event.kbd.keycode = SDLK_PERIOD;
+ event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0);
+ break;
+ case GP2X_BUTTON_Y:
+// event.kbd.keycode = SDLK_SPACE;
+// event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0);
+ break;
+ case GP2X_BUTTON_START:
+ event.kbd.keycode = SDLK_RETURN;
+ event.kbd.ascii = mapKey(SDLK_RETURN, ev.key.keysym.mod, 0);
+ break;
+ case GP2X_BUTTON_L:
+ GP2X_BUTTON_STATE_L = FALSE;
+ break;
+ case GP2X_BUTTON_R:
+ event.kbd.keycode = SDLK_F5;
+ event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0);
+ break;
+ case GP2X_BUTTON_VOLUP:
+ break;
+ case GP2X_BUTTON_VOLDOWN:
+ break;
+ }
+ }
+ return true;
+
+ case SDL_JOYAXISMOTION:
+ axis = ev.jaxis.value;
+ if ( axis > JOY_DEADZONE) {
+ axis -= JOY_DEADZONE;
+ event.type = EVENT_MOUSEMOVE;
+ } else if ( axis < -JOY_DEADZONE ) {
+ axis += JOY_DEADZONE;
+ event.type = EVENT_MOUSEMOVE;
+ } else
+ axis = 0;
+
+ if ( ev.jaxis.axis == JOY_XAXIS) {
+#ifdef JOY_ANALOG
+ _km.x_vel = axis/2000;
+ _km.x_down_count = 0;
+#else
+ if (axis != 0) {
+ _km.x_vel = (axis > 0) ? 1:-1;
+ _km.x_down_count = 1;
+ } else {
+ _km.x_vel = 0;
+ _km.x_down_count = 0;
+ }
+#endif
+
+ } else if (ev.jaxis.axis == JOY_YAXIS) {
+#ifndef JOY_INVERT_Y
+ axis = -axis;
+#endif
+#ifdef JOY_ANALOG
+ _km.y_vel = -axis / 2000;
+ _km.y_down_count = 0;
+#else
+ if (axis != 0) {
+ _km.y_vel = (-axis > 0) ? 1: -1;
+ _km.y_down_count = 1;
+ } else {
+ _km.y_vel = 0;
+ _km.y_down_count = 0;
+ }
+#endif
+ }
+
+ fillMouseEvent(event, _km.x, _km.y);
+
+ return true;
+
+ case SDL_VIDEOEXPOSE:
+ _forceFull = true;
+ break;
+
+ case SDL_QUIT:
+ event.type = EVENT_QUIT;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool OSystem_GP2X::remapKey(SDL_Event &ev,Event &event) {
+ return false;
+}
+
diff --git a/backends/platform/gp2x/gp2x-common.h b/backends/platform/gp2x/gp2x-common.h
new file mode 100644
index 0000000000..d768e1c4d8
--- /dev/null
+++ b/backends/platform/gp2x/gp2x-common.h
@@ -0,0 +1,402 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ * Copyright (C) 2005-2006 John Willis (Portions of the GP2X Backend)
+ *
+ * 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 GP2X_COMMON_H
+#define GP2X_COMMON_H
+
+#define __GP2X__
+#define USE_OSD
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "common/system.h"
+#include "graphics/scaler.h"
+#include "backends/intern.h"
+
+#include <SDL.h>
+#include <SDL_gp2x.h>
+
+//#define DISABLE_SCALERS
+
+enum {
+ GFX_NORMAL = 0,
+ GFX_DOUBLESIZE = 1,
+ GFX_TRIPLESIZE = 2,
+ GFX_2XSAI = 3,
+ GFX_SUPER2XSAI = 4,
+ GFX_SUPEREAGLE = 5,
+ GFX_ADVMAME2X = 6,
+ GFX_ADVMAME3X = 7,
+ GFX_HQ2X = 8,
+ GFX_HQ3X = 9,
+ GFX_TV2X = 10,
+ GFX_DOTMATRIX = 11
+};
+
+
+class OSystem_GP2X : public OSystem {
+public:
+ OSystem_GP2X();
+ virtual ~OSystem_GP2X();
+
+ virtual void initBackend();
+
+ void beginGFXTransaction(void);
+ void endGFXTransaction(void);
+
+ // Set the size of the video bitmap.
+ // Typically, 320x200
+ void initSize(uint w, uint h);
+ int getScreenChangeID() const { return _screenChangeCount; }
+
+ // Set colors of the palette
+ void setPalette(const byte *colors, uint start, uint num);
+
+ // Get colors of the palette
+ void grabPalette(byte *colors, uint start, uint num);
+
+ // Draw a bitmap to screen.
+ // The screen will not be updated to reflect the new bitmap
+ void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h);
+
+ // Copies the screen to a buffer
+ bool grabRawScreen(Graphics::Surface *surf);
+
+ // Clear the screen
+ void clearScreen();
+
+ // Update the dirty areas of the screen
+ void updateScreen();
+
+ // Either show or hide the mouse cursor
+ bool showMouse(bool visible);
+
+ // Warp the mouse cursor. Where set_mouse_pos() only informs the
+ // backend of the mouse cursor's current position, this function
+ // actually moves the cursor to the specified position.
+ void warpMouse(int x, int y);
+
+ // Set the bitmap that's used when drawing the cursor.
+ void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale);
+
+ // Set colors of cursor palette
+ void setCursorPalette(const byte *colors, uint start, uint num);
+
+ // Disables or enables cursor palette
+ void disableCursorPalette(bool disable) {
+ _cursorPaletteDisabled = disable;
+ blitCursor();
+ };
+
+ // Shaking is used in SCUMM. Set current shake position.
+ void setShakePos(int shake_pos);
+
+ // Get the number of milliseconds since the program was started.
+ uint32 getMillis();
+
+ // Delay for a specified amount of milliseconds
+ void delayMillis(uint msecs);
+
+ // Get the next event.
+ // Returns true if an event was retrieved.
+ virtual bool pollEvent(Event &event); // overloaded by CE backend
+
+ // Set function that generates samples
+ virtual bool setSoundCallback(SoundProc proc, void *param); // overloaded by CE backend
+
+ void clearSoundCallback();
+
+ // Poll CD status
+ // Returns true if cd audio is playing
+ bool pollCD();
+
+ // Play CD audio track
+ void playCD(int track, int num_loops, int start_frame, int duration);
+
+ // Stop CD audio track
+ void stopCD();
+
+ // Update CD audio status
+ void updateCD();
+
+ // Quit
+ virtual void quit(); // overloaded by CE backend
+
+
+ // Add a callback timer
+ void setTimerCallback(TimerProc callback, int timer);
+
+ // Mutex handling
+ MutexRef createMutex();
+ void lockMutex(MutexRef mutex);
+ void unlockMutex(MutexRef mutex);
+ void deleteMutex(MutexRef mutex);
+
+ // Overlay
+ void showOverlay();
+ void hideOverlay();
+ void clearOverlay();
+ void grabOverlay(OverlayColor *buf, int pitch);
+ void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); // WinCE FIXME
+ int16 getHeight();
+ int16 getWidth();
+ int16 getOverlayHeight() { return _overlayHeight; }
+ int16 getOverlayWidth() { return _overlayWidth; }
+
+ // Methods that convert RGB to/from colors suitable for the overlay.
+ OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b);
+ void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b);
+
+
+ virtual const GraphicsMode *getSupportedGraphicsModes() const;
+ virtual int getDefaultGraphicsMode() const;
+ virtual bool setGraphicsMode(int mode);
+ virtual int getGraphicsMode() const;
+
+ //virtual void setWindowCaption(const char *caption);
+ virtual bool openCD(int drive);
+ virtual int getOutputSampleRate() const;
+
+ virtual bool hasFeature(Feature f);
+ virtual void setFeatureState(Feature f, bool enable);
+ virtual bool getFeatureState(Feature f);
+
+ void displayMessageOnOSD(const char *msg);
+
+protected:
+ bool _inited;
+
+ SDL_Surface *_osdSurface;
+ Uint8 _osdAlpha; // Transparency level of the OSD
+ uint32 _osdFadeStartTime; // When to start the fade out
+ enum {
+ kOSDFadeOutDelay = 2 * 1000, // Delay before the OSD is faded out (in milliseconds)
+ kOSDFadeOutDuration = 500, // Duration of the OSD fade out (in milliseconds)
+ kOSDColorKey = 1,
+ kOSDInitialAlpha = 80 // Initial alpha level, in percent
+ };
+
+ // hardware screen
+ SDL_Surface *_hwscreen;
+
+ // unseen game screen
+ SDL_Surface *_screen;
+ int _screenWidth, _screenHeight;
+
+ // temporary screen (for scalers)
+ SDL_Surface *_tmpscreen;
+ SDL_Surface *_tmpscreen2;
+
+ // overlay
+ SDL_Surface *_overlayscreen;
+ int _overlayWidth, _overlayHeight;
+ bool _overlayVisible;
+
+ // Audio
+ int _samplesPerSec;
+
+ // CD Audio
+ SDL_CD *_cdrom;
+ int _cdTrack, _cdNumLoops, _cdStartFrame, _cdDuration;
+ uint32 _cdEndTime, _cdStopTime;
+
+ enum {
+ DF_WANT_RECT_OPTIM = 1 << 0,
+ DF_UPDATE_EXPAND_1_PIXEL = 1 << 1
+ };
+
+ enum {
+ kTransactionNone = 0,
+ kTransactionCommit = 1,
+ kTransactionActive = 2
+ };
+
+ struct TransactionDetails {
+ int mode;
+ bool modeChanged;
+ int w;
+ int h;
+ bool sizeChanged;
+ bool fs;
+ bool fsChanged;
+ bool ar;
+ bool arChanged;
+ bool needHotswap;
+ bool needUpdatescreen;
+ bool needUnload;
+ bool needToggle;
+ bool normal1xScaler;
+ };
+ TransactionDetails _transactionDetails;
+
+ /** Force full redraw on next updateScreen */
+ bool _forceFull;
+ ScalerProc *_scalerProc;
+ int _scalerType;
+ int _scaleFactor;
+ int _mode;
+ int _transactionMode;
+ bool _fullscreen;
+
+ /** Current video mode flags (see DF_* constants) */
+ uint32 _modeFlags;
+ bool _modeChanged;
+ int _screenChangeCount;
+
+ /** True if aspect ratio correction is enabled. */
+ bool _adjustAspectRatio;
+
+ /** True if zoom on mouse is enabled. (only set by > 240 high games) */
+ bool _adjustZoomOnMouse;
+ //_adjustZoomOnMouse = false;
+
+ enum {
+ NUM_DIRTY_RECT = 100,
+
+ MAX_MOUSE_W = 80,
+ MAX_MOUSE_H = 80,
+ MAX_SCALING = 3
+ };
+
+ // Dirty rect management
+ SDL_Rect _dirtyRectList[NUM_DIRTY_RECT];
+ int _numDirtyRects;
+ uint32 *_dirtyChecksums;
+ bool _cksumValid;
+ int _cksumNum;
+
+ // Keyboard mouse emulation. Disabled by fingolfin 2004-12-18.
+ // I am keeping the rest of the code in for now, since the joystick
+ // code (or rather, "hack") uses it, too.
+ struct KbdMouse {
+ int16 x, y, x_vel, y_vel, x_max, y_max, x_down_count, y_down_count;
+ uint32 last_time, delay_time, x_down_time, y_down_time;
+ };
+
+ struct MousePos {
+ // The mouse position, using either virtual (game) or real
+ // (overlay) coordinates.
+ int16 x, y;
+
+ // The size and hotspot of the original cursor image.
+ int16 w, h;
+ int16 hotX, hotY;
+
+ // The size and hotspot of the pre-scaled cursor image, in real
+ // coordinates.
+ int16 rW, rH;
+ int16 rHotX, rHotY;
+
+ // The size and hotspot of the pre-scaled cursor image, in game
+ // coordinates.
+ int16 vW, vH;
+ int16 vHotX, vHotY;
+
+ MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0),
+ rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0),
+ vHotX(0), vHotY(0)
+ { }
+ };
+
+ // mouse
+ KbdMouse _km;
+ bool _mouseVisible;
+ bool _mouseDrawn;
+ byte *_mouseData;
+ SDL_Rect _mouseBackup;
+ MousePos _mouseCurState;
+ //int16 _mouseHotspotX;
+ //int16 _mouseHotspotY;
+ byte _mouseKeyColor;
+ int _cursorTargetScale;
+ //bool _cursorHasOwnPalette;
+ bool _cursorPaletteDisabled;
+ SDL_Surface *_mouseOrigSurface;
+ SDL_Surface *_mouseSurface;
+ enum {
+ kMouseColorKey = 1
+ };
+
+ // joystick
+ SDL_Joystick *_joystick;
+ bool _stickBtn[32];
+
+ // Shake mode
+ int _currentShakePos;
+ int _newShakePos;
+
+ // Palette data
+ SDL_Color *_currentPalette;
+ uint _paletteDirtyStart, _paletteDirtyEnd;
+
+ // Cursor palette data
+ SDL_Color *_cursorPalette;
+
+ /**
+ * Mutex which prevents multiple threads from interfering with each other
+ * when accessing the screen.
+ */
+ MutexRef _graphicsMutex;
+
+
+ void addDirtyRgnAuto(const byte *buf);
+ void makeChecksums(const byte *buf);
+
+ virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false);
+
+ void drawMouse();
+ virtual void undrawMouse();
+ virtual void blitCursor();
+
+ /** Set the position of the virtual mouse cursor. */
+ void setMousePos(int x, int y);
+ virtual void fillMouseEvent(Event &event, int x, int y);
+ //void toggleMouseGrab();
+
+ virtual void internUpdateScreen();
+
+ virtual void loadGFXMode();
+ virtual void unloadGFXMode();
+ virtual void hotswapGFXMode();
+
+ void setFullscreenMode(bool enable);
+ void setAspectRatioCorrection(bool enable);
+
+ void setZoomOnMouse(); // GP2X: On > 240 high games zooms on the mouse + radius.
+
+ virtual bool saveScreenshot(const char *filename);
+
+ int effectiveScreenHeight() const { return (_adjustAspectRatio ? 240 : _screenHeight) * _scaleFactor; }
+
+ void setupIcon();
+ void handleKbdMouse();
+
+ virtual bool remapKey(SDL_Event &ev, Event &event);
+
+ void handleScalerHotkeys(const SDL_KeyboardEvent &key);
+
+ void moveStick();
+};
+
+#endif // GP2X_COMMON_H
diff --git a/backends/platform/gp2x/gp2x-hw.cpp b/backends/platform/gp2x/gp2x-hw.cpp
new file mode 100644
index 0000000000..e967b6df62
--- /dev/null
+++ b/backends/platform/gp2x/gp2x-hw.cpp
@@ -0,0 +1,248 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ * Copyright (C) 2005-2006 John Willis (Portions of the GP2X Backend)
+ *
+ * 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$
+ *
+ */
+
+/*
+ * GP2X: Hardware Stuff.
+ * Thanks to Rlyeh, Snaff, Squidge, Hermes, PS2Reality and RobBrown
+ * for there help with us all getting to grips with this.
+ *
+ */
+
+#include "gp2x-common.h"
+
+#include "gp2x-hw.h"
+
+// Linux includes to let us goof about with the system.
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+
+static unsigned long gp2x_dev[8]={0,0,0,0,0,0,0,0};//, gp2x_ticks_per_second;
+static volatile unsigned short *gp2x_memregs;
+
+/* system registers */
+static struct
+{
+ unsigned short SYSCLKENREG,SYSCSETREG,FPLLVSETREG,DUALINT920,DUALINT940,DUALCTRL940;
+}
+system_reg;
+
+static unsigned short dispclockdiv;
+
+static volatile unsigned short *MEM_REG;
+
+#define SYS_CLK_FREQ 7372800
+
+void GP2X_device_init() {
+ // Open devices
+ if(!gp2x_dev[0]) gp2x_dev[0] = open("/dev/mixer", O_RDWR);
+ if(!gp2x_dev[1]) gp2x_dev[1] = open("/dev/batt", O_RDONLY);
+ if(!gp2x_dev[2]) gp2x_dev[2] = open("/dev/mem", O_RDWR);
+}
+
+void GP2X_device_deinit() {
+ // Close devices
+ if (gp2x_dev[0]) close(gp2x_dev[0]);
+ if (gp2x_dev[1]) close(gp2x_dev[1]);
+ if (gp2x_dev[2]) close(gp2x_dev[2]);
+
+ MEM_REG[0x91c>>1]=system_reg.SYSCSETREG;
+ MEM_REG[0x910>>1]=system_reg.FPLLVSETREG;
+ MEM_REG[0x3B40>>1]=system_reg.DUALINT920;
+ MEM_REG[0x3B42>>1]=system_reg.DUALINT940;
+ MEM_REG[0x3B48>>1]=system_reg.DUALCTRL940;
+ MEM_REG[0x904>>1]=system_reg.SYSCLKENREG;
+ MEM_REG[0x924>>1]=dispclockdiv;
+}
+
+
+// Vairous mixer level fudges.
+// TODO: Clean up and merge quick hacks.
+
+void GP2X_mixer_set_volume(int L /*0..100*/, int R /*0..100*/) {
+
+ /* Set an arbitrary percentage value for the hardware mixer volume.
+
+ Parameters:
+ L (0..100) - volume percentage for the left channel
+ R (0..100) - volume percentage for the right channel
+
+ Note:
+ - A higher percentage than 100 will distort your sound.
+ */
+
+ unsigned char temp[4];
+
+ if (L < 0) L = 0;
+ if (L > GP2X_MAXVOL) L = GP2X_MAXVOL;
+ if (R < 0) R = 0;
+ if (R > GP2X_MAXVOL) R = GP2X_MAXVOL;
+
+ temp[0]=(unsigned char)L;
+ temp[1]=(unsigned char)R;
+ temp[2]=temp[3]=0;
+
+ //warning("GP2X_mixer_set_volume is about to set %d %d", L, R);
+ ioctl(gp2x_dev[0], SOUND_MIXER_WRITE_PCM, temp);
+}
+
+int GP2X_mixer_get_volume() {
+ int vol;
+ ioctl(gp2x_dev[0], SOUND_MIXER_READ_PCM, &vol);
+ //warning("GP2X_mixer_get_volume returned %d %d", (int)((vol & 0xff)), (int)((vol >> 8) & 0xff));
+ return (int)((vol & 0xff));
+}
+
+void GP2X_mixer_move_volume(int UpDown) {
+ // Raise volume 5% if 1 passed, lower 5% if 0.
+ int curvol, newvol;
+ ioctl(gp2x_dev[0], SOUND_MIXER_READ_PCM, &curvol);
+ curvol = ((int)((curvol & 0xff)));
+ newvol = ((int)((curvol & 0xff)));
+ //warning("GP2X_mixer_move_volume got current volume @ %d", curvol);
+ if (UpDown == 1) {
+ newvol = (curvol + 5);
+ } else if (UpDown == 0) {
+ newvol = (curvol - 5);
+ }
+ //warning("GP2X_mixer_move_volume is about to set volume @ %d", newvol);
+ GP2X_mixer_set_volume(newvol, newvol);
+ return;
+}
+
+void GP2X_setCpuspeed(unsigned int mhz)
+{
+ set_FCLK(mhz);
+ set_DCLK_Div(0);
+ set_920_Div(0);
+}
+
+void set_display_clock_div(unsigned div)
+{
+ div=((div & 63) | 64)<<8;
+ MEM_REG[0x924>>1]=(MEM_REG[0x924>>1] & ~(255<<8)) | div;
+}
+
+
+void set_FCLK(unsigned MHZ)
+{
+ unsigned v;
+ unsigned mdiv,pdiv=3,scale=0;
+ MHZ*=1000000;
+ mdiv=(MHZ*pdiv)/SYS_CLK_FREQ;
+ mdiv=((mdiv-8)<<8) & 0xff00;
+ pdiv=((pdiv-2)<<2) & 0xfc;
+ scale&=3;
+ v=mdiv | pdiv | scale;
+ MEM_REG[0x910>>1]=v;
+}
+
+
+void set_920_Div(unsigned short div)
+{
+ unsigned short v;
+ v = MEM_REG[0x91c>>1] & (~0x3);
+ MEM_REG[0x91c>>1] = (div & 0x7) | v;
+}
+
+
+void set_DCLK_Div( unsigned short div )
+{
+ unsigned short v;
+ v = (unsigned short)( MEM_REG[0x91c>>1] & (~(0x7 << 6)) );
+ MEM_REG[0x91c>>1] = ((div & 0x7) << 6) | v;
+}
+
+
+void Disable_940(void)
+{
+ MEM_REG[0x3B42>>1];
+ MEM_REG[0x3B42>>1]=0;
+ MEM_REG[0x3B46>>1]=0xffff;
+ MEM_REG[0x3B48>>1]|= (1 << 7);
+ MEM_REG[0x904>>1]&=0xfffe;
+}
+
+void gp2x_video_wait_vsync(void)
+{
+ MEM_REG[0x2846>>1]=(MEM_REG[0x2846>>1] | 0x20) & ~2;
+ while(!(MEM_REG[0x2846>>1] & 2));
+}
+
+//char GP2X_get_battery_level() {
+ // Returns string of level in English for use in displayMessageOnOSD() to show battery level.
+ //
+ //if (gp2x_dev[1] == -1)
+ //{
+ // warning("Error occured getting voltage status");
+ // return "Unable to read battery level.";
+ //}
+ //
+ //int i;
+ //int battval;
+ //unsigned short cbv;
+ //int v;
+ //
+ //battval = 0;
+ //for (i = 0; i < 1000; i ++)
+ //{
+ // if (read (gp2x_dev[1], &cbv, 2) == 2)
+ // battval += cbv;
+ // if (gp2x_joystick_read() & GP2X_START)
+ // {
+ // needexit = 1;
+ // break;
+ // }
+ //}
+ //if (needexit) break;
+ //
+ //battval /= 1000;
+
+ // Do a very rough translation
+ //if (battval > 1016) v = 37;
+ //else if (battval > 974) v = 33;
+ //else if (battval > 943) v = 32;
+ //else if (battval > 915) v = 31;
+ //else if (battval > 896) v = 30;
+ //else if (battval > 837) v = 29;
+ //else if (battval > 815) v = 28;
+ //else if (battval > 788) v = 27;
+ //else if (battval > 745) v = 26;
+ //else if (battval > 708) v = 25;
+ //else if (battval > 678) v = 24;
+ //else if (battval > 649) v = 23;
+ //else if (battval > 605) v = 22;
+ //else if (battval > 573) v = 21;
+ //else if (battval > 534) v = 20;
+ //else if (battval > 496) v = 19;
+ //else if (battval > 448) v = 18;
+ //else v = 17;
+
+ //gp2x_printf (NULL, 0, 0, "Voltage: ~%d.%dV (%s)", v/10, v%10, v>26?"Battery Full" : v>24?"Battery Medium" : "Battery Empty");
+ //gp2x_video_RGB_flip(0);
+ //}
+ //close (gp2x_dev[1]);
+
+ //return "Voltage: ~%d.%dV (%s)", v/10, v%10, v>26?"Battery Full" : v>24?"Battery Medium" : "Battery Empty";
+//}
diff --git a/backends/platform/gp2x/gp2x-hw.h b/backends/platform/gp2x/gp2x-hw.h
new file mode 100644
index 0000000000..59593882b0
--- /dev/null
+++ b/backends/platform/gp2x/gp2x-hw.h
@@ -0,0 +1,74 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ * Copyright (C) 2005-2006 John Willis (Portions of the GP2X Backend)
+ *
+ * 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$
+ *
+ */
+
+/*
+ * GP2X: Hardware Stuff.
+ *
+ */
+
+#ifndef GP2X_HW_H
+#define GP2X_HW_H
+
+//GP2X Main Joystick Mappings
+//TODO: Use these more standard mappings over the custom ones.
+
+#define GP2X_BUTTON_UP (0)
+#define GP2X_BUTTON_UPLEFT (1)
+#define GP2X_BUTTON_LEFT (2)
+#define GP2X_BUTTON_DOWNLEFT (3)
+#define GP2X_BUTTON_DOWN (4)
+#define GP2X_BUTTON_DOWNRIGHT (5)
+#define GP2X_BUTTON_RIGHT (6)
+#define GP2X_BUTTON_UPRIGHT (7)
+#define GP2X_BUTTON_START (8)
+#define GP2X_BUTTON_SELECT (9)
+#define GP2X_BUTTON_L (10)
+#define GP2X_BUTTON_R (11)
+#define GP2X_BUTTON_A (12)
+#define GP2X_BUTTON_B (13)
+#define GP2X_BUTTON_X (14)
+#define GP2X_BUTTON_Y (15)
+#define GP2X_BUTTON_VOLUP (16)
+#define GP2X_BUTTON_VOLDOWN (17)
+#define GP2X_BUTTON_CLICK (18)
+
+#define GP2X_MAXVOL 100 // Highest level permitted by GP2X's mixer
+#define SYS_CLK_FREQ 7372800 // Clock Frequency
+
+extern void GP2X_device_init();
+extern void GP2X_device_deinit();
+extern void GP2X_mixer_set_volume(int, int);
+extern int GP2X_mixer_get_volume();
+extern void GP2X_mixer_move_volume(int);
+extern void GP2X_setCpuspeed(unsigned int cpuspeed);
+
+extern void save_system_regs(void); /* save some registers */
+extern void set_display_clock_div(unsigned div);
+extern void set_FCLK(unsigned MHZ); /* adjust the clock frequency (in Mhz units) */
+extern void set_920_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+div)) */
+extern void set_DCLK_Div(unsigned short div); /* 0 to 7 divider (freq=FCLK/(1+div)) */
+extern void Disable_940(void); /* 940t down */
+extern void gp2x_video_wait_vsync(void);
+
+#endif //GP2X_HW_H
diff --git a/backends/platform/gp2x/gp2x-mem.c b/backends/platform/gp2x/gp2x-mem.c
new file mode 100644
index 0000000000..fa09c2c4bd
--- /dev/null
+++ b/backends/platform/gp2x/gp2x-mem.c
@@ -0,0 +1,300 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ * Copyright (C) 2005-2006 John Willis (Portions of the GP2X Backend)
+ *
+ * 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$
+ *
+ */
+
+/*
+ * GP2X: Memory tweaking stuff.
+ *
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gp2x-mem.h"
+
+void InitRam (void)
+{
+ if(!gp2x_dev)
+ {
+ gp2x_dev = open("/dev/mem", O_RDWR);
+ gp2x_ram = (unsigned short *)mmap(0, 0x10000, 3, 1, gp2x_dev, 0x03000000);
+ gp2x_memregs = (unsigned short *)mmap(0, 0x10000, 3, 1, gp2x_dev, 0xc0000000);
+ }
+}
+
+void CloseRam (void)
+{
+ if(gp2x_dev) close(gp2x_dev);
+}
+
+/*
+****** [BEGIN] Squidge's MMU hack code ******
+*/
+
+int myuname(char *buffer)
+{
+ asm volatile ("swi #0x90007a");
+}
+
+void DecodeCoarse (unsigned int indx, unsigned int sa)
+{
+ unsigned int cpt[256];
+ unsigned int temp;
+ unsigned int i = 0;
+ unsigned int wb = 0;
+
+ sa &= 0xfffffc00;
+ indx *= 1048576;
+
+ //printf (" > %08X\n", sa);
+ //printf ("%d\n",
+ lseek (gp2x_dev, sa, SEEK_SET);
+ memset (cpt, 0, 256*4);
+ temp = read (gp2x_dev, cpt, 256*4);
+ //printf ("%d\n", temp);
+ if (temp != 256*4)
+ {
+ printf (" # Bad read\n");
+ return;
+ }
+
+ //printf ("%08X %08X %08X %08X\n", cpt[0], cpt[4], cpt[8], cpt[12]);
+
+ for (i = 0; i < 256; i ++)
+ {
+ if (cpt[i])
+ {
+ switch (cpt[i] & 3)
+ {
+ case 0:
+ //printf (" -- [%08X] Invalid --\n", cpt[i]);
+ break;
+ case 1:
+ /*
+ printf (" VA: %08X PA: %08X - %08X A: %d %d %d %d D: %d C: %d B: %d\n", indx,
+ cpt[i] & 0xFFFF0000, (cpt[i] & 0xFFFF0000) | 0xFFFF,
+ (cpt[i] >> 10) & 3, (cpt[i] >> 8) & 3, (cpt[i] >> 6) & 3,
+ (cpt[i] >> 4) & 3, dom, (cpt[i] >> 3) & 1, (cpt[i] >> 2) & 1);
+ */
+ break;
+ case 2:
+ //a=((cpt[i] & 0xff000000)>>24);
+ /*printf (" VA: %08X PA: %08X - %08X A: %d %d %d %d D: %d C: %d B: %d\n", indx,
+ cpt[i] & 0xfffff000, (cpt[i] & 0xfffff000) | 0xFFF,
+ (cpt[i] >> 10) & 3, (cpt[i] >> 8) & 3, (cpt[i] >> 6) & 3,
+ (cpt[i] >> 4) & 3, dom, (cpt[i] >> 3) & 1, (cpt[i] >> 2) & 1);
+ */
+ // This is where we look for any virtual addresses that map to physical address 0x03000000 and
+ // alter the cachable and bufferable bits...
+ if (((cpt[i] & 0xff000000) == 0x02000000) )
+ {
+ //printf("SOUND c and b bits not set, overwriting\n");
+ if((cpt[i] & 12)==0) {
+ cpt[i] |= 0xFFC;
+ wb++;
+ }
+ }
+ //if ((a>=0x31 && a<=0x36) && ((cpt[i] & 12)==0))
+ if (((cpt[i] & 0xff000000) == 0x03000000) )
+ {
+ //printf("SDL c and b bits not set, overwriting\n");
+ if((cpt[i] & 12)==0) {
+ cpt[i] |= 0xFFC;
+ wb++;
+ }
+ }
+ break;
+ case 3:
+ //printf (" -- [%08X/%d] Unsupported --\n", cpt[i],cpt[i] & 3);
+ break;
+ default:
+ //printf (" -- [%08X/%d] Unknown --\n", cpt[i], cpt[i] & 3);
+ break;
+ }
+ }
+ indx += 4096;
+ }
+ //printf ("%08X %08X %08X %08X\n", cpt[0], cpt[4], cpt[8], cpt[12]);
+ if (wb)
+ {
+ //printf("Hacking cpt\n");
+ lseek (gp2x_dev, sa, SEEK_SET);
+ temp = write (gp2x_dev, cpt, 256*4);
+ printf("%d bytes written, %s\n", temp, temp == 1024 ? "yay!" : "oh fooble :(!");
+ }
+}
+
+void dumppgtable (unsigned int ttb)
+{
+ unsigned int pgtable[4096];
+ char *desctypes[] = {"Invalid", "Coarse", "Section", "Fine"};
+
+ memset (pgtable, 0, 4096*4);
+ lseek (gp2x_dev, ttb, SEEK_SET);
+ read (gp2x_dev, pgtable, 4096*4);
+
+ int i;
+ for (i = 0; i < 4096; i ++)
+ {
+ int temp;
+
+ if (pgtable[i])
+ {
+ //printf ("Indx: %d VA: %08X Type: %d [%s] \n", i, i * 1048576, pgtable[i] & 3, desctypes[pgtable[i]&3]);
+ switch (pgtable[i]&3)
+ {
+ case 0:
+ //printf (" -- Invalid --\n");
+ break;
+ case 1:
+ DecodeCoarse(i, pgtable[i]);
+ break;
+ case 2:
+ temp = pgtable[i] & 0xFFF00000;
+ //printf (" PA: %08X - %08X A: %d D: %d C: %d B: %d\n", temp, temp | 0xFFFFF,
+ // (pgtable[i] >> 10) & 3, (pgtable[i] >> 5) & 15, (pgtable[i] >> 3) & 1,
+ // (pgtable[i] >> 2) & 1);
+
+ break;
+ case 3:
+ printf (" -- Unsupported! --\n");
+ break;
+ }
+ }
+ }
+}
+
+int hackpgtable (void)
+{
+ unsigned int oldc1, oldc2, oldc3, oldc4;
+ unsigned int newc1 = 0xee120f10, newc2 = 0xe12fff1e;
+ unsigned int ttb, ttx;
+ int a=0;int try=0;
+ // We need to execute a "MRC p15, 0, r0, c2, c0, 0", to get the pointer to the translation table base, but we can't
+ // do this in user mode, so we have to patch the kernel to get it to run it for us in supervisor mode. We dothis
+ // at the moment by overwriting the sys_newuname function and then calling it.
+
+ lseek (gp2x_dev, 0x6ec00, SEEK_SET); // fixme: We should ask the kernel for this address rather than assuming it...
+ read (gp2x_dev, &oldc1, 4);
+ read (gp2x_dev, &oldc2, 4);
+ read (gp2x_dev, &oldc3, 4);
+ read (gp2x_dev, &oldc4, 4);
+
+ printf ("0:%08X %08X - %08X %08X\n", oldc1, oldc2, newc1, newc2);
+
+
+
+ printf ("point1 %d\n",a);
+ do {
+ lseek (gp2x_dev, 0x6ec00, SEEK_SET);
+ a+=write (gp2x_dev, &newc1, 4);
+ a+=write (gp2x_dev, &newc2, 4);
+ SDL_Delay(200);
+ try++;
+ ttb = myuname(name);
+ printf ("2:%08X try %d\n", ttb,try);
+ } while (ttb==0 && try<4);
+
+
+
+ lseek (gp2x_dev, 0x6ec00, SEEK_SET);
+ a+=write (gp2x_dev, &oldc1, 4);
+ a+=write (gp2x_dev, &oldc2, 4);
+
+ printf ("2:%08X %d\n", ttb,a);
+ if (ttb!=0) {
+
+
+ //printf ("Restored contents\n");
+
+ // We now have the translation table base ! Walk the table looking for our allocation and hack it :)
+ dumppgtable(ttb);
+
+ // Now drain the write buffer and flush the tlb caches. Something else we can't do in user mode...
+ unsigned int tlbc1 = 0xe3a00000; // mov r0, #0
+ unsigned int tlbc2 = 0xee070f9a; // mcr 15, 0, r0, cr7, cr10, 4
+ unsigned int tlbc3 = 0xee080f17; // mcr 15, 0, r0, cr8, cr7, 0
+ unsigned int tlbc4 = 0xe1a0f00e; // mov pc, lr
+
+ lseek (gp2x_dev, 0x6ec00, SEEK_SET);
+ write (gp2x_dev, &tlbc1, 4);
+ write (gp2x_dev, &tlbc2, 4);
+ write (gp2x_dev, &tlbc3, 4);
+ write (gp2x_dev, &tlbc4, 4);
+
+ SDL_Delay(200);
+
+ ttx = myuname(name);
+
+ printf ("Return from uname: %08X\n", ttx);
+
+ lseek (gp2x_dev, 0x6ec00, SEEK_SET);
+ write (gp2x_dev, &oldc1, 4);
+ write (gp2x_dev, &oldc2, 4);
+ write (gp2x_dev, &oldc3, 4);
+ write (gp2x_dev, &oldc4, 4);
+ lseek (gp2x_dev, 0x0, SEEK_SET);
+ return 0;
+ }
+
+ lseek (gp2x_dev, 0x0, SEEK_SET);
+ return 1;
+ //printf ("Restored contents\n");
+
+ //printf ("Pagetable after modification!\n");
+ //printf ("-------------------------------\n");
+ //dumppgtable(ttb);
+}
+
+/*
+****** [END] Squidge's MMU hack code ******
+*/
+
+void SetClock (unsigned c)
+{
+ unsigned v;
+ unsigned mdiv,pdiv=3,scale=0;
+
+ // Set ARM920t clock
+ c *= 1000000;
+ mdiv = (c*pdiv) / SYS_CLK_FREQ;
+ mdiv = ((mdiv-8)<<8) & 0xff00;
+ pdiv = ((pdiv-2)<<2) & 0xfc;
+ scale &= 3;
+ v = mdiv | pdiv | scale;
+ gp2x_memregs[0x910>>1] = v;
+}
+
+void MMUpatch (void)
+{
+ volatile unsigned int *secbuf = (unsigned int *)malloc (204800);
+
+ // Squidge's MMU hack
+ hackpgtable();
+}
diff --git a/backends/platform/gp2x/gp2x-mem.h b/backends/platform/gp2x/gp2x-mem.h
new file mode 100644
index 0000000000..a7a5490205
--- /dev/null
+++ b/backends/platform/gp2x/gp2x-mem.h
@@ -0,0 +1,57 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ * Copyright (C) 2005-2006 John Willis (Portions of the GP2X Backend)
+ *
+ * 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$
+ *
+ */
+
+/*
+ * GP2X: Memory Stuff.
+ *
+ */
+
+#ifndef GP2X_MEM_H
+#define GP2X_MEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// Use Squidge's MMU patch rather then myown (his is neater).
+// The effect if not that great but cacheing the upper RAM is no bad thing (tm) ;).
+
+void InitRam (void);
+void CloseRam (void);
+// Set ARM920t clock frequency
+void SetClock (unsigned c);
+void MMUpatch (void);
+
+#define SYS_CLK_FREQ 7372800
+
+char name[256];
+unsigned long gp2x_dev;
+volatile unsigned short *gp2x_ram, *gp2x_memregs;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif //GP2X_MEM_H
diff --git a/backends/platform/gp2x/gp2x.cpp b/backends/platform/gp2x/gp2x.cpp
new file mode 100644
index 0000000000..7da510ad29
--- /dev/null
+++ b/backends/platform/gp2x/gp2x.cpp
@@ -0,0 +1,298 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ * Copyright (C) 2005-2006 John Willis (Portions of the GP2X Backend)
+ *
+ * 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$
+ *
+ */
+
+/*
+ * GP2X: Main backend.
+ *
+ */
+
+#include "backends/platform/gp2x/gp2x-common.h"
+#include "backends/platform/gp2x/gp2x-hw.h"
+#include "backends/platform/gp2x/gp2x-mem.h"
+#include "common/config-manager.h"
+#include "common/util.h"
+#include "base/main.h"
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+int main(int argc, char *argv[]) {
+
+ // Setup GP2X upper 32MB caching
+ //InitRam();
+ //MMUpatch();
+
+ extern OSystem *OSystem_GP2X_create();
+ g_system = OSystem_GP2X_create();
+ assert(g_system);
+
+ // Invoke the actual ScummVM main entry point:
+ int res = scummvm_main(argc, argv);
+ g_system->quit();
+ return res;
+}
+
+OSystem *OSystem_GP2X_create() {
+ return new OSystem_GP2X();
+}
+
+void OSystem_GP2X::initBackend() {
+ assert(!_inited);
+
+ ConfMan.set("joystick_num", 0);
+ int joystick_num = ConfMan.getInt("joystick_num");
+ uint32 sdlFlags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
+
+ if (ConfMan.hasKey("disable_sdl_parachute"))
+ sdlFlags |= SDL_INIT_NOPARACHUTE;
+
+ if (joystick_num > -1)
+ sdlFlags |= SDL_INIT_JOYSTICK;
+
+ if (SDL_Init(sdlFlags) == -1) {
+ error("Could not initialize SDL: %s", SDL_GetError());
+ }
+
+ // TODO: Clean way of flushing the file on every write without resorting to this or hacking the POSIX FS code.
+ //system("/bin/mount -t vfat -o remount,sync,iocharset=utf8 /dev/mmcsd/disc0/part1 /mnt/sd");
+
+ _graphicsMutex = createMutex();
+
+ _cksumValid = false;
+ _mode = GFX_NORMAL;
+ _scaleFactor = 0;
+ _scalerProc = Normal1x;
+ _fullscreen = true;
+ _adjustAspectRatio = ConfMan.getBool("aspect_ratio");
+ _scalerType = 0;
+ _modeFlags = 0;
+ _adjustZoomOnMouse = false;
+ ConfMan.setBool("FM_low_quality", true);
+
+ // enable joystick
+ if (joystick_num > -1 && SDL_NumJoysticks() > 0) {
+ printf("Using joystick: %s\n", SDL_JoystickName(0));
+ _joystick = SDL_JoystickOpen(joystick_num);
+ }
+
+ // Initialise any GP2X specific stuff we may want (Volume, Batt Status etc.)
+ GP2X_device_init();
+
+ // Set Default hardware mixer volume to a plesent level.
+ // This is done to 'reset' volume level if set by other apps.
+ GP2X_mixer_set_volume(70, 70);
+
+ SDL_ShowCursor(SDL_DISABLE);
+
+ _inited = true;
+}
+
+OSystem_GP2X::OSystem_GP2X()
+ :
+ _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0),
+ _hwscreen(0), _screen(0), _screenWidth(0), _screenHeight(0),
+ _tmpscreen(0), _overlayWidth(0), _overlayHeight(0),
+ _overlayVisible(false),
+ _overlayscreen(0), _tmpscreen2(0),
+ _samplesPerSec(0),
+ _cdrom(0), _scalerProc(0), _modeChanged(false), _screenChangeCount(0), _dirtyChecksums(0),
+ _mouseVisible(false), _mouseDrawn(false), _mouseData(0), _mouseSurface(0),
+ _mouseOrigSurface(0), _cursorTargetScale(1), _cursorPaletteDisabled(true),
+ _joystick(0),
+ _currentShakePos(0), _newShakePos(0),
+ _paletteDirtyStart(0), _paletteDirtyEnd(0),
+ _graphicsMutex(0), _transactionMode(kTransactionNone) {
+
+ // allocate palette storage
+ _currentPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
+ _cursorPalette = (SDL_Color *)calloc(sizeof(SDL_Color), 256);
+
+ _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
+
+ // reset mouse state
+ memset(&_km, 0, sizeof(_km));
+ memset(&_mouseCurState, 0, sizeof(_mouseCurState));
+
+ _inited = false;
+}
+
+OSystem_GP2X::~OSystem_GP2X() {
+ free(_dirtyChecksums);
+ free(_currentPalette);
+ free(_cursorPalette);
+ free(_mouseData);
+}
+
+uint32 OSystem_GP2X::getMillis() {
+ return SDL_GetTicks();
+}
+
+void OSystem_GP2X::delayMillis(uint msecs) {
+ SDL_Delay(msecs);
+}
+
+void OSystem_GP2X::setTimerCallback(TimerProc callback, int timer) {
+ SDL_SetTimer(timer, (SDL_TimerCallback) callback);
+}
+
+bool OSystem_GP2X::hasFeature(Feature f) {
+ return
+ (f == kFeatureFullscreenMode) ||
+ (f == kFeatureAspectRatioCorrection) ||
+ (f == kFeatureAutoComputeDirtyRects) ||
+ (f == kFeatureCursorHasPalette);
+}
+
+void OSystem_GP2X::setFeatureState(Feature f, bool enable) {
+ switch (f) {
+ case kFeatureFullscreenMode:
+ return;
+ case kFeatureAspectRatioCorrection:
+ setAspectRatioCorrection(enable);
+ break;
+ case kFeatureAutoComputeDirtyRects:
+ if (enable)
+ _modeFlags |= DF_WANT_RECT_OPTIM;
+ else
+ _modeFlags &= ~DF_WANT_RECT_OPTIM;
+ break;
+ default:
+ break;
+ }
+}
+
+bool OSystem_GP2X::getFeatureState(Feature f) {
+ assert (_transactionMode == kTransactionNone);
+
+ switch (f) {
+ case kFeatureFullscreenMode:
+ return false;
+ //case kFeatureFullscreenMode:
+ // return _fullscreen;
+ case kFeatureAspectRatioCorrection:
+ return _adjustAspectRatio;
+ case kFeatureAutoComputeDirtyRects:
+ return _modeFlags & DF_WANT_RECT_OPTIM;
+ default:
+ return false;
+ }
+}
+
+void OSystem_GP2X::quit() {
+ unloadGFXMode();
+ deleteMutex(_graphicsMutex);
+
+ if (_joystick)
+ SDL_JoystickClose(_joystick);
+ //CloseRam();
+ GP2X_device_deinit();
+ SDL_Quit();
+ chdir("/usr/gp2x");
+ execl("/usr/gp2x/gp2xmenu", "/usr/gp2x/gp2xmenu", NULL);
+}
+
+OSystem::MutexRef OSystem_GP2X::createMutex(void) {
+ return (MutexRef) SDL_CreateMutex();
+}
+
+void OSystem_GP2X::lockMutex(MutexRef mutex) {
+ SDL_mutexP((SDL_mutex *) mutex);
+}
+
+void OSystem_GP2X::unlockMutex(MutexRef mutex) {
+ SDL_mutexV((SDL_mutex *) mutex);
+}
+
+void OSystem_GP2X::deleteMutex(MutexRef mutex) {
+ SDL_DestroyMutex((SDL_mutex *) mutex);
+}
+
+#pragma mark -
+#pragma mark --- Audio ---
+#pragma mark -
+
+bool OSystem_GP2X::setSoundCallback(SoundProc proc, void *param) {
+ SDL_AudioSpec desired;
+ SDL_AudioSpec obtained;
+
+ memset(&desired, 0, sizeof(desired));
+
+ _samplesPerSec = 0;
+
+ if (ConfMan.hasKey("output_rate"))
+ _samplesPerSec = ConfMan.getInt("output_rate");
+
+ if (_samplesPerSec <= 0)
+ _samplesPerSec = SAMPLES_PER_SEC;
+
+ //Quick EVIL Hack - DJWillis
+ _samplesPerSec = 11025;
+
+ desired.freq = _samplesPerSec;
+ desired.format = AUDIO_S16SYS;
+ desired.channels = 2;
+ //desired.samples = (uint16)samples;
+ desired.samples = 128; // Samples hack
+ desired.callback = proc;
+ desired.userdata = param;
+ if (SDL_OpenAudio(&desired, &obtained) != 0) {
+ warning("Could not open audio device: %s", SDL_GetError());
+ return false;
+ }
+ _samplesPerSec = obtained.freq;
+ SDL_PauseAudio(0);
+ return true;
+}
+
+void OSystem_GP2X::clearSoundCallback() {
+ SDL_CloseAudio();
+}
+
+int OSystem_GP2X::getOutputSampleRate() const {
+ return _samplesPerSec;
+}
+
+#pragma mark -
+#pragma mark --- CD Audio ---
+#pragma mark -
+
+bool OSystem_GP2X::openCD(int drive) {
+ return (_cdrom = NULL);
+}
+
+void OSystem_GP2X::stopCD() {
+}
+
+void OSystem_GP2X::playCD(int track, int num_loops, int start_frame, int duration) {
+ return;
+}
+
+bool OSystem_GP2X::pollCD() {
+ return false;
+}
+
+void OSystem_GP2X::updateCD() {
+ return;
+}
diff --git a/backends/platform/gp2x/graphics.cpp b/backends/platform/gp2x/graphics.cpp
new file mode 100644
index 0000000000..64f31f10e4
--- /dev/null
+++ b/backends/platform/gp2x/graphics.cpp
@@ -0,0 +1,1722 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ * Copyright (C) 2005-2006 John Willis (Portions of the GP2X Backend)
+ *
+ * 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$
+ *
+ */
+
+/*
+ * GP2X: Graphics handling.
+ *
+ */
+
+#include "backends/platform/gp2x/gp2x-common.h"
+#include "graphics/scaler.h"
+#include "common/util.h"
+#include "graphics/font.h"
+#include "graphics/fontman.h"
+#include "graphics/surface.h"
+
+static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
+ {"GP2X Graphics Mode", "1x", GFX_NORMAL},
+ {0, 0, 0}
+};
+
+// Table of relative scalers magnitudes
+// [definedScale - 1][_scaleFactor - 1]
+static ScalerProc *scalersMagn[3][3] = {
+ { Normal1x, Normal1x, Normal1x },
+ { Normal1x, Normal1x, Normal1x },
+ { Normal1x, Normal1x, Normal1x }
+};
+
+static const int s_gfxModeSwitchTable[][4] = {
+ { GFX_NORMAL, GFX_DOUBLESIZE, GFX_TRIPLESIZE, -1 },
+ { GFX_NORMAL, GFX_ADVMAME2X, GFX_ADVMAME3X, -1 },
+ { GFX_NORMAL, GFX_HQ2X, GFX_HQ3X, -1 },
+ { GFX_NORMAL, GFX_2XSAI, -1, -1 },
+ { GFX_NORMAL, GFX_SUPER2XSAI, -1, -1 },
+ { GFX_NORMAL, GFX_SUPEREAGLE, -1, -1 },
+ { GFX_NORMAL, GFX_TV2X, -1, -1 },
+ { GFX_NORMAL, GFX_DOTMATRIX, -1, -1 }
+ };
+
+static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY);
+
+const OSystem::GraphicsMode *OSystem_GP2X::getSupportedGraphicsModes() const {
+ return s_supportedGraphicsModes;
+}
+
+int OSystem_GP2X::getDefaultGraphicsMode() const {
+ return GFX_NORMAL;
+}
+
+void OSystem_GP2X::beginGFXTransaction(void) {
+ assert (_transactionMode == kTransactionNone);
+
+ _transactionMode = kTransactionActive;
+
+ _transactionDetails.modeChanged = false;
+ _transactionDetails.sizeChanged = false;
+ _transactionDetails.arChanged = false;
+ _transactionDetails.fsChanged = false;
+
+ _transactionDetails.needHotswap = false;
+ _transactionDetails.needUpdatescreen = false;
+ _transactionDetails.needUnload = false;
+
+ _transactionDetails.normal1xScaler = false;
+}
+
+void OSystem_GP2X::endGFXTransaction(void) {
+ // for each engine we run initCommonGFX() as first thing in the transaction
+ // and initSize() is called later. If user runs launcher at 320x200 with
+ // 2x overlay, setting to Nomral1x sclaler in that case will be suppressed
+ // and backend is forced to 2x
+ //
+ // This leads to bad results such as 1280x960 window for 640x480 engines.
+ // To prevent that we rerun setGraphicsMode() if there was 1x scaler request
+ if (_transactionDetails.normal1xScaler)
+ setGraphicsMode(GFX_NORMAL);
+
+ assert (_transactionMode == kTransactionActive);
+
+ _transactionMode = kTransactionCommit;
+ if (_transactionDetails.modeChanged)
+ setGraphicsMode(_transactionDetails.mode);
+
+ if (_transactionDetails.sizeChanged)
+ initSize(_transactionDetails.w, _transactionDetails.h);
+
+ if (_transactionDetails.arChanged)
+ setAspectRatioCorrection(_transactionDetails.ar);
+
+ if (_transactionDetails.needUnload) {
+ unloadGFXMode();
+ loadGFXMode();
+ clearOverlay();
+ } else {
+ if (!_transactionDetails.fsChanged) {
+ if (_transactionDetails.needHotswap)
+ hotswapGFXMode();
+ else if (_transactionDetails.needUpdatescreen)
+ internUpdateScreen();
+ }
+ }
+
+ if (_transactionDetails.fsChanged)
+ setFullscreenMode(_transactionDetails.fs);
+
+ _transactionMode = kTransactionNone;
+}
+
+bool OSystem_GP2X::setGraphicsMode(int mode) {
+ Common::StackLock lock(_graphicsMutex);
+
+ int newScaleFactor = 1;
+ ScalerProc *newScalerProc;
+
+ mode = GFX_NORMAL;
+ newScaleFactor = 1;
+ newScalerProc = Normal1x;
+
+ _transactionDetails.normal1xScaler = (mode == GFX_NORMAL);
+
+ _mode = mode;
+ _scalerProc = newScalerProc;
+
+ if (_transactionMode == kTransactionActive) {
+ _transactionDetails.mode = mode;
+ _transactionDetails.modeChanged = true;
+
+ if (newScaleFactor != _scaleFactor) {
+ _transactionDetails.needHotswap = true;
+ _scaleFactor = newScaleFactor;
+ }
+
+ _transactionDetails.needUpdatescreen = true;
+
+ return true;
+ }
+
+ // NOTE: This should not be executed at transaction commit
+ // Otherwise there is some unsolicited setGraphicsMode() call
+ // which should be properly removed
+ if (newScaleFactor != _scaleFactor) {
+ assert(_transactionMode != kTransactionCommit);
+
+ _scaleFactor = newScaleFactor;
+ hotswapGFXMode();
+ }
+
+ // Determine the "scaler type", i.e. essentially an index into the
+ // s_gfxModeSwitchTable array defined in events.cpp.
+ if (_mode != GFX_NORMAL) {
+ for (int i = 0; i < ARRAYSIZE(s_gfxModeSwitchTable); i++) {
+ if (s_gfxModeSwitchTable[i][1] == _mode || s_gfxModeSwitchTable[i][2] == _mode) {
+ _scalerType = i;
+ break;
+ }
+ }
+ }
+
+ if (!_screen)
+ return true;
+
+ // Blit everything to the screen
+ _forceFull = true;
+
+ // Even if the old and new scale factors are the same, we may have a
+ // different scaler for the cursor now.
+ blitCursor();
+
+ if (_transactionMode != kTransactionCommit)
+ internUpdateScreen();
+
+ // Make sure that an EVENT_SCREEN_CHANGED gets sent later
+ _modeChanged = true;
+
+ return true;
+}
+
+int OSystem_GP2X::getGraphicsMode() const {
+ assert (_transactionMode == kTransactionNone);
+ return _mode;
+}
+
+void OSystem_GP2X::initSize(uint w, uint h){
+ // Avoid redundant res changes
+ if ((int)w == _screenWidth && (int)h == _screenHeight &&
+ _transactionMode != kTransactionCommit)
+ return;
+
+ _screenWidth = w;
+ _screenHeight = h;
+
+ _cksumNum = (_screenWidth * _screenHeight / (8 * 8));
+
+ if (_transactionMode == kTransactionActive) {
+ _transactionDetails.w = w;
+ _transactionDetails.h = h;
+ _transactionDetails.sizeChanged = true;
+
+ _transactionDetails.needUnload = true;
+
+ return;
+ }
+
+ free(_dirtyChecksums);
+ _dirtyChecksums = (uint32 *)calloc(_cksumNum * 2, sizeof(uint32));
+
+ if (_transactionMode != kTransactionCommit) {
+ unloadGFXMode();
+ loadGFXMode();
+
+ // if initSize() gets called in the middle, overlay is not transparent
+ clearOverlay();
+ }
+}
+
+void OSystem_GP2X::loadGFXMode() {
+
+ //enable 320x240 image to fit the 320x240 display area (aka, disable scaling)
+ //gp2x_video_RGB_setscaling(320,240);
+
+ assert(_inited);
+ _forceFull = true;
+ _modeFlags |= DF_UPDATE_EXPAND_1_PIXEL;
+
+ int hwW, hwH;
+
+#ifndef __MAEMO__
+ _overlayWidth = _screenWidth * _scaleFactor;
+ _overlayHeight = _screenHeight * _scaleFactor;
+
+ if (_screenHeight != 200)
+ _adjustAspectRatio = false;
+
+ if (_adjustAspectRatio)
+ _overlayHeight = real2Aspect(_overlayHeight);
+
+ hwW = _screenWidth * _scaleFactor;
+ hwH = effectiveScreenHeight();
+#else
+ hwW = _overlayWidth;
+ hwH = _overlayHeight;
+#endif
+
+ //
+ // Create the surface that contains the 8 bit game data
+ //
+ _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _screenWidth, _screenHeight, 8, 0, 0, 0, 0);
+ if (_screen == NULL)
+ error("allocating _screen failed");
+
+ //
+ // Create the surface that contains the graphics in 16 bit mode
+ //
+
+ // FIXME: Hack for GP2X SDL querks.
+ if (_screenWidth <= 320) {
+ _hwscreen = SDL_SetVideoMode(320, 240, 16, SDL_FULLSCREEN|SDL_SWSURFACE);
+ } else {
+ _hwscreen = SDL_SetVideoMode(_screenWidth, _screenHeight, 16, SDL_FULLSCREEN|SDL_SWSURFACE);
+ }
+
+ if (_hwscreen == NULL) {
+ warning("SDL_SetVideoMode says we can't switch to that mode");
+ quit();
+ }
+
+ // GP2X Specific, must be called after any SDL_SetVideoMode to ensure the hardware cursor is off.
+ // Note: On the GP2X SDL_SetVideoMode recalls SDL_Init().
+ SDL_ShowCursor(SDL_DISABLE);
+
+
+ //
+ // Create the surface used for the graphics in 16 bit before scaling, and also the overlay
+ //
+
+ // Distinguish 555 and 565 mode
+ if (_hwscreen->format->Rmask == 0x7C00)
+ InitScalers(555);
+ else
+ InitScalers(565);
+
+ // Need some extra bytes around when using 2xSaI
+ _tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _screenWidth + 3, _screenHeight + 3,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_tmpscreen == NULL)
+ error("allocating _tmpscreen failed");
+
+ _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _overlayWidth, _overlayHeight,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_overlayscreen == NULL)
+ error("allocating _overlayscreen failed");
+
+ _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _overlayWidth + 3, _overlayHeight + 3,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_tmpscreen2 == NULL)
+ error("allocating _tmpscreen2 failed");
+
+ _osdSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
+ _hwscreen->w,
+ _hwscreen->h,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+ if (_osdSurface == NULL)
+ error("allocating _osdSurface failed");
+ SDL_SetColorKey(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kOSDColorKey);
+
+ // keyboard cursor control, some other better place for it?
+ _km.x_max = _screenWidth * _scaleFactor - 1;
+ _km.y_max = effectiveScreenHeight() - 1;
+ _km.delay_time = 25;
+ _km.last_time = 0;
+
+}
+
+void OSystem_GP2X::unloadGFXMode() {
+ if (_screen) {
+ SDL_FreeSurface(_screen);
+ _screen = NULL;
+ }
+
+ if (_hwscreen) {
+ SDL_FreeSurface(_hwscreen);
+ _hwscreen = NULL;
+ }
+
+ if (_tmpscreen) {
+ SDL_FreeSurface(_tmpscreen);
+ _tmpscreen = NULL;
+ }
+
+ if (_tmpscreen2) {
+ SDL_FreeSurface(_tmpscreen2);
+ _tmpscreen2 = NULL;
+ }
+
+ if (_overlayscreen) {
+ SDL_FreeSurface(_overlayscreen);
+ _overlayscreen = NULL;
+ }
+
+ if (_osdSurface) {
+ SDL_FreeSurface(_osdSurface);
+ _osdSurface = NULL;
+ }
+}
+
+void OSystem_GP2X::hotswapGFXMode() {
+ if (!_screen)
+ return;
+
+ // Keep around the old _screen & _overlayscreen so we can restore the screen data
+ // after the mode switch.
+ SDL_Surface *old_screen = _screen;
+ SDL_Surface *old_overlayscreen = _overlayscreen;
+
+ // Release the HW screen surface
+ SDL_FreeSurface(_hwscreen);
+
+ SDL_FreeSurface(_tmpscreen);
+ SDL_FreeSurface(_tmpscreen2);
+
+ // Release the OSD surface
+ SDL_FreeSurface(_osdSurface);
+
+ // Setup the new GFX mode
+ loadGFXMode();
+
+ // reset palette
+ SDL_SetColors(_screen, _currentPalette, 0, 256);
+
+ // Restore old screen content
+ SDL_BlitSurface(old_screen, NULL, _screen, NULL);
+ SDL_BlitSurface(old_overlayscreen, NULL, _overlayscreen, NULL);
+
+ // Free the old surfaces
+ SDL_FreeSurface(old_screen);
+ SDL_FreeSurface(old_overlayscreen);
+
+ // Update cursor to new scale
+ blitCursor();
+
+ // Blit everything to the screen
+ internUpdateScreen();
+
+ // Make sure that an EVENT_SCREEN_CHANGED gets sent later
+ _modeChanged = true;
+}
+
+void OSystem_GP2X::updateScreen() {
+ assert (_transactionMode == kTransactionNone);
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+
+ internUpdateScreen();
+}
+
+void OSystem_GP2X::internUpdateScreen() {
+ SDL_Surface *srcSurf, *origSurf;
+ int height, width;
+ ScalerProc *scalerProc;
+ int scale1;
+
+#if defined (DEBUG) && ! defined(_WIN32_WCE) // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?)
+ assert(_hwscreen != NULL);
+ assert(_hwscreen->map->sw_data != NULL);
+#endif
+
+ // If the shake position changed, fill the dirty area with blackness
+ if (_currentShakePos != _newShakePos) {
+ SDL_Rect blackrect = {0, 0, _screenWidth * _scaleFactor, _newShakePos * _scaleFactor};
+
+ if (_adjustAspectRatio && !_overlayVisible)
+ blackrect.h = real2Aspect(blackrect.h - 1) + 1;
+
+ SDL_FillRect(_hwscreen, &blackrect, 0);
+
+ _currentShakePos = _newShakePos;
+
+ _forceFull = true;
+ }
+
+ // Check whether the palette was changed in the meantime and update the
+ // screen surface accordingly.
+ if (_screen && _paletteDirtyEnd != 0) {
+ SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart,
+ _paletteDirtyStart,
+ _paletteDirtyEnd - _paletteDirtyStart);
+
+ _paletteDirtyEnd = 0;
+
+ _forceFull = true;
+ }
+ // OSD visible (i.e. non-transparent)?
+ if (_osdAlpha != SDL_ALPHA_TRANSPARENT) {
+ // Updated alpha value
+ const int diff = SDL_GetTicks() - _osdFadeStartTime;
+ if (diff > 0) {
+ if (diff >= kOSDFadeOutDuration) {
+ // Back to full transparency
+ _osdAlpha = SDL_ALPHA_TRANSPARENT;
+ } else {
+ // Do a linear fade out...
+ const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100;
+ _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration;
+ }
+ SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha);
+ _forceFull = true;
+ }
+ }
+
+ if (!_overlayVisible) {
+ origSurf = _screen;
+ srcSurf = _tmpscreen;
+ width = _screenWidth;
+ height = _screenHeight;
+ scalerProc = _scalerProc;
+ scale1 = _scaleFactor;
+ } else {
+ origSurf = _overlayscreen;
+ srcSurf = _tmpscreen2;
+ width = _overlayWidth;
+ height = _overlayHeight;
+ scalerProc = Normal1x;
+
+ scale1 = 1;
+ }
+
+ // Force a full redraw if requested
+ if (_forceFull) {
+ _numDirtyRects = 1;
+ _dirtyRectList[0].x = 0;
+ _dirtyRectList[0].y = 0;
+ _dirtyRectList[0].w = width;
+ _dirtyRectList[0].h = height;
+ } else
+ undrawMouse();
+
+ // Only draw anything if necessary
+ if (_numDirtyRects > 0) {
+
+ SDL_Rect *r;
+ SDL_Rect dst;
+ uint32 srcPitch, dstPitch;
+ SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects;
+
+ if (scalerProc == Normal1x && !_adjustAspectRatio && 0) {
+ for (r = _dirtyRectList; r != lastRect; ++r) {
+ dst = *r;
+
+ dst.y += _currentShakePos;
+ if (SDL_BlitSurface(origSurf, r, _hwscreen, &dst) != 0)
+ error("SDL_BlitSurface failed: %s", SDL_GetError());
+ }
+ } else {
+ for (r = _dirtyRectList; r != lastRect; ++r) {
+ dst = *r;
+ dst.x++; // Shift rect by one since 2xSai needs to acces the data around
+ dst.y++; // any pixel to scale it, and we want to avoid mem access crashes.
+
+ if (SDL_BlitSurface(origSurf, r, srcSurf, &dst) != 0)
+ error("SDL_BlitSurface failed: %s", SDL_GetError());
+ }
+
+ SDL_LockSurface(srcSurf);
+ SDL_LockSurface(_hwscreen);
+
+ srcPitch = srcSurf->pitch;
+ dstPitch = _hwscreen->pitch;
+
+ for (r = _dirtyRectList; r != lastRect; ++r) {
+ register int dst_y = r->y + _currentShakePos;
+ register int dst_h = 0;
+ register int orig_dst_y = 0;
+ register int rx1 = r->x * scale1;
+
+ if (dst_y < height) {
+ dst_h = r->h;
+ if (dst_h > height - dst_y)
+ dst_h = height - dst_y;
+
+ orig_dst_y = dst_y;
+ dst_y = dst_y * scale1;
+
+ if (_adjustAspectRatio && !_overlayVisible)
+ dst_y = real2Aspect(dst_y);
+
+ assert(scalerProc != NULL);
+ scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch,
+ (byte *)_hwscreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h);
+ }
+
+ r->x = rx1;
+ r->y = dst_y;
+ r->w = r->w * scale1;
+ r->h = dst_h * scale1;
+
+#ifndef DISABLE_SCALERS
+ if (_adjustAspectRatio && orig_dst_y < height && !_overlayVisible)
+ r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1);
+#endif
+ }
+ SDL_UnlockSurface(srcSurf);
+ SDL_UnlockSurface(_hwscreen);
+ }
+
+ // Readjust the dirty rect list in case we are doing a full update.
+ // This is necessary if shaking is active.
+ if (_forceFull) {
+ _dirtyRectList[0].y = 0;
+ _dirtyRectList[0].h = effectiveScreenHeight();
+ }
+
+ drawMouse();
+
+ if (_osdAlpha != SDL_ALPHA_TRANSPARENT) {
+ SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0);
+ }
+
+ // Finally, blit all our changes to the screen
+ SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
+ } else {
+ drawMouse();
+ if (_numDirtyRects)
+ SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
+ }
+
+ _numDirtyRects = 0;
+ _forceFull = false;
+}
+
+bool OSystem_GP2X::saveScreenshot(const char *filename) {
+ assert(_hwscreen != NULL);
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+ return SDL_SaveBMP(_hwscreen, filename) == 0;
+}
+
+void OSystem_GP2X::setFullscreenMode(bool enable) {
+ Common::StackLock lock(_graphicsMutex);
+
+ if (_fullscreen != enable || _transactionMode == kTransactionCommit) {
+ assert(_hwscreen != 0);
+ _fullscreen = enable;
+
+ if (_transactionMode == kTransactionActive) {
+ _transactionDetails.fs = enable;
+ _transactionDetails.fsChanged = true;
+
+ _transactionDetails.needHotswap = true;
+
+ return;
+ }
+
+#if (defined(MACOSX) && !SDL_VERSION_ATLEAST(1, 2, 6)) || defined(__MAEMO__)
+ // On OS X, SDL_WM_ToggleFullScreen is currently not implemented. Worse,
+ // before SDL 1.2.6 it always returned -1 (which would indicate a
+ // successful switch). So we simply don't call it at all and use
+ // hotswapGFXMode() directly to switch to fullscreen mode.
+ hotswapGFXMode();
+#else
+ if (!SDL_WM_ToggleFullScreen(_hwscreen)) {
+ // if ToggleFullScreen fails, achieve the same effect with hotswap gfx mode
+ hotswapGFXMode();
+ } else {
+ // Blit everything to the screen
+ internUpdateScreen();
+
+ // Make sure that an EVENT_SCREEN_CHANGED gets sent later
+ _modeChanged = true;
+ }
+#endif
+ }
+}
+
+void OSystem_GP2X::setAspectRatioCorrection(bool enable) {
+ if ((_screenHeight == 200 && _adjustAspectRatio != enable) ||
+ _transactionMode == kTransactionCommit) {
+ Common::StackLock lock(_graphicsMutex);
+
+ //assert(_hwscreen != 0);
+ _adjustAspectRatio = enable;
+
+ if (_transactionMode == kTransactionActive) {
+ _transactionDetails.ar = enable;
+ _transactionDetails.arChanged = true;
+
+ _transactionDetails.needHotswap = true;
+
+ return;
+ } else {
+ if (_transactionMode != kTransactionCommit)
+ hotswapGFXMode();
+ }
+
+ // Make sure that an EVENT_SCREEN_CHANGED gets sent later
+ _modeChanged = true;
+ }
+}
+
+void OSystem_GP2X::setZoomOnMouse() {
+ if (_adjustZoomOnMouse == true) {
+ _adjustZoomOnMouse = false;
+ return;
+ } else {
+ _adjustZoomOnMouse = true;
+ return;
+ }
+}
+
+void OSystem_GP2X::clearScreen() {
+ assert (_transactionMode == kTransactionNone);
+
+ // Try to lock the screen surface
+ if (SDL_LockSurface(_screen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ byte *dst = (byte *)_screen->pixels;
+
+ // Clear the screen
+ memset(dst, 0, _screenWidth * _screenHeight);
+
+ // Unlock the screen surface
+ SDL_UnlockSurface(_screen);
+}
+
+void OSystem_GP2X::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) {
+ assert (_transactionMode == kTransactionNone);
+ assert(src);
+
+ if (_screen == NULL)
+ return;
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+
+// assert(x >= 0 && x < _screenWidth);
+// assert(y >= 0 && y < _screenHeight);
+// assert(h > 0 && y + h <= _screenHeight);
+// assert(w > 0 && x + w <= _screenWidth);
+
+ if (((long)src & 3) == 0 && pitch == _screenWidth && x == 0 && y == 0 &&
+ w == _screenWidth && h == _screenHeight && _modeFlags & DF_WANT_RECT_OPTIM) {
+ /* Special, optimized case for full screen updates.
+ * It tries to determine what areas were actually changed,
+ * and just updates those, on the actual display. */
+ addDirtyRgnAuto(src);
+ } else {
+ /* Clip the coordinates */
+ if (x < 0) {
+ w += x;
+ src -= x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y;
+ src -= y * pitch;
+ y = 0;
+ }
+
+ if (w > _screenWidth - x) {
+ w = _screenWidth - x;
+ }
+
+ if (h > _screenHeight - y) {
+ h = _screenHeight - y;
+ }
+
+ if (w <= 0 || h <= 0)
+ return;
+
+ _cksumValid = false;
+ addDirtyRect(x, y, w, h);
+ }
+
+ // Try to lock the screen surface
+ if (SDL_LockSurface(_screen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ byte *dst = (byte *)_screen->pixels + y * _screenWidth + x;
+
+ if (_screenWidth == pitch && pitch == w) {
+ memcpy(dst, src, h*w);
+ } else {
+ do {
+ memcpy(dst, src, w);
+ src += pitch;
+ dst += _screenWidth;
+ } while (--h);
+ }
+
+ // Unlock the screen surface
+ SDL_UnlockSurface(_screen);
+}
+
+bool OSystem_GP2X::grabRawScreen(Graphics::Surface *surf) {
+ assert(_screen);
+ assert(surf);
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+
+ surf->create(_screenWidth, _screenHeight, _screen->format->BytesPerPixel);
+
+ // Try to lock the screen surface
+ if (SDL_LockSurface(_screen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ memcpy(surf->pixels, _screen->pixels, _screenWidth * _screenHeight * _screen->format->BytesPerPixel);
+
+ // Unlock the screen surface
+ SDL_UnlockSurface(_screen);
+
+ return true;
+}
+
+void OSystem_GP2X::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) {
+ if (_forceFull)
+ return;
+
+ if (_numDirtyRects == NUM_DIRTY_RECT) {
+ _forceFull = true;
+ return;
+ }
+
+ int height, width;
+
+ if (!_overlayVisible && !realCoordinates) {
+ width = _screenWidth;
+ height = _screenHeight;
+ } else {
+ width = _overlayWidth;
+ height = _overlayHeight;
+ }
+
+ // Extend the dirty region by 1 pixel for scalers
+ // that "smear" the screen, e.g. 2xSAI
+ if ((_modeFlags & DF_UPDATE_EXPAND_1_PIXEL) && !realCoordinates) {
+ x--;
+ y--;
+ w+=2;
+ h+=2;
+ }
+
+ // clip
+ if (x < 0) {
+ w += x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y;
+ y=0;
+ }
+
+ if (w > width - x) {
+ w = width - x;
+ }
+
+ if (h > height - y) {
+ h = height - y;
+ }
+
+#ifndef DISABLE_SCALERS
+ if (_adjustAspectRatio && !_overlayVisible && !realCoordinates) {
+ makeRectStretchable(x, y, w, h);
+ }
+#endif
+
+ if (w == width && h == height) {
+ _forceFull = true;
+ return;
+ }
+
+ if (w > 0 && h > 0) {
+ SDL_Rect *r = &_dirtyRectList[_numDirtyRects++];
+
+ r->x = x;
+ r->y = y;
+ r->w = w;
+ r->h = h;
+ }
+}
+
+void OSystem_GP2X::makeChecksums(const byte *buf) {
+ assert(buf);
+ uint32 *sums = _dirtyChecksums;
+ uint x,y;
+ const uint last_x = (uint)_screenWidth / 8;
+ const uint last_y = (uint)_screenHeight / 8;
+
+ const uint BASE = 65521; /* largest prime smaller than 65536 */
+
+ /* the 8x8 blocks in buf are enumerated starting in the top left corner and
+ * reading each line at a time from left to right */
+ for (y = 0; y != last_y; y++, buf += _screenWidth * (8 - 1))
+ for (x = 0; x != last_x; x++, buf += 8) { // Adler32 checksum algorithm (from RFC1950, used by gzip and zlib).
+ // Adler32 checksum algorithm (from RFC1950, used by gzip and zlib).
+ // This computes the Adler32 checksum of a 8x8 pixel block. Note
+ // that we can do the modulo operation (which is the slowest part)
+ // of the algorithm) at the end, instead of doing each iteration,
+ // since we only have 64 iterations in total - and thus s1 and
+ // s2 can't overflow anyway.
+ uint32 s1 = 1;
+ uint32 s2 = 0;
+ const byte *ptr = buf;
+ for (int subY = 0; subY < 8; subY++) {
+ for (int subX = 0; subX < 8; subX++) {
+ s1 += ptr[subX];
+ s2 += s1;
+ }
+ ptr += _screenWidth;
+ }
+
+ s1 %= BASE;
+ s2 %= BASE;
+
+ /* output the checksum for this block */
+ *sums++ = (s2 << 16) + s1;
+ }
+}
+
+void OSystem_GP2X::addDirtyRgnAuto(const byte *buf) {
+ assert(buf);
+ assert(((long)buf & 3) == 0);
+
+ /* generate a table of the checksums */
+ makeChecksums(buf);
+
+ if (!_cksumValid) {
+ _forceFull = true;
+ _cksumValid = true;
+ }
+
+ /* go through the checksum list, compare it with the previous checksums,
+ and add all dirty rectangles to a list. try to combine small rectangles
+ into bigger ones in a simple way */
+ if (!_forceFull) {
+ int x, y, w;
+ uint32 *ck = _dirtyChecksums;
+
+ for (y = 0; y != _screenHeight / 8; y++) {
+ for (x = 0; x != _screenWidth / 8; x++, ck++) {
+ if (ck[0] != ck[_cksumNum]) {
+ /* found a dirty 8x8 block, now go as far to the right as possible,
+ and at the same time, unmark the dirty status by setting old to new. */
+ w=0;
+ do {
+ ck[w + _cksumNum] = ck[w];
+ w++;
+ } while (x + w != _screenWidth / 8 && ck[w] != ck[w + _cksumNum]);
+
+ addDirtyRect(x * 8, y * 8, w * 8, 8);
+
+ if (_forceFull)
+ goto get_out;
+ }
+ }
+ }
+ } else {
+ get_out:;
+ /* Copy old checksums to new */
+ memcpy(_dirtyChecksums + _cksumNum, _dirtyChecksums, _cksumNum * sizeof(uint32));
+ }
+}
+
+int16 OSystem_GP2X::getHeight() {
+ return _screenHeight;
+}
+
+int16 OSystem_GP2X::getWidth() {
+ return _screenWidth;
+}
+
+void OSystem_GP2X::setPalette(const byte *colors, uint start, uint num) {
+ assert(colors);
+
+ // Setting the palette before _screen is created is allowed - for now -
+ // since we don't actually set the palette until the screen is updated.
+ // But it could indicate a programming error, so let's warn about it.
+
+ if (!_screen)
+ warning("OSystem_SDL::setPalette: _screen == NULL");
+
+ const byte *b = colors;
+ uint i;
+ SDL_Color *base = _currentPalette + start;
+ for (i = 0; i < num; i++) {
+ base[i].r = b[0];
+ base[i].g = b[1];
+ base[i].b = b[2];
+ b += 4;
+ }
+
+ if (start < _paletteDirtyStart)
+ _paletteDirtyStart = start;
+
+ if (start + num > _paletteDirtyEnd)
+ _paletteDirtyEnd = start + num;
+
+ // Some games blink cursors with palette
+ if (_cursorPaletteDisabled)
+ blitCursor();
+}
+
+void OSystem_GP2X::grabPalette(byte *colors, uint start, uint num) {
+ assert(colors);
+ const SDL_Color *base = _currentPalette + start;
+
+ for (uint i = 0; i < num; ++i) {
+ colors[i * 4] = base[i].r;
+ colors[i * 4 + 1] = base[i].g;
+ colors[i * 4 + 2] = base[i].b;
+ colors[i * 4 + 3] = 0xFF;
+ }
+}
+
+void OSystem_GP2X::setCursorPalette(const byte *colors, uint start, uint num) {
+ assert(colors);
+ const byte *b = colors;
+ uint i;
+ SDL_Color *base = _cursorPalette + start;
+ for (i = 0; i < num; i++) {
+ base[i].r = b[0];
+ base[i].g = b[1];
+ base[i].b = b[2];
+ b += 4;
+ }
+
+ _cursorPaletteDisabled = false;
+
+ blitCursor();
+}
+
+void OSystem_GP2X::setShakePos(int shake_pos) {
+ assert (_transactionMode == kTransactionNone);
+
+ _newShakePos = shake_pos;
+}
+
+#pragma mark -
+#pragma mark --- Overlays ---
+#pragma mark -
+
+void OSystem_GP2X::showOverlay() {
+ assert (_transactionMode == kTransactionNone);
+
+ int x, y;
+
+ if (_overlayVisible)
+ return;
+
+ _overlayVisible = true;
+
+ // Since resolution could change, put mouse to adjusted position
+ // Fixes bug #1349059
+ x = _mouseCurState.x * _scaleFactor;
+ if (_adjustAspectRatio)
+ y = real2Aspect(_mouseCurState.y) * _scaleFactor;
+ else
+ y = _mouseCurState.y * _scaleFactor;
+
+ warpMouse(x, y);
+
+ clearOverlay();
+}
+
+void OSystem_GP2X::hideOverlay() {
+ assert (_transactionMode == kTransactionNone);
+
+ if (!_overlayVisible)
+ return;
+
+ int x, y;
+
+ _overlayVisible = false;
+
+ // Since resolution could change, put mouse to adjusted position
+ // Fixes bug #1349059
+ x = _mouseCurState.x / _scaleFactor;
+ y = _mouseCurState.y / _scaleFactor;
+ if (_adjustAspectRatio)
+ y = aspect2Real(y);
+
+ warpMouse(x, y);
+
+ clearOverlay();
+
+ _forceFull = true;
+}
+
+void OSystem_GP2X::clearOverlay() {
+ //assert (_transactionMode == kTransactionNone);
+
+ Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
+
+ if (!_overlayVisible)
+ return;
+
+ // Clear the overlay by making the game screen "look through" everywhere.
+ SDL_Rect src, dst;
+ src.x = src.y = 0;
+ dst.x = dst.y = 1;
+ src.w = dst.w = _screenWidth;
+ src.h = dst.h = _screenHeight;
+ if (SDL_BlitSurface(_screen, &src, _tmpscreen, &dst) != 0)
+ error("SDL_BlitSurface failed: %s", SDL_GetError());
+
+ SDL_LockSurface(_tmpscreen);
+ SDL_LockSurface(_overlayscreen);
+ _scalerProc((byte *)(_tmpscreen->pixels) + _tmpscreen->pitch + 2, _tmpscreen->pitch,
+ (byte *)_overlayscreen->pixels, _overlayscreen->pitch, _screenWidth, _screenHeight);
+
+#ifndef DISABLE_SCALERS
+ if (_adjustAspectRatio)
+ stretch200To240((uint8 *)_overlayscreen->pixels, _overlayscreen->pitch,
+ _overlayWidth, _screenHeight * _scaleFactor, 0, 0, 0);
+#endif
+ SDL_UnlockSurface(_tmpscreen);
+ SDL_UnlockSurface(_overlayscreen);
+
+ _forceFull = true;
+}
+
+void OSystem_GP2X::grabOverlay(OverlayColor *buf, int pitch) {
+ assert (_transactionMode == kTransactionNone);
+
+ if (_overlayscreen == NULL)
+ return;
+
+ if (SDL_LockSurface(_overlayscreen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ byte *src = (byte *)_overlayscreen->pixels;
+ int h = _overlayHeight;
+ do {
+ memcpy(buf, src, _overlayWidth * 2);
+ src += _overlayscreen->pitch;
+ buf += pitch;
+ } while (--h);
+
+ SDL_UnlockSurface(_overlayscreen);
+}
+
+void OSystem_GP2X::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) {
+ assert (_transactionMode == kTransactionNone);
+
+ if (_overlayscreen == NULL)
+ return;
+
+ // Clip the coordinates
+ if (x < 0) {
+ w += x;
+ buf -= x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h += y; buf -= y * pitch;
+ y = 0;
+ }
+
+ if (w > _overlayWidth - x) {
+ w = _overlayWidth - x;
+ }
+
+ if (h > _overlayHeight - y) {
+ h = _overlayHeight - y;
+ }
+
+ if (w <= 0 || h <= 0)
+ return;
+
+ // Mark the modified region as dirty
+ _cksumValid = false;
+ addDirtyRect(x, y, w, h);
+
+ if (SDL_LockSurface(_overlayscreen) == -1)
+ error("SDL_LockSurface failed: %s", SDL_GetError());
+
+ byte *dst = (byte *)_overlayscreen->pixels + y * _overlayscreen->pitch + x * 2;
+ do {
+ memcpy(dst, buf, w * 2);
+ dst += _overlayscreen->pitch;
+ buf += pitch;
+ } while (--h);
+
+ SDL_UnlockSurface(_overlayscreen);
+}
+
+OverlayColor OSystem_GP2X::RGBToColor(uint8 r, uint8 g, uint8 b) {
+ return SDL_MapRGB(_overlayscreen->format, r, g, b);
+}
+
+void OSystem_GP2X::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b) {
+ SDL_GetRGB(color, _overlayscreen->format, &r, &g, &b);
+}
+
+
+#pragma mark -
+#pragma mark --- Mouse ---
+#pragma mark -
+
+bool OSystem_GP2X::showMouse(bool visible) {
+ if (_mouseVisible == visible)
+ return visible;
+
+ bool last = _mouseVisible;
+ _mouseVisible = visible;
+
+ //updateScreen();
+
+ return last;
+}
+
+void OSystem_GP2X::setMousePos(int x, int y) {
+ if (x != _mouseCurState.x || y != _mouseCurState.y) {
+ _mouseCurState.x = x;
+ _mouseCurState.y = y;
+ //updateScreen();
+ }
+}
+
+void OSystem_GP2X::warpMouse(int x, int y) {
+ int y1 = y;
+
+ if (_adjustAspectRatio && !_overlayVisible)
+ y1 = real2Aspect(y);
+
+ if (_mouseCurState.x != x || _mouseCurState.y != y) {
+ if (!_overlayVisible)
+ SDL_WarpMouse(x * _scaleFactor, y1 * _scaleFactor);
+ else
+ SDL_WarpMouse(x, y1);
+
+ // SDL_WarpMouse() generates a mouse movement event, so
+ // setMousePos() would be called eventually. However, the
+ // cannon script in CoMI calls this function twice each time
+ // the cannon is reloaded. Unless we update the mouse position
+ // immediately the second call is ignored, causing the cannon
+ // to change its aim.
+
+ setMousePos(x, y);
+ }
+}
+
+void OSystem_GP2X::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) {
+ if (w == 0 || h == 0)
+ return;
+
+ _mouseCurState.hotX = hotspot_x;
+ _mouseCurState.hotY = hotspot_y;
+
+ _mouseKeyColor = keycolor;
+
+ _cursorTargetScale = cursorTargetScale;
+
+ if (_mouseCurState.w != (int)w || _mouseCurState.h != (int)h) {
+ _mouseCurState.w = w;
+ _mouseCurState.h = h;
+
+ if (_mouseOrigSurface)
+ SDL_FreeSurface(_mouseOrigSurface);
+
+ // Allocate bigger surface because AdvMame2x adds black pixel at [0,0]
+ _mouseOrigSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
+ _mouseCurState.w + 2,
+ _mouseCurState.h + 2,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_mouseOrigSurface == NULL)
+ error("allocating _mouseOrigSurface failed");
+ SDL_SetColorKey(_mouseOrigSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey);
+ }
+
+ free(_mouseData);
+
+ _mouseData = (byte *)malloc(w * h);
+ memcpy(_mouseData, buf, w * h);
+ blitCursor();
+}
+
+void OSystem_GP2X::blitCursor() {
+ byte *dstPtr;
+ const byte *srcPtr = _mouseData;
+ byte color;
+ int w, h, i, j;
+
+ if (!_mouseOrigSurface || !_mouseData)
+ return;
+
+ w = _mouseCurState.w;
+ h = _mouseCurState.h;
+
+ SDL_LockSurface(_mouseOrigSurface);
+
+ // Make whole surface transparent
+ for (i = 0; i < h + 2; i++) {
+ dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch * i;
+ for (j = 0; j < w + 2; j++) {
+ *(uint16 *)dstPtr = kMouseColorKey;
+ dstPtr += 2;
+ }
+ }
+
+ // Draw from [1,1] since AdvMame2x adds artefact at 0,0
+ dstPtr = (byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2;
+
+ SDL_Color *palette;
+
+ if (_cursorPaletteDisabled)
+ palette = _currentPalette;
+ else
+ palette = _cursorPalette;
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ color = *srcPtr;
+ if (color != _mouseKeyColor) { // transparent, don't draw
+ *(uint16 *)dstPtr = SDL_MapRGB(_mouseOrigSurface->format,
+ palette[color].r, palette[color].g, palette[color].b);
+ }
+ dstPtr += 2;
+ srcPtr++;
+ }
+ dstPtr += _mouseOrigSurface->pitch - w * 2;
+ }
+
+ int rW, rH;
+
+ if (_cursorTargetScale >= _scaleFactor) {
+ // The cursor target scale is greater or equal to the scale at
+ // which the rest of the screen is drawn. We do not downscale
+ // the cursor image, we draw it at its original size. It will
+ // appear too large on screen.
+
+ rW = w;
+ rH = h;
+ _mouseCurState.rHotX = _mouseCurState.hotX;
+ _mouseCurState.rHotY = _mouseCurState.hotY;
+
+ // The virtual dimensions may be larger than the original.
+
+ _mouseCurState.vW = w * _cursorTargetScale / _scaleFactor;
+ _mouseCurState.vH = h * _cursorTargetScale / _scaleFactor;
+ _mouseCurState.vHotX = _mouseCurState.hotX * _cursorTargetScale /
+ _scaleFactor;
+ _mouseCurState.vHotY = _mouseCurState.hotY * _cursorTargetScale /
+ _scaleFactor;
+ } else {
+ // The cursor target scale is smaller than the scale at which
+ // the rest of the screen is drawn. We scale up the cursor
+ // image to make it appear correct.
+
+ rW = w * _scaleFactor / _cursorTargetScale;
+ rH = h * _scaleFactor / _cursorTargetScale;
+ _mouseCurState.rHotX = _mouseCurState.hotX * _scaleFactor /
+ _cursorTargetScale;
+ _mouseCurState.rHotY = _mouseCurState.hotY * _scaleFactor /
+ _cursorTargetScale;
+
+ // The virtual dimensions will be the same as the original.
+
+ _mouseCurState.vW = w;
+ _mouseCurState.vH = h;
+ _mouseCurState.vHotX = _mouseCurState.hotX;
+ _mouseCurState.vHotY = _mouseCurState.hotY;
+ }
+
+ int rH1 = rH; // store original to pass to aspect-correction function later
+ if (_adjustAspectRatio && _cursorTargetScale == 1) {
+ rH = real2Aspect(rH - 1) + 1;
+ _mouseCurState.rHotY = real2Aspect(_mouseCurState.rHotY);
+ }
+
+ if (_mouseCurState.rW != rW || _mouseCurState.rH != rH) {
+ _mouseCurState.rW = rW;
+ _mouseCurState.rH = rH;
+
+ if (_mouseSurface)
+ SDL_FreeSurface(_mouseSurface);
+
+ _mouseSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA,
+ _mouseCurState.rW,
+ _mouseCurState.rH,
+ 16,
+ _hwscreen->format->Rmask,
+ _hwscreen->format->Gmask,
+ _hwscreen->format->Bmask,
+ _hwscreen->format->Amask);
+
+ if (_mouseSurface == NULL)
+ error("allocating _mouseSurface failed");
+
+ SDL_SetColorKey(_mouseSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kMouseColorKey);
+ }
+
+ SDL_LockSurface(_mouseSurface);
+
+ ScalerProc *scalerProc;
+
+ // If possible, use the same scaler for the cursor as for the rest of
+ // the game. This only works well with the non-blurring scalers so we
+ // actually only use the 1x, 1.5x, 2x and AdvMame scalers.
+
+ if (_cursorTargetScale == 1 && (_mode == GFX_DOUBLESIZE || _mode == GFX_TRIPLESIZE))
+ scalerProc = _scalerProc;
+ else
+ scalerProc = scalersMagn[_cursorTargetScale - 1][_scaleFactor - 1];
+
+ scalerProc((byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2,
+ _mouseOrigSurface->pitch, (byte *)_mouseSurface->pixels, _mouseSurface->pitch,
+ _mouseCurState.w, _mouseCurState.h);
+
+ if (_adjustAspectRatio && _cursorTargetScale == 1)
+ cursorStretch200To240((uint8 *)_mouseSurface->pixels, _mouseSurface->pitch, rW, rH1, 0, 0, 0);
+
+ SDL_UnlockSurface(_mouseSurface);
+ SDL_UnlockSurface(_mouseOrigSurface);
+}
+
+// Basically it is kVeryFastAndUglyAspectMode of stretch200To240 from
+// common/scale/aspect.cpp
+static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY) {
+ int maxDstY = real2Aspect(origSrcY + height - 1);
+ int y;
+ const uint8 *startSrcPtr = buf + srcX * 2 + (srcY - origSrcY) * pitch;
+ uint8 *dstPtr = buf + srcX * 2 + maxDstY * pitch;
+
+ for (y = maxDstY; y >= srcY; y--) {
+ const uint8 *srcPtr = startSrcPtr + aspect2Real(y) * pitch;
+
+ if (srcPtr == dstPtr)
+ break;
+ memcpy(dstPtr, srcPtr, width * 2);
+ dstPtr -= pitch;
+ }
+
+ return 1 + maxDstY - srcY;
+}
+
+void OSystem_GP2X::undrawMouse() {
+ const int x = _mouseBackup.x;
+ const int y = _mouseBackup.y;
+
+ // When we switch bigger overlay off mouse jumps. Argh!
+ // This is intended to prevent undrawing offscreen mouse
+ if (!_overlayVisible && (x >= _screenWidth || y >= _screenHeight)) {
+ return;
+ }
+
+ if (_mouseBackup.w != 0 && _mouseBackup.h != 0)
+ addDirtyRect(x, y, _mouseBackup.w, _mouseBackup.h);
+}
+
+void OSystem_GP2X::drawMouse() {
+ if (!_mouseVisible || !_mouseSurface) {
+ _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0;
+ return;
+ }
+
+ SDL_Rect zoomdst;
+ SDL_Rect dst;
+ int scale;
+ int width, height;
+ int hotX, hotY;
+ int tmpScreenWidth, tmpScreenHeight;
+
+ // Temp vars to ensure we zoom to the LCD resolution or greater.
+ tmpScreenWidth = _screenWidth;
+ tmpScreenHeight = _screenHeight;
+
+ if (_screenHeight <= 240) {
+ tmpScreenHeight = 240;
+ }
+
+ if (_screenWidth <= 320) {
+ tmpScreenWidth = 320;
+ }
+
+ dst.x = _mouseCurState.x;
+ dst.y = _mouseCurState.y;
+
+ if (!_overlayVisible) {
+ scale = _scaleFactor;
+ width = _screenWidth;
+ height = _screenHeight;
+ dst.w = _mouseCurState.vW;
+ dst.h = _mouseCurState.vH;
+ hotX = _mouseCurState.vHotX;
+ hotY = _mouseCurState.vHotY;
+ } else {
+ scale = 1;
+ width = _overlayWidth;
+ height = _overlayHeight;
+ dst.w = _mouseCurState.rW;
+ dst.h = _mouseCurState.rH;
+ hotX = _mouseCurState.rHotX;
+ hotY = _mouseCurState.rHotY;
+ }
+
+ // The mouse is undrawn using virtual coordinates, i.e. they may be
+ // scaled and aspect-ratio corrected.
+
+ _mouseBackup.x = dst.x - hotX;
+ _mouseBackup.y = dst.y - hotY;
+ _mouseBackup.w = dst.w;
+ _mouseBackup.h = dst.h;
+
+ // We draw the pre-scaled cursor image, so now we need to adjust for
+ // scaling, shake position and aspect ratio correction manually.
+
+ if (!_overlayVisible) {
+ dst.y += _currentShakePos;
+ }
+
+ if (_adjustAspectRatio && !_overlayVisible)
+ dst.y = real2Aspect(dst.y);
+
+ dst.x = scale * dst.x - _mouseCurState.rHotX;
+ dst.y = scale * dst.y - _mouseCurState.rHotY;
+ dst.w = _mouseCurState.rW;
+ dst.h = _mouseCurState.rH;
+
+ // Hacking about with the zoom around mouse pointer stuff.
+
+ if (_adjustZoomOnMouse == true){
+
+ zoomdst.w = (tmpScreenWidth / 2);
+ zoomdst.h = (tmpScreenHeight / 2);
+
+ // Create a zoomed rect centered on the mouse pointer.
+ // Will pan 1/4 of the screen.
+
+ if (dst.x > ((tmpScreenWidth / 4) * 3)) {
+ zoomdst.x = (tmpScreenWidth / 2);
+ } else {
+ zoomdst.x = (dst.x - (tmpScreenWidth / 4));
+ if (zoomdst.x < 0) {
+ zoomdst.x = 0;
+ }
+ }
+
+ if (dst.y > ((tmpScreenHeight / 4) * 3)) {
+ zoomdst.y = (tmpScreenHeight / 2);
+ } else {
+ zoomdst.y = (dst.y - (tmpScreenHeight / 4));
+ if (zoomdst.y < 0) {
+ zoomdst.y = 0;
+ }
+ }
+ SDL_GP2X_Display(&zoomdst);
+ } else {
+
+ // Make sure we are looking at the whole screen otherwise.
+
+ zoomdst.x = 0;
+ zoomdst.y = 0;
+ zoomdst.w = (tmpScreenWidth);
+ zoomdst.h = (tmpScreenHeight);
+
+ SDL_GP2X_Display(&zoomdst);
+
+ };
+
+
+ // Note that SDL_BlitSurface() and addDirtyRect() will both perform any
+ // clipping necessary
+
+ if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0)
+ error("SDL_BlitSurface failed: %s", SDL_GetError());
+
+ // The screen will be updated using real surface coordinates, i.e.
+ // they will not be scaled or aspect-ratio corrected.
+
+ addDirtyRect(dst.x, dst.y, dst.w, dst.h, true);
+}
+
+#pragma mark -
+#pragma mark --- On Screen Display ---
+#pragma mark -
+
+void OSystem_GP2X::displayMessageOnOSD(const char *msg) {
+ assert (_transactionMode == kTransactionNone);
+ assert(msg);
+
+ uint i;
+
+ // Lock the OSD surface for drawing
+ if (SDL_LockSurface(_osdSurface))
+ error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError());
+
+ Graphics::Surface dst;
+ dst.pixels = _osdSurface->pixels;
+ dst.w = _osdSurface->w;
+ dst.h = _osdSurface->h;
+ dst.pitch = _osdSurface->pitch;
+ dst.bytesPerPixel = _osdSurface->format->BytesPerPixel;
+
+ // The font we are going to use:
+ const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kOSDFont);
+
+ // Clear everything with the "transparent" color, i.e. the colorkey
+ SDL_FillRect(_osdSurface, 0, kOSDColorKey);
+
+ // Split the message into separate lines.
+ Common::StringList lines;
+ const char *ptr;
+ for (ptr = msg; *ptr; ++ptr) {
+ if (*ptr == '\n') {
+ lines.push_back(Common::String(msg, ptr - msg));
+ msg = ptr + 1;
+ }
+ }
+ lines.push_back(Common::String(msg, ptr - msg));
+
+ // Determine a rect which would contain the message string (clipped to the
+ // screen dimensions).
+ const int vOffset = 6;
+ const int lineSpacing = 1;
+ const int lineHeight = font->getFontHeight() + 2 * lineSpacing;
+ int width = 0;
+ int height = lineHeight * lines.size() + 2 * vOffset;
+ for (i = 0; i < lines.size(); i++) {
+ width = MAX(width, font->getStringWidth(lines[i]) + 14);
+ }
+
+ // Clip the rect
+ if (width > dst.w)
+ width = dst.w;
+ if (height > dst.h)
+ height = dst.h;
+
+ // Draw a dark gray rect
+ // TODO: Rounded corners ? Border?
+ SDL_Rect osdRect;
+ osdRect.x = (dst.w - width) / 2;
+ osdRect.y = (dst.h - height) / 2;
+ osdRect.w = width;
+ osdRect.h = height;
+ SDL_FillRect(_osdSurface, &osdRect, SDL_MapRGB(_osdSurface->format, 64, 64, 64));
+
+ // Render the message, centered, and in white
+ for (i = 0; i < lines.size(); i++) {
+ font->drawString(&dst, lines[i],
+ osdRect.x, osdRect.y + i * lineHeight + vOffset + lineSpacing, osdRect.w,
+ SDL_MapRGB(_osdSurface->format, 255, 255, 255),
+ Graphics::kTextAlignCenter);
+ }
+
+ // Finished drawing, so unlock the OSD surface again
+ SDL_UnlockSurface(_osdSurface);
+
+ // Init the OSD display parameters, and the fade out
+ _osdAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100;
+ _osdFadeStartTime = SDL_GetTicks() + kOSDFadeOutDelay;
+ SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha);
+
+ // Ensure a full redraw takes place next time the screen is updated
+ _forceFull = true;
+}
+
+#pragma mark -
+#pragma mark --- Misc ---
+#pragma mark -
+
+void OSystem_GP2X::handleScalerHotkeys(const SDL_KeyboardEvent &key) {
+ // Ctrl-Alt-a toggles aspect ratio correction
+ if (key.keysym.sym == 'a') {
+ setFeatureState(kFeatureAspectRatioCorrection, !_adjustAspectRatio);
+
+ char buffer[128];
+ if (_adjustAspectRatio)
+ sprintf(buffer, "Enabled aspect ratio correction\n%d x %d -> %d x %d",
+ _screenWidth, _screenHeight,
+ _hwscreen->w, _hwscreen->h
+ );
+ else
+ sprintf(buffer, "Disabled aspect ratio correction\n%d x %d -> %d x %d",
+ _screenWidth, _screenHeight,
+ _hwscreen->w, _hwscreen->h
+ );
+ displayMessageOnOSD(buffer);
+
+
+ return;
+ }
+
+ int newMode = -1;
+ int factor = _scaleFactor - 1;
+
+ // Increase/decrease the scale factor
+ if (key.keysym.sym == SDLK_EQUALS || key.keysym.sym == SDLK_PLUS || key.keysym.sym == SDLK_MINUS ||
+ key.keysym.sym == SDLK_KP_PLUS || key.keysym.sym == SDLK_KP_MINUS) {
+ factor += (key.keysym.sym == SDLK_MINUS || key.keysym.sym == SDLK_KP_MINUS) ? -1 : +1;
+ if (0 <= factor && factor <= 3) {
+ newMode = s_gfxModeSwitchTable[_scalerType][factor];
+ }
+ }
+
+ const bool isNormalNumber = (SDLK_1 <= key.keysym.sym && key.keysym.sym <= SDLK_9);
+ const bool isKeypadNumber = (SDLK_KP1 <= key.keysym.sym && key.keysym.sym <= SDLK_KP9);
+ if (isNormalNumber || isKeypadNumber) {
+ _scalerType = key.keysym.sym - (isNormalNumber ? SDLK_1 : SDLK_KP1);
+ if (_scalerType >= ARRAYSIZE(s_gfxModeSwitchTable))
+ return;
+
+ while (s_gfxModeSwitchTable[_scalerType][factor] < 0) {
+ assert(factor > 0);
+ factor--;
+ }
+ newMode = s_gfxModeSwitchTable[_scalerType][factor];
+ }
+
+ if (newMode >= 0) {
+ setGraphicsMode(newMode);
+
+ if (_osdSurface) {
+ const char *newScalerName = 0;
+ const GraphicsMode *g = getSupportedGraphicsModes();
+ while (g->name) {
+ if (g->id == _mode) {
+ newScalerName = g->description;
+ break;
+ }
+ g++;
+ }
+ if (newScalerName) {
+ char buffer[128];
+ sprintf(buffer, "Active graphics filter: %s\n%d x %d -> %d x %d",
+ newScalerName,
+ _screenWidth, _screenHeight,
+ _hwscreen->w, _hwscreen->h
+ );
+ displayMessageOnOSD(buffer);
+ }
+ }
+
+ }
+
+}
diff --git a/backends/platform/gp2x/module.mk b/backends/platform/gp2x/module.mk
new file mode 100644
index 0000000000..34c7d79501
--- /dev/null
+++ b/backends/platform/gp2x/module.mk
@@ -0,0 +1,15 @@
+MODULE := backends/platform/gp2x
+
+MODULE_OBJS := \
+ gp2x-hw.o \
+ gp2x-mem.o \
+ events.o \
+ graphics.o \
+ gp2x.o
+ # overload_help.o
+
+MODULE_DIRS += \
+ backends/platform/gp2x/
+
+# We don't use the common.rules here on purpose
+OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS)
diff --git a/common/config-manager.cpp b/common/config-manager.cpp
index 354a48e031..0f80e5c84f 100644
--- a/common/config-manager.cpp
+++ b/common/config-manager.cpp
@@ -89,7 +89,7 @@ ConfigManager::ConfigManager()
void ConfigManager::loadDefaultConfigFile() {
char configFile[MAXPATHLEN];
-#if defined(UNIX)
+#if defined(UNIX) && !defined(GP2X) // GP2X is Linux based but Home dir can be read only so do not use it and put the config in the executable dir.
const char *home = getenv("HOME");
if (home != NULL && strlen(home) < MAXPATHLEN)
snprintf(configFile, MAXPATHLEN, "%s/%s", home, DEFAULT_CONFIG_FILE);
@@ -335,7 +335,7 @@ void ConfigManager::writeDomain(FILE *file, const String &name, const Domain &do
const ConfigManager::Domain *ConfigManager::getDomain(const String &domName) const {
assert(!domName.empty());
assert(isValidDomainName(domName));
-
+
if (domName == kTransientDomain)
return &_transientDomain;
if (domName == kApplicationDomain)
@@ -349,7 +349,7 @@ const ConfigManager::Domain *ConfigManager::getDomain(const String &domName) con
ConfigManager::Domain *ConfigManager::getDomain(const String &domName) {
assert(!domName.empty());
assert(isValidDomainName(domName));
-
+
if (domName == kTransientDomain)
return &_transientDomain;
if (domName == kApplicationDomain)
@@ -527,7 +527,7 @@ void ConfigManager::set(const String &key, const String &value, const String &do
key.c_str(), value.c_str(), domName.c_str());
(*domain)[key] = value;
-
+
// TODO/FIXME: We used to erase the given key from the transient domain
// here. Do we still want to do that?
// It was probably there to simplify the options dialogs code:
diff --git a/configure b/configure
index e558a6328c..2a5cf0ba8c 100755
--- a/configure
+++ b/configure
@@ -303,7 +303,7 @@ Usage: $0 [OPTIONS]...
Configuration:
-h, --help display this help and exit
- --backend=BACKEND backend to build (sdl, x11, morphos, dc, gp32, null) [sdl]
+ --backend=BACKEND backend to build (sdl, x11, morphos, dc, gp32, gp2x, null) [sdl]
Installation directories:
--prefix=DIR use this prefix for installing ScummVM [/usr/local]
@@ -527,6 +527,10 @@ ppc-amigaos)
_host_os=amigaos
_host_cpu=ppc
;;
+gp2x)
+ _host_os=gp2x-linux
+ _host_cpu=arm
+ ;;
*)
guessed_host=`$_srcdir/config.guess`
_host_cpu=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
@@ -545,6 +549,9 @@ mingw* | cygwin* | os2-emx*)
arm-riscos)
EXEEXT=",ff8"
;;
+gp2x-linux)
+ EXEEXT=".gpe"
+ ;;
*)
EXEEXT=""
;;
@@ -704,6 +711,18 @@ if test -n "$_host"; then
type_2_byte='short'
type_4_byte='int'
;;
+ gp2x)
+ echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
+ DEFINES="$DEFINES -DUNIX -DGP2X"
+ _def_endianness='#define SCUMM_LITTLE_ENDIAN'
+ _def_align='#define SCUMM_NEED_ALIGNMENT'
+ type_1_byte='char'
+ type_2_byte='short'
+ type_4_byte='int'
+ _backend="gp2x"
+ _mak_hq_scalers='DISABLE_HQ_SCALERS = 1'
+ _build_hq_scalers="no"
+ ;;
ppc-amigaos)
echo "Cross-compiling to $_host, forcing endianness, alignment and type sizes"
_def_endianness='#define SCUMM_BIG_ENDIAN'
@@ -1288,6 +1307,14 @@ case $_backend in
LIBS="$LIBS `$_sdlconfig --libs`"
MODULES="$MODULES backends/platform/sdl"
;;
+ gp2x)
+ find_sdlconfig
+ INCLUDES="$INCLUDES `$_sdlconfig --cflags`"
+ LIBS="$LIBS `$_sdlconfig --libs`"
+ LDFLAGS="$LDFLAGS -static"
+ CXXFLAGS="$CXXFLAGS -march=armv4t"
+ MODULES="$MODULES backends/platform/gp2x"
+ ;;
x11)
INCLUDES="$INCLUDES -I/usr/X11R6/include"
LIBS="$LIBS -lpthread -lXext -lX11"
diff --git a/sound/fmopl.cpp b/sound/fmopl.cpp
index c5705e01b7..9fd8a33ee4 100644
--- a/sound/fmopl.cpp
+++ b/sound/fmopl.cpp
@@ -35,7 +35,7 @@
#include "common/util.h"
-#if defined (_WIN32_WCE) || defined (__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined (__MAEMO__) || defined(__DS__)
+#if defined (_WIN32_WCE) || defined (__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined(__GP2X__) || defined (__MAEMO__) || defined(__DS__)
#include "common/config-manager.h"
#endif
@@ -477,7 +477,7 @@ inline void OPL_CALC_CH(OPL_CH *CH) {
env_out=OPL_CALC_SLOT(SLOT);
if(env_out < (uint)(EG_ENT - 1)) {
/* PG */
- if(SLOT->vib)
+ if(SLOT->vib)
SLOT->Cnt += (SLOT->Incr * vib / VIB_RATE);
else
SLOT->Cnt += SLOT->Incr;
@@ -512,7 +512,7 @@ inline void OPL_CALC_CH(OPL_CH *CH) {
inline void OPL_CALC_RH(OPL_CH *CH) {
uint env_tam, env_sd, env_top, env_hh;
int whitenoise = int(oplRnd.getRandomNumber(1) * (WHITE_NOISE_db / EG_STEP));
-
+
int tone8;
OPL_SLOT *SLOT;
@@ -609,7 +609,7 @@ static void init_timetables(FM_OPL *OPL, int ARRATE, int DRRATE) {
OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0;
for (i = 4; i <= 60; i++) {
rate = OPL->freqbase; /* frequency rate */
- if(i < 60)
+ if(i < 60)
rate *= 1.0 + (i & 3) * 0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
rate *= 1 << ((i >> 2) - 1); /* b2-5 : shift bit */
rate *= (double)(EG_ENT << ENV_BITS);
@@ -1177,7 +1177,7 @@ FM_OPL *makeAdlibOPL(int rate) {
// We need to emulate one YM3812 chip
int env_bits = FMOPL_ENV_BITS_HQ;
int eg_ent = FMOPL_EG_ENT_HQ;
-#if defined (_WIN32_WCE) || defined(__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined(__MAEMO__) || defined(__DS__)
+#if defined (_WIN32_WCE) || defined(__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined (GP2X) || defined(__MAEMO__) || defined(__DS__)
if (ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) {
env_bits = FMOPL_ENV_BITS_HQ;
eg_ent = FMOPL_EG_ENT_HQ;