From 492c65009cb186024f52ec1970617028c3d09efe Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 24 Jun 2006 12:33:52 +0000 Subject: Started to move 'monolithic' parts of our ports to the new 'background/platform' directory (see also the 'Modular_Backends' page in our Wiki) svn-id: r23293 --- backends/maemo/Makefile | 69 - backends/maemo/hildon.cpp | 134 -- backends/maemo/maemo-sdl.cpp | 42 - backends/maemo/maemo-sdl.h | 41 - backends/maemo/main.cpp | 81 -- backends/maemo/portdefs.h | 69 - backends/morphos/MorphOS.readme | 13 - backends/morphos/build.rules | 11 - backends/morphos/morphos.cpp | 1645 ------------------------ backends/morphos/morphos.h | 232 ---- backends/morphos/morphos_scaler.cpp | 848 ------------- backends/morphos/morphos_scaler.h | 94 -- backends/morphos/morphos_sound.cpp | 254 ---- backends/morphos/morphos_sound.h | 43 - backends/morphos/morphos_start.cpp | 444 ------- backends/morphos/morphos_timer.cpp | 234 ---- backends/morphos/morphos_timer.h | 88 -- backends/null/module.mk | 10 - backends/null/null.cpp | 263 ---- backends/platform/maemo/Makefile | 69 + backends/platform/maemo/hildon.cpp | 134 ++ backends/platform/maemo/maemo-sdl.cpp | 42 + backends/platform/maemo/maemo-sdl.h | 41 + backends/platform/maemo/main.cpp | 81 ++ backends/platform/maemo/portdefs.h | 69 + backends/platform/morphos/MorphOS.readme | 13 + backends/platform/morphos/build.rules | 11 + backends/platform/morphos/morphos.cpp | 1645 ++++++++++++++++++++++++ backends/platform/morphos/morphos.h | 232 ++++ backends/platform/morphos/morphos_scaler.cpp | 848 +++++++++++++ backends/platform/morphos/morphos_scaler.h | 94 ++ backends/platform/morphos/morphos_sound.cpp | 254 ++++ backends/platform/morphos/morphos_sound.h | 43 + backends/platform/morphos/morphos_start.cpp | 444 +++++++ backends/platform/morphos/morphos_timer.cpp | 234 ++++ backends/platform/morphos/morphos_timer.h | 88 ++ backends/platform/null/module.mk | 10 + backends/platform/null/null.cpp | 263 ++++ backends/platform/sdl/build.rules | 9 + backends/platform/sdl/events.cpp | 510 ++++++++ backends/platform/sdl/graphics.cpp | 1745 ++++++++++++++++++++++++++ backends/platform/sdl/module.mk | 12 + backends/platform/sdl/sdl-common.h | 392 ++++++ backends/platform/sdl/sdl.cpp | 488 +++++++ backends/platform/x11/build.rules | 7 + backends/platform/x11/module.mk | 10 + backends/platform/x11/x11.cpp | 1037 +++++++++++++++ backends/platform/x11/x11.h | 195 +++ backends/sdl/build.rules | 9 - backends/sdl/events.cpp | 510 -------- backends/sdl/graphics.cpp | 1745 -------------------------- backends/sdl/module.mk | 12 - backends/sdl/sdl-common.h | 392 ------ backends/sdl/sdl.cpp | 488 ------- backends/symbian/src/SymbianOS.h | 2 +- backends/wince/wince-sdl.h | 2 +- backends/x11/build.rules | 7 - backends/x11/module.mk | 10 - backends/x11/x11.cpp | 1037 --------------- backends/x11/x11.h | 195 --- 60 files changed, 9022 insertions(+), 9022 deletions(-) delete mode 100644 backends/maemo/Makefile delete mode 100644 backends/maemo/hildon.cpp delete mode 100644 backends/maemo/maemo-sdl.cpp delete mode 100644 backends/maemo/maemo-sdl.h delete mode 100644 backends/maemo/main.cpp delete mode 100644 backends/maemo/portdefs.h delete mode 100644 backends/morphos/MorphOS.readme delete mode 100644 backends/morphos/build.rules delete mode 100644 backends/morphos/morphos.cpp delete mode 100644 backends/morphos/morphos.h delete mode 100644 backends/morphos/morphos_scaler.cpp delete mode 100644 backends/morphos/morphos_scaler.h delete mode 100644 backends/morphos/morphos_sound.cpp delete mode 100644 backends/morphos/morphos_sound.h delete mode 100644 backends/morphos/morphos_start.cpp delete mode 100644 backends/morphos/morphos_timer.cpp delete mode 100644 backends/morphos/morphos_timer.h delete mode 100644 backends/null/module.mk delete mode 100644 backends/null/null.cpp create mode 100644 backends/platform/maemo/Makefile create mode 100644 backends/platform/maemo/hildon.cpp create mode 100644 backends/platform/maemo/maemo-sdl.cpp create mode 100644 backends/platform/maemo/maemo-sdl.h create mode 100644 backends/platform/maemo/main.cpp create mode 100644 backends/platform/maemo/portdefs.h create mode 100644 backends/platform/morphos/MorphOS.readme create mode 100644 backends/platform/morphos/build.rules create mode 100644 backends/platform/morphos/morphos.cpp create mode 100644 backends/platform/morphos/morphos.h create mode 100644 backends/platform/morphos/morphos_scaler.cpp create mode 100644 backends/platform/morphos/morphos_scaler.h create mode 100644 backends/platform/morphos/morphos_sound.cpp create mode 100644 backends/platform/morphos/morphos_sound.h create mode 100644 backends/platform/morphos/morphos_start.cpp create mode 100644 backends/platform/morphos/morphos_timer.cpp create mode 100644 backends/platform/morphos/morphos_timer.h create mode 100644 backends/platform/null/module.mk create mode 100644 backends/platform/null/null.cpp create mode 100644 backends/platform/sdl/build.rules create mode 100644 backends/platform/sdl/events.cpp create mode 100644 backends/platform/sdl/graphics.cpp create mode 100644 backends/platform/sdl/module.mk create mode 100644 backends/platform/sdl/sdl-common.h create mode 100644 backends/platform/sdl/sdl.cpp create mode 100644 backends/platform/x11/build.rules create mode 100644 backends/platform/x11/module.mk create mode 100644 backends/platform/x11/x11.cpp create mode 100644 backends/platform/x11/x11.h delete mode 100644 backends/sdl/build.rules delete mode 100644 backends/sdl/events.cpp delete mode 100644 backends/sdl/graphics.cpp delete mode 100644 backends/sdl/module.mk delete mode 100644 backends/sdl/sdl-common.h delete mode 100644 backends/sdl/sdl.cpp delete mode 100644 backends/x11/build.rules delete mode 100644 backends/x11/module.mk delete mode 100644 backends/x11/x11.cpp delete mode 100644 backends/x11/x11.h (limited to 'backends') diff --git a/backends/maemo/Makefile b/backends/maemo/Makefile deleted file mode 100644 index 75ae01c430..0000000000 --- a/backends/maemo/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# ScummVM Maemo MakeFile -# $URL$ -# $Id$ - -#control build -DISABLE_HQ_SCALERS = true - -#DISABLE_SCUMM = 1 -#DISABLE_HE = 1 -DISABLE_SIMON = 1 -DISABLE_SKY = 1 -DISABLE_SWORD1 = 1 -DISABLE_SWORD2 = 1 -DISABLE_QUEEN = 1 -DISABLE_KYRA = 1 -DISABLE_SAGA = 1 -DISABLE_GOB = 1 -DISABLE_LURE = 1 -DISABLE_CINE = 1 -DISABLE_AGI = 1 - -srcdir = ../.. -VPATH = $(srcdir) - -CXX := g++ -EXECUTABLE := scummvm - -INCDIR = ../../ . $(srcdir)/engines/ - -CXXFLAGS := -g -ansi -W -Wno-unused-parameter -CXXFLAGS += `pkg-config --cflags gconf-2.0 hildon-libs gtk+-2.0 libosso gdk-2.0` -CXXFLAGS += $(addprefix -I,$(INCDIR)) -I. -Wall $(CXXFLAGS) -CXXFLAGS += -O -Wuninitialized -CXXFLAGS += -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -# Even more warnings... -CXXFLAGS += -pedantic -Wpointer-arith -Wcast-qual -Wconversion -CXXFLAGS += -Wshadow -Wimplicit -Wundef -Wnon-virtual-dtor -CXXFLAGS += -Wno-reorder -Wwrite-strings -fcheck-new - -LIBS += -lz -L/usr/lib -lSDL -lpthread -lXsp -losso -LIBS += `pkg-config --libs gconf-2.0 hildon-libs gtk+-2.0 libosso gdk-2.0` -INCLUDES += -I/usr/include/SDL -D_REENTRANT -I/usr/X11R6/include -OBJS += -DEFINES += -DUNIX -DNONSTANDARD_PORT -D__MAEMO__ -LDFLAGS += - -RANLIB := ranlib -INSTALL := install -AR := ar cru -MKDIR := mkdir -p -ECHO := printf -CAT := cat -RM := rm -f -RM_REC := rm -f -r -CP := cp - -OBJS := main.o maemo-sdl.o - -MODULE_DIRS += . - - -BACKEND := sdl -MODULES += backends/sdl base -MODULE_DIRS += . - -HAVE_GCC3 = 1 - -include $(srcdir)/Makefile.common - diff --git a/backends/maemo/hildon.cpp b/backends/maemo/hildon.cpp deleted file mode 100644 index 1c9bd9162a..0000000000 --- a/backends/maemo/hildon.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include -#include -#include - -#define OSSO_APP_NAME "scummvm" -#define OSSO_APP_VERSION "0.9.0CVS" -#define OSSO_APP_SERVICE "org.scummvm."OSSO_APP_NAME -#define OSSO_APP_OBJECT "/org/scummvm/"OSSO_APP_NAME -#define OSSO_APP_IFACE "org.scummvm."OSSO_APP_NAME - -// Application UI data struct -typedef struct _AppData AppData; -struct _AppData { - HildonApp *app; - HildonAppView *appview; - osso_context_t *osso_context; -}; - -// Callback for exit D-BUS event -void exit_event_handler(gboolean die_now, gpointer data) { - AppData *appdata; - appdata = (AppData *)data; - g_print("exit_event_handler called\n"); - /* Do whatever application needs to do before exiting */ - gtk_infoprint(GTK_WINDOW(appdata->app), "Exiting..."); -} - -// Callback for normal D-BUS messages -gint dbus_req_handler(const gchar *interface, const gchar *method, - GArray *arguments, gpointer data, - osso_rpc_t *retval) { - AppData *appdata; - appdata = (AppData *)data; - osso_system_note_infoprint(appdata->osso_context, method, retval); - return OSSO_OK; -} - - -// Main application -int main(int argc, char *argv[]) { - // Create needed variables - HildonApp *app; - HildonAppView *appview; - osso_context_t *osso_context; - osso_return_t result; - GtkWidget *main_vbox; - GtkWidget *label; - - // Initialize the GTK. - gtk_init(&argc, &argv); - - // Initialize maemo application - osso_context = osso_initialize(OSSO_APP_NAME, OSSO_APP_VERSION, TRUE, NULL); - - // Check that initialization was ok - if (osso_context == NULL) { - return OSSO_ERROR; - } - - // Create the hildon application and setup the title - app = HILDON_APP(hildon_app_new()); - hildon_app_set_title(app, "ScummVM"); - hildon_app_set_two_part_title(app, TRUE); - - // Create HildonAppView and set it to HildonApp - appview = HILDON_APPVIEW(hildon_appview_new("AppView Title")); - hildon_app_set_appview(app, appview); - - // Create AppData - AppData *appdata; - appdata = g_new0(AppData, 1); - appdata->app = app; - appdata->appview = appview; - appdata->osso_context = osso_context; - - // Add vbox to appview - main_vbox = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(appview), main_vbox); - - // Add button to vbox - label = gtk_label_new("Waiting for DBUS message..."); - gtk_box_pack_start(GTK_BOX(main_vbox), label, FALSE, TRUE, 0); - - // Add handler for hello D-BUS messages - result = osso_rpc_set_cb_f(appdata->osso_context, - OSSO_APP_SERVICE, - OSSO_APP_OBJECT, - OSSO_APP_IFACE, - dbus_req_handler, appdata); - if (result != OSSO_OK) { - g_print("Error setting D-BUS callback (%d)\n", result); - return OSSO_ERROR; - } - - // Add handler for Exit D-BUS messages - result = osso_application_set_exit_cb(appdata->osso_context, - exit_event_handler, - (gpointer) appdata); - if (result != OSSO_OK) { - g_print("Error setting exit callback (%d)\n", result); - return OSSO_ERROR; - } - - // Begin the main application - gtk_widget_show_all(GTK_WIDGET(app)); - gtk_main(); - - // Deinitialize OSSO - osso_deinitialize(osso_context); - - return 0; -} diff --git a/backends/maemo/maemo-sdl.cpp b/backends/maemo/maemo-sdl.cpp deleted file mode 100644 index dfb6cb7048..0000000000 --- a/backends/maemo/maemo-sdl.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "backends/maemo/maemo-sdl.h" - - -void OSystem_MAEMO::loadGFXMode() { - if (_fullscreen || effectiveScreenHeight() > 400) { - _overlayWidth = 800; - _overlayHeight = 480; - - _fullscreen = true; - } else { - _overlayWidth = 720; - _overlayHeight = 400; - } - - if (_screenHeight != 200) - _adjustAspectRatio = false; - - OSystem_SDL::loadGFXMode(); -} diff --git a/backends/maemo/maemo-sdl.h b/backends/maemo/maemo-sdl.h deleted file mode 100644 index eff02df21f..0000000000 --- a/backends/maemo/maemo-sdl.h +++ /dev/null @@ -1,41 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001-2006 The ScummVM project - * - * 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 MAEMO_SDL_H -#define MAEMO_SDL_H - -#include "common/stdafx.h" -#include "backends/sdl/sdl-common.h" - -//#include "CEkeys.h" - -#include - - -class OSystem_MAEMO : public OSystem_SDL { -public: - OSystem_MAEMO() {}; - - void loadGFXMode(); -}; - -#endif diff --git a/backends/maemo/main.cpp b/backends/maemo/main.cpp deleted file mode 100644 index 2631d35000..0000000000 --- a/backends/maemo/main.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include -#include -#include -#include - -#include -#include - -#include "backends/maemo/maemo-sdl.h" -#include "base/main.h" -#include -#include -#include - -#include -#include - -#define OSSO_APP_NAME "scummvm" -#define OSSO_APP_VERSION "0.9.0CVS" - -void set_doubling(unsigned char enable) { - return; - - SDL_SysWMinfo wminfo; - SDL_VERSION(&wminfo.version); - SDL_GetWMInfo(&wminfo); - XSPSetPixelDoubling(wminfo.info.x11.display, 0, enable); -} - -int main(int argc, char *argv[]) { - osso_context_t *osso_context; - - // Initialize maemo application - //osso_context = osso_initialize(OSSO_APP_NAME, OSSO_APP_VERSION, TRUE, NULL); - - // Check that initialization was ok - //if (osso_context == NULL) { - // return OSSO_ERROR; - //} - - // Maemo task navigator priority inheritance fix - setpriority(PRIO_PROCESS, 0, 0); - - set_doubling(0); - - g_system = new OSystem_MAEMO(); - assert(g_system); - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - g_system->quit(); // TODO: Consider removing / replacing this! - - /* Deinitialize OSSO */ - //osso_deinitialize(osso_context); - - set_doubling(0); - - return res; -} diff --git a/backends/maemo/portdefs.h b/backends/maemo/portdefs.h deleted file mode 100644 index f825e5c4e2..0000000000 --- a/backends/maemo/portdefs.h +++ /dev/null @@ -1,69 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2006 The ScummVM project - * - * 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 PORTDEFS_H -#define PORTDEFS_H - -#define SCUMM_LITTLE_ENDIAN -#define SCUMM_NEED_ALIGNMENT - -#undef HAVE_X86 - -#undef LINUPY - -/* Data types */ -typedef unsigned char byte; -typedef unsigned int uint; -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef signed char int8; -typedef signed short int16; -typedef signed int int32; - -/* Libs */ -#undef USE_VORBIS -#undef USE_TREMOR -#undef USE_FLAC -#undef USE_MAD -#define USE_ZLIB -#undef USE_MPEG2 -#undef USE_MT32EMU - -/* Whether we should use i386 assembly routines */ -#undef USE_NASM - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void set_doubling(unsigned char enable); - -#endif /* PORTDEFS_H */ - - diff --git a/backends/morphos/MorphOS.readme b/backends/morphos/MorphOS.readme deleted file mode 100644 index 201c8f32b8..0000000000 --- a/backends/morphos/MorphOS.readme +++ /dev/null @@ -1,13 +0,0 @@ -This directory contains the source for the MorphOS port of ScummVM. To build, you -must have a proper Geek Gadgets installation. If you don't have the includes for -Etude and cdda.library, check my webpage. If they aren't uploaded yet, feel free -to e-mail me. - -You don't have to build ScummVM yourself. The latest official and CVS binaries are -available from my website at: - -http://www.muenster.de/~tomjoad/scummvm.html - -Ruediger Hanke -tomjoad@muenster.de - diff --git a/backends/morphos/build.rules b/backends/morphos/build.rules deleted file mode 100644 index 13b0033b8c..0000000000 --- a/backends/morphos/build.rules +++ /dev/null @@ -1,11 +0,0 @@ -CXX = g++ -CXXFLAGS = -Wno-multichar -fstrength-reduce -fsigned-char -O2 -DEFINES = -DNDEBUG -LDFLAGS = -noixemul -s -LIBS = -lamiga -lamigastubs -lcybergraphics -INCLUDES += -Ibackends/morphos -MODULES += backends/morphos -OBJS += backends/morphos/morphos.o backends/morphos/morphos_scaler.o \ - backends/morphos/morphos_sound.o backends/morphos/morphos_start.o \ - backends/morphos/morphos_timer.o - diff --git a/backends/morphos/morphos.cpp b/backends/morphos/morphos.cpp deleted file mode 100644 index 889976afc4..0000000000 --- a/backends/morphos/morphos.cpp +++ /dev/null @@ -1,1645 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2002 Rüdiger Hanke - * - * 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. - * - * MorphOS interface - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "base/engine.h" -#include "common/util.h" -#include "scumm/scumm.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "morphos.h" -#include "morphos_sound.h" -#include "morphos_scaler.h" - -static TagItem PlayTags[] = { { CDPA_StartTrack, 1 }, - { CDPA_StartFrame, 0 }, - { CDPA_EndTrack, 1 }, - { CDPA_EndFrame, 0 }, - { CDPA_Loops, 1 }, - { TAG_DONE, 0 } - }; - -static CONST_STRPTR MonkeyCDIDs[] = { "ID2500496F035CBC", "ID250040360345DB", NULL }; -static CONST_STRPTR LoomCDIDs[] = { NULL }; -static CONST_STRPTR MonkeyNames[] = { "Monkey1CD", "Madness", NULL }; -static CONST_STRPTR LoomNames[] = { "LoomCD", NULL }; - -#define BLOCKSIZE_X 32 -#define BLOCKSIZE_Y 8 - -#define BLOCKS_X (ScummBufferWidth/BLOCKSIZE_X) -#define BLOCKS_Y (ScummBufferHeight/BLOCKSIZE_Y) -#define BLOCK_ID(x, y) ((y/BLOCKSIZE_Y)*BLOCKS_X+(x/BLOCKSIZE_X)) - -OSystem_MorphOS *OSystem_MorphOS::create(SCALERTYPE gfx_scaler, bool full_screen) -{ - OSystem_MorphOS *syst = new OSystem_MorphOS(gfx_scaler, full_screen); - - if (!syst || !syst->Initialise()) - { - delete syst; - error("Failed to create system object. Exiting."); - } - - return syst; -} - -OSystem_MorphOS::OSystem_MorphOS(SCALERTYPE gfx_mode, bool full_screen) -{ - ScummScreen = NULL; - ScummWindow = NULL; - ScummBuffer = NULL; - ScummScreenBuffer[0] = NULL; - ScummScreenBuffer[1] = NULL; - ScummRenderTo = NULL; - ScummNoCursor = NULL; - ScummSoundThread = NULL; - ScummWinX = -1; - ScummWinY = -1; - ScummDefaultMouse = false; - ScummOrigMouse = false; - ScummShakePos = 0; - ScummScaler = gfx_mode; - ScummScale = (gfx_mode == ST_NONE) ? 0 : 1; - ScummDepth = 0; - Scumm16ColFmt16 = false; - ScummScrWidth = 0; - ScummScrHeight = 0; - ScreenChanged = false; - DirtyBlocks = NULL; - BlockColors = NULL; - UpdateRects = 0; - Scaler = NULL; - FullScreenMode = full_screen; - CDrive = NULL; - CDDATrackOffset = 0; - strcpy(ScummWndTitle, "ScummVM MorphOS"); - TimerMsgPort = NULL; - TimerIORequest = NULL; - InputMsgPort = NULL; - InputIORequest = NULL; - ThreadPort = NULL; - OvlCMap = NULL; - OvlBitMap = NULL; - OvlSavedBuffer = NULL; - TimerBase = NULL; - ScummNoCursor = NULL; - UpdateRegion = NULL; - NewUpdateRegion = NULL; - MouseImage = NULL; -} - -bool OSystem_MorphOS::Initialise() -{ - OpenATimer(&TimerMsgPort, (IORequest **) &TimerIORequest, UNIT_MICROHZ); - - if ((InputMsgPort = CreateMsgPort())) - { - if ((InputIORequest = (IOStdReq*) CreateIORequest(InputMsgPort, sizeof (IOStdReq)))) - { - if ((OpenDevice("input.device", NULL, (IORequest *) InputIORequest, NULL))) - { - DeleteIORequest(InputIORequest); - DeleteMsgPort(InputMsgPort); - InputIORequest = NULL; - InputMsgPort = NULL; - } - } - else - { - DeleteMsgPort(InputMsgPort); - InputMsgPort = NULL; - } - } - - if (!InputIORequest) - { - warning("input.device could not be opened"); - return false; - } - - ThreadPort = CreateMsgPort(); - if (!ThreadPort) - { - warning("Unable to create a message port"); - return false; - } - - OvlCMap = GetColorMap(256); - - InitSemaphore(&CritSec); - - TimerBase = (Library*) TimerIORequest->tr_node.io_Device; - ScummNoCursor = (UWORD *) AllocVec(16, MEMF_CLEAR); - UpdateRegion = NewRegion(); - NewUpdateRegion = NewRegion(); - if (!UpdateRegion || !NewUpdateRegion) - { - warning("Could not create region for screen update"); - return false; - } - if (!OvlCMap) - { - warning("Could not allocate overlay color map"); - return false; - } - if (!ScummNoCursor) - { - warning("Could not allocate empty cursor image"); - return false; - } - - return true; -} - -OSystem_MorphOS::~OSystem_MorphOS() -{ - if (DirtyBlocks) - { - FreeVec(DirtyBlocks); - - for (int b = 0; b < BLOCKS_X*BLOCKS_Y; b++) - FreeVec(BlockColors[b]); - FreeVec(BlockColors); - } - - if (OvlCMap) - FreeColorMap(OvlCMap); - - delete Scaler; - - if (UpdateRegion) - DisposeRegion(UpdateRegion); - - if (NewUpdateRegion) - DisposeRegion(NewUpdateRegion); - - if (ThreadPort) - DeleteMsgPort(ThreadPort); - - if (CDrive && CDDABase) - { - CDDA_Stop(CDrive); - CDDA_ReleaseDrive(CDrive); - } - - if (InputIORequest) - { - CloseDevice((IORequest *) InputIORequest); - DeleteIORequest((IORequest *) InputIORequest); - } - - if (InputMsgPort) - DeleteMsgPort(InputMsgPort); - - if (TimerIORequest) - { - CloseDevice((IORequest *) TimerIORequest); - DeleteIORequest((IORequest *) TimerIORequest); - } - - if (TimerMsgPort) - DeleteMsgPort(TimerMsgPort); - - if (ScummNoCursor) - FreeVec(ScummNoCursor); - - if (ScummBuffer) - FreeVec(ScummBuffer); - - if (OvlSavedBuffer) - FreeVec(OvlSavedBuffer); - - if (ScummRenderTo && !ScummScreen) - FreeBitMap(ScummRenderTo); - - if (OvlBitMap) - FreeVec(OvlBitMap); - - if (ScummWindow) - CloseWindow(ScummWindow); - - if (ScummScreen) - { - if (ScummScreenBuffer[0]) - FreeScreenBuffer(ScummScreen, ScummScreenBuffer[0]); - if( ScummScreenBuffer[1] ) - FreeScreenBuffer(ScummScreen, ScummScreenBuffer[1]); - CloseScreen(ScummScreen); - } -} - -bool OSystem_MorphOS::OpenATimer(MsgPort **port, IORequest **req, ULONG unit, bool required) -{ - *req = NULL; - const char *err_msg = NULL; - - *port = CreateMsgPort(); - if (*port) - { - *req = (IORequest *) CreateIORequest(*port, sizeof (timerequest)); - if (*req) - { - if (OpenDevice(TIMERNAME, unit, *req, 0)) - { - DeleteIORequest(*req); - *req = NULL; - err_msg = "Failed to open timer device"; - } - } - else - err_msg = "Failed to create IO request"; - } - else - err_msg = "Failed to create message port"; - - if (err_msg) - { - if (required) - error(err_msg); - warning(err_msg); - } - - return *req != NULL; -} - -uint32 OSystem_MorphOS::getMillis() -{ - int ticks = clock(); - ticks *= (1000/CLOCKS_PER_SEC); - return ticks; -} - -void OSystem_MorphOS::delayMillis(uint msecs) -{ -/* TimerIORequest->tr_node.io_Command = TR_ADDREQUEST; - TimerIORequest->tr_time.tv_secs = 0; - TimerIORequest->tr_time.tv_micro = msecs*1000; - DoIO((IORequest *) TimerIORequest);*/ - TimeDelay(UNIT_MICROHZ, 0, msecs*1000); -} - -void OSystem_MorphOS::setTimerCallback(TimerProc callback, int timer) -{ - warning("setTimerCallback() unexpectedly called"); -} - -OSystem::MutexRef OSystem_MorphOS::createMutex() -{ - SignalSemaphore *sem = (SignalSemaphore *) AllocVec(sizeof (SignalSemaphore), MEMF_PUBLIC); - - if (sem) - InitSemaphore(sem); - - return (MutexRef)sem; -} - -void OSystem_MorphOS::lockMutex(MutexRef mutex) -{ - ObtainSemaphore((SignalSemaphore *) mutex); -} - -void OSystem_MorphOS::unlockMutex(MutexRef mutex) -{ - ReleaseSemaphore((SignalSemaphore *)mutex); -} - -void OSystem_MorphOS::deleteMutex(MutexRef mutex) -{ - FreeVec(mutex); -} - -uint32 OSystem_MorphOS::property(int param, Property *value) -{ - AUTO_LOCK - - switch (param) - { - case PROP_GET_FULLSCREEN: - return ScummScreen != NULL; - - case PROP_TOGGLE_FULLSCREEN: - CreateScreen(CSDSPTYPE_TOGGLE); - return 1; - - case PROP_SET_WINDOW_CAPTION: - sprintf(ScummWndTitle, "ScummVM MorphOS - %s", value->caption); - if (ScummWindow) - SetWindowTitles(ScummWindow, ScummWndTitle, ScummWndTitle); - return 1; - - case PROP_OPEN_CD: - { - CONST_STRPTR *ids = NULL, *names = NULL; - - if (g_scumm) - GameID = g_scumm->_gameId; - - switch (GameID) - { - case GID_MONKEY: - case GID_MONKEY_SEGA: - ids = MonkeyCDIDs; - names = MonkeyNames; - break; - - case GID_LOOM256: - ids = LoomCDIDs; - names = LoomNames; - break; - } - - if (!CDDABase) CDDABase = OpenLibrary("cdda.library", 2); - if (CDDABase) - { - CDrive = NULL; - if (ids) - { - int i = 0; - - while (ids[i] && !CDrive) - { - TagItem FindCDTags[] = { { CDFA_CDID, (ULONG) ids[i] }, - { TAG_DONE, 0 } - }; - CDrive = CDDA_FindNextDriveA(NULL, FindCDTags); - i++; - } - } - - if (!CDrive && names) - { - int i = 0; - - while (names[i] && !CDrive) - { - TagItem FindCDTags[] = { { CDFA_VolumeName, (ULONG) names[i] }, - { TAG_DONE, 0 } - }; - CDrive = CDDA_FindNextDriveA(NULL, FindCDTags); - i++; - } - } - - if (CDrive) - { - if (!CDDA_ObtainDriveA(CDrive, CDDA_SHARED_ACCESS, NULL)) - { - CDrive = NULL; - warning("Failed to obtain CD drive - music will not play"); - } - else if (GameID == GID_LOOM256) - { - // Offset correction *may* be required - CDS_TrackInfo ti = { sizeof (CDS_TrackInfo) }; - - if (CDDA_GetTrackInfo(CDrive, 1, 0, &ti)) - CDDATrackOffset = ti.ti_TrackStart.tm_Format.tm_Frame-22650; - } - } - else - warning( "Could not find game CD inserted in CD-ROM drive - cd audio will not play" ); - } - else - warning( "Failed to open cdda.library - cd audio will not play" ); - break; - } - - case PROP_GET_SAMPLE_RATE: - return SAMPLES_PER_SEC; - } - - return 0; -} - -void OSystem_MorphOS::playCD(int track, int num_loops, int start_frame, int duration) -{ - if (CDrive && start_frame >= 0) - { - if (start_frame > 0) - start_frame -= CDDATrackOffset; - - PlayTags[0].ti_Data = track; - PlayTags[1].ti_Data = start_frame; - PlayTags[2].ti_Data = (duration == 0) ? track+1 : track; - PlayTags[3].ti_Data = duration ? start_frame+duration : 0; - PlayTags[4].ti_Data = (num_loops == 0) ? 1 : num_loops; - CDDA_PlayA(CDrive, PlayTags); - } -} - -void OSystem_MorphOS::stopCD() -{ - if (CDrive) - CDDA_Stop(CDrive); -} - -bool OSystem_MorphOS::pollCD() -{ - ULONG status; - - if (CDrive == NULL) - return false; - - CDDA_GetAttr(CDDA_Status, CDrive, &status); - return status == CDDA_Status_Busy; -} - -void OSystem_MorphOS::updateCD() -{ -} - -void OSystem_MorphOS::quit() -{ - int num_threads = 0; - - if (ScummSoundThread) - { - num_threads++; - Signal((Task *) ScummSoundThread, SIGBREAKF_CTRL_C); - ScummSoundThread = NULL; - } - - // TODO: this code could probably greatly simplified now that there is - // only one thread left... - while (num_threads > 0) - { - Message* msg; - - WaitPort(ThreadPort); - while (msg = GetMsg(ThreadPort)) - num_threads--; - } - - exit(0); -} - -#define CVT8TO32(col) ((col<<24) | (col<<16) | (col<<8) | col) - -void OSystem_MorphOS::setPalette(const byte *colors, uint start, uint num) -{ - const byte *data = colors; - UWORD changed_colors[256]; - UWORD num_changed = 0; - - for (uint i = start; i != start+num; i++) - { - ULONG color32 = (data[0] << 16) | (data[1] << 8) | data[2]; - if (color32 != ScummColors[i]) - { - if (ScummDepth == 8) - SetRGB32(&ScummScreen->ViewPort, i, CVT8TO32(data[0]), CVT8TO32(data[1]), CVT8TO32(data[2])); - ScummColors16[i] = Scumm16ColFmt16 ? (((data[0]*31)/255) << 11) | (((data[1]*63)/255) << 5) | ((data[ 2 ]*31)/255) : (((data[0]*31)/255) << 10) | (((data[1]*31)/255) << 5) | ((data[2]*31)/255); - ScummColors[i] = color32; - changed_colors[num_changed++] = i; - } - data += 4; - } - - if (ScummScale || ScummDepth != 8) - { - if (DirtyBlocks && num_changed < 200) - { - for (int b = 0; b < BLOCKS_X*BLOCKS_Y; b++) - { - UWORD *block_colors = BlockColors[b]; - UWORD *color_ptr = changed_colors; - for (int c = 0; c < num_changed; c++) - { - if (block_colors[*color_ptr++]) - { - UWORD x, y; - x = b % BLOCKS_X; - y = b / BLOCKS_X; - DirtyBlocks[b] = true; - AddUpdateRect(x*BLOCKSIZE_X, y*BLOCKSIZE_Y, BLOCKSIZE_X, BLOCKSIZE_Y); - break; - } - } - } - } - else - AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); - } -} - -void OSystem_MorphOS::CreateScreen(CS_DSPTYPE dspType) -{ - LONG mode = INVALID_ID; - int depths[] = { 8, 32, 16, 15, 0 }; - int i; - Screen *wb = NULL; - - if (dspType != CSDSPTYPE_KEEP) - FullScreenMode = (dspType == CSDSPTYPE_FULLSCREEN) || (dspType == CSDSPTYPE_TOGGLE && !FullScreenMode); - - if (ScummRenderTo && !ScummScreen) - FreeBitMap(ScummRenderTo); - ScummRenderTo = NULL; - - if (ScummWindow) - { - if (ScummScreen == NULL) - { - ScummWinX = ScummWindow->LeftEdge; - ScummWinY = ScummWindow->TopEdge; - } - CloseWindow (ScummWindow); - ScummWindow = NULL; - } - - if (ScummScreen) - { - if (ScummScreenBuffer[0]) - FreeScreenBuffer(ScummScreen, ScummScreenBuffer[0]); - if (ScummScreenBuffer[1]) - FreeScreenBuffer(ScummScreen, ScummScreenBuffer[1]); - CloseScreen(ScummScreen); - ScummScreen = NULL; - } - - ScummScrWidth = ScummBufferWidth << ScummScale; - ScummScrHeight = ScummBufferHeight << ScummScale; - - if (FullScreenMode) - { - for (i = ScummScale; mode == INVALID_ID && depths[i]; i++) - mode = BestCModeIDTags(CYBRBIDTG_NominalWidth, ScummScrWidth, - CYBRBIDTG_NominalHeight, ScummScrHeight, - CYBRBIDTG_Depth, depths[i], - TAG_DONE - ); - ScummDepth = depths[i-1]; - - if (mode == INVALID_ID) - error("Could not find suitable screenmode"); - - ScummScreen = OpenScreenTags(NULL, SA_AutoScroll, TRUE, - SA_Depth, ScummDepth, - SA_Width, STDSCREENWIDTH, - SA_Height, STDSCREENHEIGHT, - SA_DisplayID, mode, - SA_ShowTitle, FALSE, - SA_Type, CUSTOMSCREEN, - SA_Title, "ScummVM MorphOS", - TAG_DONE - ); - - if (ScummScreen == NULL) - error("Failed to open screen"); - - LONG RealDepth = GetBitMapAttr(&ScummScreen->BitMap, BMA_DEPTH); - if (RealDepth != ScummDepth) - { - warning("Screen did not open in expected depth"); - ScummDepth = RealDepth; - } - ScummScreenBuffer[0] = AllocScreenBuffer(ScummScreen, NULL, SB_SCREEN_BITMAP); - ScummScreenBuffer[1] = AllocScreenBuffer(ScummScreen, NULL, 0); - ScummRenderTo = ScummScreenBuffer[1]->sb_BitMap; - ScummPaintBuffer = 1; - - if (ScummScreenBuffer[0] == NULL || ScummScreenBuffer[1] == NULL) - error("Failed to allocate screen buffer"); - - // Make both buffers black to avoid grey strip on bottom of screen - RastPort rp; - InitRastPort(&rp); - SetRGB32(&ScummScreen->ViewPort, 0, 0, 0, 0); - rp.BitMap = ScummScreenBuffer[0]->sb_BitMap; - FillPixelArray(&ScummScreen->RastPort, 0, 0, ScummScreen->Width, ScummScreen->Height, 0); - rp.BitMap = ScummRenderTo; - FillPixelArray(&rp, 0, 0, ScummScreen->Width, ScummScreen->Height, 0); - - if (ScummDepth == 8) - { - for (int color = 0; color < 256; color++) - { - ULONG r, g, b; - - r = (ScummColors[color] >> 16) & 0xff; - g = (ScummColors[color] >> 8) & 0xff; - b = (ScummColors[color] >> 0) & 0xff; - SetRGB32(&ScummScreen->ViewPort, color, CVT8TO32(r), CVT8TO32(g), CVT8TO32(b)); - } - } - } - else - { - wb = LockPubScreen(NULL); - if (wb == NULL) - error("Could not lock default public screen"); - - ScreenToFront(wb); - } - - ScummWindow = OpenWindowTags(NULL, WA_Left, (wb && ScummWinX >= 0) ? ScummWinX : 0, - WA_Top, wb ? ((ScummWinY >= 0) ? ScummWinY : wb->BarHeight+1) : 0, - WA_InnerWidth, FullScreenMode ? ScummScreen->Width : ScummScrWidth, - WA_InnerHeight, FullScreenMode ? ScummScreen->Height : ScummScrHeight, - WA_Activate, TRUE, - WA_Title, wb ? ScummWndTitle : NULL, - WA_ScreenTitle, wb ? ScummWndTitle : NULL, - WA_Borderless, FullScreenMode, - WA_CloseGadget, !FullScreenMode, - WA_DepthGadget, !FullScreenMode, - WA_DragBar, !FullScreenMode, - WA_ReportMouse, TRUE, - WA_RMBTrap, TRUE, - WA_IDCMP, IDCMP_RAWKEY | - IDCMP_MOUSEMOVE | - IDCMP_CLOSEWINDOW | - IDCMP_MOUSEBUTTONS, - WA_CustomScreen, FullScreenMode ? (ULONG)ScummScreen : (ULONG)wb, - TAG_DONE - ); - - if (wb) - UnlockPubScreen(NULL, wb); - - if (ScummWindow == NULL) - error("Failed to open window"); - - if (!ScummDefaultMouse) - { - SetPointer(ScummWindow, ScummNoCursor, 1, 1, 0, 0); - ScummOrigMouse = false; - } - - if (ScummScreen == NULL) - { - ScummDepth = GetCyberMapAttr(ScummWindow->RPort->BitMap, CYBRMATTR_DEPTH); - if (ScummDepth == 8) - error("Default public screen must be 15 bit or higher if you want to play in window mode"); - - ScummRenderTo = AllocBitMap(ScummScrWidth, ScummScrHeight, ScummDepth, BMF_MINPLANES, ScummWindow->RPort->BitMap); - if (ScummRenderTo == NULL) - error("Failed to allocate bitmap"); - } - - if ((ScummDepth == 15 && Scumm16ColFmt16) || (ScummDepth == 16 && !Scumm16ColFmt16)) - { - for (int col = 0; col < 256; col++) - { - int r = (ScummColors[col] >> 16) & 0xff; - int g = (ScummColors[col] >> 8) & 0xff; - int b = ScummColors[col] & 0xff; - ScummColors16[col] = (Scumm16ColFmt16 == false) ? (((r*31)/255) << 11) | (((g*63)/255) << 5) | ((b*31)/255) : (((r*31)/255) << 10) | (((g*31)/255) << 5) | ((b*31)/255); - } - - Scumm16ColFmt16 = (ScummDepth == 16); - } - - if (OvlBitMap) - FreeVec(OvlBitMap); - - OvlBitMap = AllocVec(ScummBufferWidth*ScummBufferHeight*3, MEMF_PUBLIC | MEMF_CLEAR); - if (OvlBitMap == NULL) - error("Failed to allocated bitmap for overlay"); - - if (Scaler) - { - delete Scaler; - Scaler = NULL; - } - - if (ScummScale) - { - Scaler = MorphOSScaler::Create(ScummScaler, ScummBuffer, ScummBufferWidth, ScummBufferHeight, ScummColors, ScummColors16, ScummRenderTo); - if (Scaler == NULL) - { - warning("Failed to create scaler - scaling will be disabled"); - SwitchScalerTo(ST_NONE); - } - } - - AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); -} - -void OSystem_MorphOS::SwitchScalerTo(SCALERTYPE newScaler) -{ - if (newScaler == ST_NONE && ScummScale != 0) - { - if (Scaler) - { - delete Scaler; - Scaler = NULL; - } - ScummScale = 0; - ScummScaler = ST_NONE; - CreateScreen(ScummScreen ? CSDSPTYPE_FULLSCREEN : CSDSPTYPE_WINDOWED); - } - else - { - if (ScummScale == 0) - { - ScummScale = 1; - ScummScaler = newScaler; - CreateScreen(ScummScreen ? CSDSPTYPE_FULLSCREEN : CSDSPTYPE_WINDOWED); - } - else if (ScummScaler != newScaler) - { - ScummScaler = newScaler; - if (Scaler) - delete Scaler; - Scaler = MorphOSScaler::Create(ScummScaler, ScummBuffer, ScummBufferWidth, ScummBufferHeight, ScummColors, ScummColors16, ScummRenderTo); - if (Scaler == NULL) - { - warning("Failed to create scaler - scaling will be disabled"); - SwitchScalerTo(ST_NONE); - } - else - AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); - } - } -} - -bool OSystem_MorphOS::pollEvent(Event &event) -{ - IntuiMessage *ScummMsg; - - ScummMsg = (IntuiMessage *) GetMsg(ScummWindow->UserPort); - if (ScummMsg) - { - switch (ScummMsg->Class) - { - case IDCMP_RAWKEY: - { - InputEvent FakedIEvent; - char charbuf; - int qual = 0; - - memset(&FakedIEvent, 0, sizeof (InputEvent)); - FakedIEvent.ie_Class = IECLASS_RAWKEY; - FakedIEvent.ie_Code = ScummMsg->Code; - - if (ScummMsg->Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT)) - qual |= KBD_ALT; - if (ScummMsg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) - qual |= KBD_SHIFT; - if (ScummMsg->Qualifier & IEQUALIFIER_CONTROL) - qual |= KBD_CTRL; - event.kbd.flags = qual; - - event.type = (ScummMsg->Code & IECODE_UP_PREFIX) ? EVENT_KEYUP : EVENT_KEYDOWN; - ScummMsg->Code &= ~IECODE_UP_PREFIX; - - if (ScummMsg->Code >= RAWKEY_F1 && ScummMsg->Code <= RAWKEY_F10) - { - /* - * Function key - */ - event.kbd.ascii = (ScummMsg->Code-RAWKEY_F1)+315; - event.kbd.keycode = 0; - } - else if (ScummMsg->Code == RAWKEY_F11 || ScummMsg->Code == RAWKEY_F12) - { - /* - * Function key on PC keyboard - */ - event.kbd.ascii = (ScummMsg->Code == RAWKEY_F11) ? 325 : 326; - event.kbd.keycode = 0; - } - else if (ScummMsg->Code == NM_WHEEL_UP || ScummMsg->Code == NM_WHEEL_DOWN) - { - /* - * Wheelmouse event - */ - event.type = (ScummMsg->Code == NM_WHEEL_UP) ? EVENT_WHEELUP : EVENT_WHEELDOWN; - } - else if (MapRawKey(&FakedIEvent, &charbuf, 1, NULL) == 1) - { - if (qual == KBD_CTRL && charbuf == 'z') - { - event.type = EVENT_QUIT; - break; - } - else if (qual == KBD_ALT) - { - if (charbuf >= '0' && charbuf <= '9') - { - SCALERTYPE new_scaler = MorphOSScaler::FindByIndex(charbuf-'0'); - ReplyMsg((Message *) ScummMsg); - if (new_scaler != ST_INVALID) - SwitchScalerTo(new_scaler); - return false; - } - else if (charbuf == 'x') - { - event.type = EVENT_QUIT; - break; - } - else if (charbuf == 0x0d) - { - ReplyMsg((Message *) ScummMsg); - CreateScreen(CSDSPTYPE_TOGGLE); - return false; - } - } - - event.kbd.ascii = charbuf; - event.kbd.keycode = charbuf; - } - break; - } - - case IDCMP_MOUSEMOVE: - { - LONG newx, newy; - - newx = (ScummMsg->MouseX-ScummWindow->BorderLeft) >> ScummScale; - newy = (ScummMsg->MouseY-ScummWindow->BorderTop) >> ScummScale; - - if (!FullScreenMode && !ScummDefaultMouse) - { - if (newx < 0 || newx > (LONG) ScummBufferWidth || - newy < 0 || newy > (LONG) ScummBufferHeight - ) - { - if (!ScummOrigMouse) - { - ScummOrigMouse = true; - ClearPointer(ScummWindow); - } - } - else if (ScummOrigMouse) - { - ScummOrigMouse = false; - SetPointer(ScummWindow, ScummNoCursor, 1, 1, 0, 0); - } - } - else if (FullScreenMode) - newy = newy > ScummScale)-2; - - event.type = EVENT_MOUSEMOVE; - event.mouse.x = newx; - event.mouse.y = newy; - set_mouse_pos(event.mouse.x, event.mouse.y); - break; - } - - case IDCMP_MOUSEBUTTONS: - { - int newx, newy; - - newx = (ScummMsg->MouseX-ScummWindow->BorderLeft) >> ScummScale; - newy = (ScummMsg->MouseY-ScummWindow->BorderTop) >> ScummScale; - - switch (ScummMsg->Code) - { - case SELECTDOWN: - event.type = EVENT_LBUTTONDOWN; - break; - - case SELECTUP: - event.type = EVENT_LBUTTONUP; - break; - - case MENUDOWN: - event.type = EVENT_RBUTTONDOWN; - break; - - case MENUUP: - event.type = EVENT_RBUTTONUP; - break; - - default: - ReplyMsg((Message *)ScummMsg); - return false; - } - event.mouse.x = newx; - event.mouse.y = newy; - break; - } - - case IDCMP_CLOSEWINDOW: - event.type = EVENT_QUIT; - break; - } - - if (ScummMsg) - ReplyMsg((Message *) ScummMsg); - - return true; - } - - return false; -} - -void OSystem_MorphOS::warpMouse(int x, int y) -{ - if (InputIORequest) - { - InputEvent* FakeIE; - IEPointerPixel* NewPixel; - - /* - * Fake a mousemove input event - */ - if ((FakeIE = (InputEvent*) AllocVec(sizeof (InputEvent), MEMF_PUBLIC))) - { - if ((NewPixel = (IEPointerPixel*) AllocVec(sizeof (IEPointerPixel), MEMF_PUBLIC))) - { - NewPixel->iepp_Screen = ScummWindow->WScreen; - NewPixel->iepp_Position.X = (x << ScummScale) + ScummWindow->LeftEdge + ScummWindow->BorderLeft; - NewPixel->iepp_Position.Y = (y << ScummScale) + ScummWindow->TopEdge + ScummWindow->BorderTop; - - FakeIE->ie_EventAddress = NewPixel; - FakeIE->ie_NextEvent = NULL; - FakeIE->ie_Class = IECLASS_NEWPOINTERPOS; - FakeIE->ie_SubClass = IESUBCLASS_PIXEL; - FakeIE->ie_Code = IECODE_NOBUTTON; - FakeIE->ie_Qualifier = NULL; - - InputIORequest->io_Data = FakeIE; - InputIORequest->io_Length = sizeof (InputEvent); - InputIORequest->io_Command = IND_WRITEEVENT; - DoIO((IORequest *) InputIORequest); - - FreeVec(NewPixel); - } - FreeVec(FakeIE); - } - } -} - -void OSystem_MorphOS::setShakePos(int shake_pos) -{ - ScummShakePos = shake_pos; - AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); -} - -#define MOUSE_INTERSECTS(x, y, w, h) \ - (!((MouseOldX+MouseOldWidth <= x ) || (MouseOldX >= x+w) || \ - (MouseOldY+MouseOldHeight <= y) || (MouseOldY >= y+h))) - -/* Copy part of bitmap */ -void OSystem_MorphOS::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) -{ - byte *dst; - - if (x < 0) { w+=x; src-=x; x = 0; } - if (y < 0) { h+=y; src-=y*pitch; y = 0; } - if (w >= ScummBufferWidth-x) { w = ScummBufferWidth - x; } - if (h >= ScummBufferHeight-y) { h = ScummBufferHeight - y; } - - if (w <= 0 || h <= 0) - return; - - AUTO_LOCK - - if (MouseDrawn) - { - if (MOUSE_INTERSECTS(x, y, w, h)) - UndrawMouse(); - } - - AddUpdateRect(x, y, w, h); - - dst = (byte *)ScummBuffer+y*ScummBufferWidth + x; - if (DirtyBlocks) - { - int cx, cy; - int block = BLOCK_ID(x, y); - int line_block = block; - int start_block = BLOCKSIZE_X-(x % BLOCKSIZE_X); - int start_y_block = BLOCKSIZE_Y-(y % BLOCKSIZE_Y); - int next_block; - int next_y_block; - UWORD *block_cols = BlockColors[block]; - - if (start_block == 0) - start_block = BLOCKSIZE_X; - if (start_y_block == 0) - start_y_block = BLOCKSIZE_Y; - - next_block = start_block; - next_y_block = start_y_block; - for (cy = 0; cy < h; cy++) - { - for (cx = 0; cx < w; cx++) - { - UWORD old_pixel = *dst; - UWORD src_pixel = *src++; - if (old_pixel != src_pixel) - { - *dst++ = src_pixel; - block_cols[old_pixel]--; - block_cols[src_pixel]++; - } - else - dst++; - if (--next_block == 0) - { - block++; - block_cols = BlockColors[block]; - next_block = BLOCKSIZE_X; - } - } - if (--next_y_block == 0) - { - line_block += BLOCKS_X; - next_y_block = BLOCKSIZE_Y; - } - block = line_block; - block_cols = BlockColors[block]; - next_block = start_block; - dst += ScummBufferWidth-w; - src += pitch-w; - } - } - else - { - do - { - memcpy(dst, src, w); - dst += ScummBufferWidth; - src += pitch; - } while (--h); - } -} - -bool OSystem_MorphOS::AddUpdateRect(WORD x, WORD y, WORD w, WORD h) -{ - if (UpdateRects > 25) - return false; - - if (x < 0) { w+=x; x = 0; } - if (y < 0) { h+=y; y = 0; } - if (w >= ScummBufferWidth-x) { w = ScummBufferWidth - x; } - if (h >= ScummBufferHeight-y) { h = ScummBufferHeight - y; } - - if (w <= 0 || h <= 0) - return false; - - if (++UpdateRects > 25) - { - x = 0; y = 0; - w = ScummBufferWidth; h = ScummBufferHeight; - } - - Rectangle update_rect = { x, y, x+w, y+h }; - OrRectRegion(NewUpdateRegion, &update_rect); - ScreenChanged = true; - - return true; -} - -void OSystem_MorphOS::updateScreen() -{ - AUTO_LOCK - - DrawMouse(); - - if (!ScreenChanged) - return; - - OrRegionRegion(NewUpdateRegion, UpdateRegion); - - if (ScummShakePos) - { - RastPort rp; - - InitRastPort(&rp); - rp.BitMap = ScummRenderTo; - - uint32 src_y = 0; - uint32 dest_y = 0; - if (ScummShakePos < 0) - src_y = -ScummShakePos; - else - dest_y = ScummShakePos; - - if (!ScummScale) - { - if (ScummDepth == 8) - WritePixelArray(ScummBuffer, 0, src_y, ScummBufferWidth, &rp, 0, dest_y, ScummBufferWidth, ScummBufferHeight-src_y-dest_y, RECTFMT_LUT8); - else - WriteLUTPixelArray(ScummBuffer, 0, src_y, ScummBufferWidth, &rp, ScummColors, 0, dest_y, ScummBufferWidth, ScummBufferHeight-src_y-dest_y, CTABFMT_XRGB8); - } - else if (Scaler->Prepare(ScummRenderTo)) - { - Scaler->Scale(0, src_y, 0, dest_y, ScummBufferWidth, ScummBufferHeight-src_y-dest_y); - Scaler->Finish(); - } - - if (ScummShakePos < 0) - FillPixelArray(&rp, 0, (ScummBufferHeight-1) << ScummScale, ScummScrWidth, -ScummShakePos << ScummScale, 0); - else - FillPixelArray(&rp, 0, 0, ScummScrWidth, ScummShakePos << ScummScale, 0); - } - else if (!ScummScale) - { - RastPort rp; - - InitRastPort(&rp); - rp.BitMap = ScummRenderTo; - - int32 src_x, src_y; - int32 src_w, src_h; - int32 reg_x, reg_y; - RegionRectangle *update_rect = UpdateRegion->RegionRectangle; - - reg_x = UpdateRegion->bounds.MinX; - reg_y = UpdateRegion->bounds.MinY; - while (update_rect) - { - src_x = update_rect->bounds.MinX; - src_y = update_rect->bounds.MinY; - src_w = update_rect->bounds.MaxX-src_x; - src_h = update_rect->bounds.MaxY-src_y; - src_x += reg_x; - src_y += reg_y; - - if (src_x) src_x--; - if (src_y) src_y--; - src_w += 2; - if (src_x+src_w >= ScummBufferWidth) - src_w = ScummBufferWidth-src_x; - src_h += 2; - if (src_y+src_h >= ScummBufferHeight) - src_h = ScummBufferHeight-src_y; - - if (ScummDepth == 8) - WritePixelArray(ScummBuffer, src_x, src_y, ScummBufferWidth, &rp, src_x, src_y, src_w, src_h, RECTFMT_LUT8); - else - WriteLUTPixelArray(ScummBuffer, src_x, src_y, ScummBufferWidth, &rp, ScummColors, src_x, src_y, src_w, src_h, CTABFMT_XRGB8); - - update_rect = update_rect->Next; - } - } - else - { - int32 src_x, src_y; - int32 src_w, src_h; - int32 reg_x, reg_y; - RegionRectangle *update_rect = UpdateRegion->RegionRectangle; - - reg_x = UpdateRegion->bounds.MinX; - reg_y = UpdateRegion->bounds.MinY; - - if (!Scaler->Prepare(ScummRenderTo)) - update_rect = NULL; - - while (update_rect) - { - src_x = update_rect->bounds.MinX; - src_y = update_rect->bounds.MinY; - src_w = update_rect->bounds.MaxX-src_x; - src_h = update_rect->bounds.MaxY-src_y; - src_x += reg_x; - src_y += reg_y; - - if (src_x) src_x--; - if (src_y) src_y--; - src_w += 2; - if (src_x+src_w >= ScummBufferWidth) - src_w = ScummBufferWidth-src_x; - src_h += 2; - if (src_y+src_h >= ScummBufferHeight) - src_h = ScummBufferHeight-src_y; - - Scaler->Scale(src_x, src_y, src_x, src_y, src_w, src_h); - update_rect = update_rect->Next; - } - Scaler->Finish(); - } - - if (ScummScreen) - { - while (!ChangeScreenBuffer(ScummScreen, ScummScreenBuffer[ScummPaintBuffer])); - ScummPaintBuffer = !ScummPaintBuffer; - ScummRenderTo = ScummScreenBuffer[ScummPaintBuffer]->sb_BitMap; - } - else - { - int32 x = (UpdateRegion->bounds.MinX-1) << ScummScale; - int32 y = (UpdateRegion->bounds.MinY-1) << ScummScale; - if (x < 0) x = 0; - if (y < 0) y = 0; - int32 w = (UpdateRegion->bounds.MaxX << ScummScale)-x+(1 << ScummScale); - int32 h = (UpdateRegion->bounds.MaxY << ScummScale)-y+(1 << ScummScale); - if (x+w > ScummScrWidth) w = ScummScrWidth-x; - if (y+h > ScummScrHeight) h = ScummScrHeight-y; - BltBitMapRastPort(ScummRenderTo, x, y, ScummWindow->RPort, ScummWindow->BorderLeft+x, ScummWindow->BorderTop+y, w, h, ABNC | ABC); - WaitBlit(); - } - - Region *new_region_part = NewUpdateRegion; - NewUpdateRegion = UpdateRegion; - ClearRegion(NewUpdateRegion); - UpdateRegion = new_region_part; - - ScreenChanged = false; - memset(DirtyBlocks, 0, BLOCKS_X*BLOCKS_Y*sizeof (bool)); - UpdateRects = 0; -} - -void OSystem_MorphOS::DrawMouse() -{ - int x,y; - byte *dst,*bak; - byte color; - - if (MouseDrawn || !MouseVisible) - return; - MouseDrawn = true; - - int ydraw = MouseY - MouseHotspotY; - int xdraw = MouseX - MouseHotspotX; - int w = MouseWidth; - int h = MouseHeight; - int x_mouseimg_offs = 0; - int y_mouseimg_offs = 0; - byte *buf; - - if (xdraw < 0) { x_mouseimg_offs = -xdraw; w += xdraw; xdraw = 0; } - if (ydraw < 0) { y_mouseimg_offs = -ydraw; h += ydraw; ydraw = 0; } - - MouseOldX = xdraw; - MouseOldY = ydraw; - MouseOldWidth = w; - MouseOldHeight = h; - - AddUpdateRect(xdraw, ydraw, w, h); - dst = (byte*)ScummBuffer + ydraw*ScummBufferWidth + xdraw; - bak = MouseBackup; - buf = MouseImage + y_mouseimg_offs*MAX_MOUSE_W + x_mouseimg_offs; - - for (y = 0; y < h; y++, dst += ScummBufferWidth, bak += MAX_MOUSE_W, buf += MouseWidth) - { - if (ydraw+y < ScummBufferHeight) - { - for (x = 0; x= 0; --b) - FreeVec(BlockColors[b]); - FreeVec(BlockColors); - BlockColors = NULL; - } - } - - if (!BlockColors) - { - FreeVec(DirtyBlocks); - DirtyBlocks = NULL; - } - } - - CreateScreen(CSDSPTYPE_KEEP); -} - -int16 OSystem_MorphOS::getWidth() -{ - return ScummScrWidth; -} - -int16 OSystem_MorphOS::getHeight() -{ - return ScummScrHeight; -} - -void OSystem_MorphOS::showOverlay() -{ - UndrawMouse(); - memcpy(OvlSavedBuffer, ScummBuffer, ScummBufferWidth*ScummBufferHeight); - clearOverlay(); - for (int c = 0; c < 256; c++) - { - ULONG r, g, b; - r = ScummColors[c] >> 16; - g = (ScummColors[c] >> 8) & 0xff; - b = ScummColors[c] & 0xff; - SetRGB32CM(OvlCMap, c, CVT8TO32(r), CVT8TO32(g), CVT8TO32(b)); - } -} - -void OSystem_MorphOS::hideOverlay() -{ - copyRectToScreen((byte *) OvlSavedBuffer, ScummBufferWidth, 0, 0, ScummBufferWidth, ScummBufferHeight); -} - -void OSystem_MorphOS::clearOverlay() -{ - AUTO_LOCK - - UBYTE *src = (UBYTE *) ScummBuffer; - UBYTE *dest = (UBYTE *) OvlBitMap; - copyRectToScreen((byte *) OvlSavedBuffer, ScummBufferWidth, 0, 0, ScummBufferWidth, ScummBufferHeight); - for (int y = 0; y < ScummBufferHeight; y++) - for (int x = 0; x < ScummBufferWidth; x++) - { - *dest++ = ScummColors[*src] >> 16; - *dest++ = (ScummColors[*src] >> 8) & 0xff; - *dest++ = ScummColors[*src++] & 0xff; - } -} - -void OSystem_MorphOS::grabOverlay(int16 *buf, int pitch) -{ - int h = ScummBufferHeight; - int x; - UBYTE *src = (UBYTE *) OvlBitMap; - - do - { - for (x = 0; x < pitch; x++) - { - *buf++ = (src[0]*31/255 << 11) | (src[1]*63/255 << 5) | src[2]*31/255; - src += 3; - } - src += (ScummBufferWidth-pitch)*3; - } while (--h); -} - -void OSystem_MorphOS::copyRectToOverlay(const int16 *ovl, int pitch, int x, int y, int w, int h) -{ - int x1, y1; - UBYTE *dest; - UBYTE *bmap, *bmap_dest; - LONG last_col[2] = { -1, -1 }; - LONG last_pen[2] = { -1, -1 }; - - if (w > pitch) w = pitch; - bmap = (UBYTE*) AllocVec(w*h, MEMF_ANY); - if (bmap) - { - bmap_dest = bmap; - dest = ((UBYTE *) OvlBitMap)+y*ScummBufferWidth*3+x*3; - for (y1 = 0; y1 < h; y1++) - { - for (x1 = 0; x1 < w; x1++) - { - uint8 r, g, b; - int16 col; - - col = *ovl++; - colorToRGB(col, r, g, b); - *dest++ = r; - *dest++ = g; - *dest++ = b; - if (col == last_col[0]) - *bmap_dest++ = last_pen[0]; - else if (col == last_col[1]) - *bmap_dest++ = last_pen[1]; - else - { - last_col[1] = last_col[0]; - last_pen[1] = last_pen[0]; - last_col[0] = col; - last_pen[0] = FindColor(OvlCMap, CVT8TO32(r), CVT8TO32(g), CVT8TO32(b), -1); - *bmap_dest++ = last_pen[0]; - } - } - dest += (ScummBufferWidth-w)*3; - ovl += pitch-w; - } - copyRectToScreen(bmap, w, x, y, w, h); - FreeVec(bmap); - } -} - diff --git a/backends/morphos/morphos.h b/backends/morphos/morphos.h deleted file mode 100644 index 67ed8a481e..0000000000 --- a/backends/morphos/morphos.h +++ /dev/null @@ -1,232 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2002 Rüdiger Hanke (MorphOS port) - * - * 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. - * - * MorphOS-specific header file - * - * $URL$ - * $Id$ - * - */ - -#ifndef MORPHOS_MORPHOS_H -#define MORPHOS_MORPHOS_H - -#include -#include -#include -#include -#include -#include - -#include "backends/intern.h" -#include "morphos_scaler.h" - -class OSystem_MorphOS : public OSystem -{ - public: - OSystem_MorphOS(SCALERTYPE gfx_mode, bool full_screen); - virtual ~OSystem_MorphOS(); - - bool Initialise(); - - // Set colors of the palette - virtual void setPalette(const byte *colors, uint start, uint num); - - // Set the size of the video bitmap. - // Typically, 320x200 - virtual void initSize(uint w, uint h); - - // Draw a bitmap to screen. - // The screen will not be updated to reflect the new bitmap - virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); - - // Update the dirty areas of the screen - virtual void updateScreen(); - - // Either show or hide the mouse cursor - virtual bool showMouse(bool visible); - - // Set the position of the mouse cursor - virtual void set_mouse_pos(int x, int y); - - // Set the bitmap that's used when drawing the cursor. - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor); - - // Shaking is used in SCUMM. Set current shake position. - virtual void setShakePos(int shake_pos); - - // Overlay - virtual void showOverlay(); - virtual void hideOverlay(); - virtual void clearOverlay(); - virtual void grabOverlay(int16 *buf, int pitch); - virtual void copyRectToOverlay(const int16 *buf, int pitch, int x, int y, int w, int h); - virtual int16 getHeight(); - virtual int16 getWidth(); - - // Get the number of milliseconds since the program was started. - virtual uint32 getMillis(); - - // Delay for a specified amount of milliseconds - virtual void delayMillis(uint msecs); - - // Add a new callback timer - virtual void setTimerCallback(TimerProc callback, int timer); - - // Mutex handling - virtual MutexRef createMutex(); - virtual void lockMutex(MutexRef mutex); - virtual void unlockMutex(MutexRef mutex); - virtual void deleteMutex(MutexRef mutex); - - // Get the next event. - // Returns true if an event was retrieved. - virtual bool pollEvent(Event &event); - - // Moves mouse pointer to specified position - virtual void warpMouse(int x, int y); - - // Set the function to be invoked whenever samples need to be generated - virtual bool setSoundCallback(SoundProc proc, void *param); - void fill_sound (byte * stream, int len); - void clearSoundCallback(); - - virtual uint32 property(int param, Property *value); - - // Poll cdrom status - // Returns true if cd audio is playing - virtual bool pollCD(); - - // Play cdrom audio track - virtual void playCD(int track, int num_loops, int start_frame, int duration); - - // Stop cdrom audio track - virtual void stopCD(); - - // Update cdrom audio status - virtual void updateCD(); - - // Quit - virtual void quit(); - - static OSystem_MorphOS *create(SCALERTYPE gfx_scaler, bool full_screen); - - static bool OpenATimer(MsgPort **port, IORequest **req, ULONG unit, bool required = true); - - private: - typedef enum { CSDSPTYPE_WINDOWED, CSDSPTYPE_FULLSCREEN, CSDSPTYPE_TOGGLE, CSDSPTYPE_KEEP } CS_DSPTYPE; - - static const int MAX_MOUSE_W = 80; - static const int MAX_MOUSE_H = 80; - - void CreateScreen(CS_DSPTYPE dspType); - void SwitchScalerTo(SCALERTYPE newScaler); - bool AddUpdateRect(WORD x, WORD y, WORD w, WORD h); - - void DrawMouse(); - void UndrawMouse(); - - /* Display-related attributes */ - Screen *ScummScreen; - Window *ScummWindow; - char ScummWndTitle[125]; - APTR ScummBuffer; - LONG ScummBufferWidth; - LONG ScummBufferHeight; - ScreenBuffer *ScummScreenBuffer[2]; - BitMap *ScummRenderTo; - ULONG ScummPaintBuffer; - int ScummScrWidth; - int ScummScrHeight; - int ScummDepth; - bool Scumm16ColFmt16; - UWORD *ScummNoCursor; - ULONG ScummColors[256]; - USHORT ScummColors16[256]; - WORD ScummWinX; - WORD ScummWinY; - bool ScummDefaultMouse; - bool ScummOrigMouse; - int ScummShakePos; - bool FullScreenMode; - bool ScreenChanged; - UWORD **BlockColors; - bool *DirtyBlocks; - Region *UpdateRegion; - Region *NewUpdateRegion; - ULONG UpdateRects; - SignalSemaphore CritSec; - - /* Overlay-related attributes */ - APTR OvlBitMap; - APTR OvlSavedBuffer; - ColorMap *OvlCMap; - - /* Sound-related attributes */ - Process *ScummSoundThread; - SoundProc SoundProc; - void *SoundParam; - MsgPort *ThreadPort; - Message MusicStartup; - Message SoundStartup; - - /* CD-ROM related attributes */ - CDRIVEPTR CDrive; - ULONG CDDATrackOffset; - - /* Scaling-related attributes */ - SCALERTYPE ScummScaler; - int ScummScale; - MorphOSScaler *Scaler; - - /* Mouse cursor-related attributes */ - bool MouseVisible, MouseDrawn; - int MouseX, MouseY; - int MouseWidth, MouseHeight; - int MouseOldX, MouseOldY; - int MouseOldWidth, MouseOldHeight; - int MouseHotspotX, MouseHotspotY; - byte *MouseImage, MouseBackup[MAX_MOUSE_W*MAX_MOUSE_H]; - byte MouseKeycolor; - MsgPort* InputMsgPort; - IOStdReq*InputIORequest; - - /* Timer-related attributes */ - MsgPort *TimerMsgPort; - timerequest *TimerIORequest; - - /* Game-related attributes */ - int GameID; -}; - -class AutoLock -{ - public: - AutoLock(SignalSemaphore* s) : sem(s) { ObtainSemaphore(sem); } - ~AutoLock() { ReleaseSemaphore(sem); } - - private: - SignalSemaphore* sem; -}; - -#define AUTO_LOCK AutoLock cs(&CritSec); - - -extern OSystem_MorphOS *TheSystem; - -#endif - diff --git a/backends/morphos/morphos_scaler.cpp b/backends/morphos/morphos_scaler.cpp deleted file mode 100644 index 46d4452c0b..0000000000 --- a/backends/morphos/morphos_scaler.cpp +++ /dev/null @@ -1,848 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2002-2006 The ScummVM Team - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "base/engine.h" - -#include -#include - -#include - -#include "morphos.h" -#include "morphos_scaler.h" - -#define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D)) -#define INTERPOLATE(A, B) (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask)) -#define Q_INTERPOLATE(A, B, C, D) ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2) + ((((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2) & qlowpixelMask) -#define SWAP_WORD(word) word = ((word & 0xff) << 8) | (word >> 8) -#define SWAP_LONG(lng) lng = ((lng & 0xff) << 24) | ((lng & 0xff00) << 8) | ((lng & 0xff0000) >> 8) | (lng >> 24) - -MorphOSScaler::GfxScaler MorphOSScaler::ScummScalers[11] - = { { "none", "normal", ST_NONE }, - { "Point", "2x", ST_POINT }, - { "AdvMame2x", "advmame2x", ST_ADVMAME2X }, - { "SuperEagle", "supereagle", ST_SUPEREAGLE }, - { "Super2xSaI", "super2xsai", ST_SUPER2XSAI }, - { NULL, NULL, ST_INVALID }, - { NULL, NULL, ST_INVALID }, - { NULL, NULL, ST_INVALID }, - { NULL, NULL, ST_INVALID }, - { NULL, NULL, ST_INVALID }, - // This is the end marker ... do not assign a scaler to it! - { NULL, NULL, ST_INVALID } - }; - -MorphOSScaler::MorphOSScaler(APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap) -{ - dest = NULL; - handle = NULL; - - Buffer = buffer; - BufferWidth = width; - BufferHeight = height; - - ScummColors = col_table; - ScummColors16 = col_table16; - - /* Initialize scaling stuff */ - int minr, ming, minb; - ULONG depth = GetCyberMapAttr(bmap, CYBRMATTR_DEPTH); - - if (depth > 16) - { - minr = 1 << 16; - ming = 1 << 8; - minb = 1; - } - else - { - minr = 1 << ((depth == 15) ? 10 : 11); - ming = 1 << 5; - minb = 1; - } - - int pixfmt = GetCyberMapAttr(bmap, CYBRMATTR_PIXFMT); - - ScummPCMode = false; - if (pixfmt == PIXFMT_RGB15PC || pixfmt == PIXFMT_BGR15PC || - pixfmt == PIXFMT_RGB16PC || pixfmt == PIXFMT_BGR16PC || - pixfmt == PIXFMT_BGRA32) - ScummPCMode = true; - - colorMask = (MakeColor(pixfmt, 255, 0, 0) - minr) | (MakeColor(pixfmt, 0, 255, 0) - ming) | (MakeColor(pixfmt, 0, 0, 255) - minb); - lowPixelMask = minr | ming | minb; - qcolorMask = (MakeColor(pixfmt, 255, 0, 0) - 3*minr) | (MakeColor(pixfmt, 0, 255, 0) - 3*ming) | (MakeColor(pixfmt, 0, 0, 255) - 3*minb); - qlowpixelMask = (minr * 3) | (ming * 3) | (minb * 3); - redblueMask = MakeColor(pixfmt, 255, 0, 255); - greenMask = MakeColor(pixfmt, 0, 255, 0); - - PixelsPerMask = (depth <= 16) ? 2 : 1; - - if (PixelsPerMask == 2) - { - colorMask |= (colorMask << 16); - qcolorMask |= (qcolorMask << 16); - lowPixelMask |= (lowPixelMask << 16); - qlowpixelMask |= (qlowpixelMask << 16); - } -} - -MorphOSScaler::~MorphOSScaler() -{ - Finish(); -} - -MorphOSScaler *MorphOSScaler::Create(SCALERTYPE scaler_type, APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap) -{ - MorphOSScaler *new_scaler = NULL; - - switch (scaler_type) - { - case ST_POINT: - new_scaler = new PointScaler(buffer, width, height, col_table, col_table16, bmap); - break; - - case ST_ADVMAME2X: - new_scaler = new AdvMame2xScaler(buffer, width, height, col_table, col_table16, bmap); - break; - - case ST_SUPEREAGLE: - new_scaler = new SuperEagleScaler(buffer, width, height, col_table, col_table16, bmap); - break; - - case ST_SUPER2XSAI: - new_scaler = new Super2xSaIScaler(buffer, width, height, col_table, col_table16, bmap); - break; - - default: - warning("Invalid scaler requested - falling back to Super2xSaI"); - new_scaler = new Super2xSaIScaler(buffer, width, height, col_table, col_table16, bmap); - break; - } - - return new_scaler; -} - -bool MorphOSScaler::Prepare(BitMap *render_bmap) -{ - handle = LockBitMapTags(render_bmap, LBMI_BYTESPERPIX, &dest_bpp, - LBMI_BYTESPERROW, &dest_pitch, - LBMI_BASEADDRESS, &dest, - LBMI_PIXFMT, &dest_pixfmt, - TAG_DONE); - - return handle != NULL; -} - -void MorphOSScaler::Finish() -{ - if (handle) - { - UnLockBitMap(handle); - handle = NULL; - } -} - -uint32 MorphOSScaler::MakeColor(int pixfmt, int r, int g, int b) -{ - uint32 col = 0; - - switch (pixfmt) - { - case PIXFMT_RGB15: - case PIXFMT_RGB15PC: - col = (((r*31)/255) << 10) | (((g*31)/255) << 5) | ((b*31)/255); - break; - - case PIXFMT_BGR15: - case PIXFMT_BGR15PC: - col = (((b*31)/255) << 10) | (((g*31)/255) << 5) | ((r*31)/255); - break; - - case PIXFMT_RGB16: - case PIXFMT_RGB16PC: - col = (((r*31)/255) << 11) | (((g*63)/255) << 5) | ((b*31)/255); - break; - - case PIXFMT_BGR16: - case PIXFMT_BGR16PC: - col = (((b*31)/255) << 11) | (((g*63)/255) << 5) | ((r*31)/255); - break; - - case PIXFMT_ARGB32: - case PIXFMT_BGRA32: - col = (r << 16) | (g << 8) | b; - break; - - case PIXFMT_RGBA32: - col = (r << 24) | (g << 16) | (b << 8); - break; - - case PIXFMT_RGB24: - case PIXFMT_BGR24: - error("The scaling engines do not support 24 bit modes at the moment"); - break; - - default: - error("Unsupported pixel format: %d. Please contact author at tomjoad@muenster.de", pixfmt); - } - - return col; -} - -void Super2xSaIScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) -{ - unsigned int x, y; - unsigned long color[16]; - byte *src; - - if (!handle) - return; - - src = ((byte *)Buffer)+src_y*BufferWidth+src_x; - - /* Point to the first 3 lines. */ - src_line[0] = src; - src_line[1] = src; - src_line[2] = src + BufferWidth; - src_line[3] = src + BufferWidth * 2; - - dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; - dst_line[1] = dst_line[0]+dest_pitch; - - if (PixelsPerMask == 2) - { - byte *sbp; - sbp = src_line[0]; - color[0] = ScummColors16[*sbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; - color[4] = color[0]; color[5] = color[0]; color[6] = ScummColors16[*(sbp+1)]; color[7] = ScummColors16[*(sbp+2)]; - sbp = src_line[2]; - color[8] = ScummColors16[*sbp]; color[9] = color[8]; color[10] = ScummColors16[*(sbp+1)]; color[11] = ScummColors16[*(sbp+2)]; - sbp = src_line[3]; - color[12] = ScummColors16[*sbp]; color[13] = color[12]; color[14] = ScummColors16[*(sbp+1)]; color[15] = ScummColors16[*(sbp+2)]; - } - else - { - byte *lbp; - lbp = src_line[0]; - color[0] = ScummColors[*lbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; - color[4] = color[0]; color[5] = color[0]; color[6] = ScummColors[*(lbp+1)]; color[7] = ScummColors[*(lbp+2)]; - lbp = src_line[2]; - color[8] = ScummColors[*lbp]; color[9] = color[8]; color[10] = ScummColors[*(lbp+1)]; color[11] = ScummColors[*(lbp+2)]; - lbp = src_line[3]; - color[12] = ScummColors[*lbp]; color[13] = color[12]; color[14] = ScummColors[*(lbp+1)]; color[15] = ScummColors[*(lbp+2)]; - } - - for (y = 0; y < height; y++) - { - for (x = 0; x < width; x++) - { - unsigned long product1a, product1b, product2a, product2b; - -//--------------------------------------- B0 B1 B2 B3 0 1 2 3 -// 4 5* 6 S2 -> 4 5* 6 7 -// 1 2 3 S1 8 9 10 11 -// A0 A1 A2 A3 12 13 14 15 -//-------------------------------------- - if (color[9] == color[6] && color[5] != color[10]) - { - product2b = color[9]; - product1b = product2b; - } - else if (color[5] == color[10] && color[9] != color[6]) - { - product2b = color[5]; - product1b = product2b; - } - else if (color[5] == color[10] && color[9] == color[6]) - { - int r = 0; - - r += GET_RESULT(color[6], color[5], color[8], color[13]); - r += GET_RESULT(color[6], color[5], color[4], color[1]); - r += GET_RESULT(color[6], color[5], color[14], color[11]); - r += GET_RESULT(color[6], color[5], color[2], color[7]); - - if (r > 0) - product1b = color[6]; - else if (r < 0) - product1b = color[5]; - else - product1b = INTERPOLATE(color[5], color[6]); - - product2b = product1b; - - } - else - { - if (color[6] == color[10] && color[10] == color[13] && color[9] != color[14] && color[10] != color[12]) - product2b = Q_INTERPOLATE(color[10], color[10], color[10], color[9]); - else if (color[5] == color[9] && color[9] == color[14] && color[13] != color[10] && color[9] != color[15]) - product2b = Q_INTERPOLATE(color[9], color[9], color[9], color[10]); - else - product2b = INTERPOLATE(color[9], color[10]); - - if (color[6] == color[10] && color[6] == color[1] && color[5] != color[2] && color[6] != color[0]) - product1b = Q_INTERPOLATE(color[6], color[6], color[6], color[5]); - else if (color[5] == color[9] && color[5] == color[2] && color[1] != color[6] && color[5] != color[3]) - product1b = Q_INTERPOLATE(color[6], color[5], color[5], color[5]); - else - product1b = INTERPOLATE(color[5], color[6]); - } - - if (color[5] == color[10] && color[9] != color[6] && color[4] == color[5] && color[5] != color[14]) - product2a = INTERPOLATE(color[9], color[5]); - else if (color[5] == color[8] && color[6] == color[5] && color[4] != color[9] && color[5] != color[12]) - product2a = INTERPOLATE(color[9], color[5]); - else - product2a = color[9]; - - if (color[9] == color[6] && color[5] != color[10] && color[8] == color[9] && color[9] != color[2]) - product1a = INTERPOLATE(color[9], color[5]); - else if (color[4] == color[9] && color[10] == color[9] && color[8] != color[5] && color[9] != color[0]) - product1a = INTERPOLATE(color[9], color[5]); - else - product1a = color[5]; - - if (PixelsPerMask == 2) - { - if (ScummPCMode) - { - SWAP_WORD(product1a); - SWAP_WORD(product1b); - SWAP_WORD(product2a); - SWAP_WORD(product2b); - } - *((unsigned long *) (&dst_line[0][x * 4])) = (product1a << 16) | product1b; - *((unsigned long *) (&dst_line[1][x * 4])) = (product2a << 16) | product2b; - } - else - { - if (ScummPCMode) - { - SWAP_LONG(product1a); - SWAP_LONG(product1b); - SWAP_LONG(product2a); - SWAP_LONG(product2b); - } - *((unsigned long *) (&dst_line[0][x * 8])) = product1a; - *((unsigned long *) (&dst_line[0][x * 8 + 4])) = product1b; - *((unsigned long *) (&dst_line[1][x * 8])) = product2a; - *((unsigned long *) (&dst_line[1][x * 8 + 4])) = product2b; - } - - /* Move color matrix forward */ - color[0] = color[1]; color[4] = color[5]; color[8] = color[9]; color[12] = color[13]; - color[1] = color[2]; color[5] = color[6]; color[9] = color[10]; color[13] = color[14]; - color[2] = color[3]; color[6] = color[7]; color[10] = color[11]; color[14] = color[15]; - - if (src_x+x < BufferWidth-3) - { - x += 3; - if (PixelsPerMask == 2) - { - color[3] = ScummColors16[*(src_line[0] + x) ]; - color[7] = ScummColors16[*(src_line[1] + x) ]; - color[11] = ScummColors16[*(src_line[2] + x) ]; - color[15] = ScummColors16[*(src_line[3] + x) ]; - } - else - { - color[3] = ScummColors[*(src_line[0] + x)]; - color[7] = ScummColors[*(src_line[1] + x)]; - color[11] = ScummColors[*(src_line[2] + x)]; - color[15] = ScummColors[*(src_line[3] + x)]; - } - x -= 3; - } - } - - /* We're done with one line, so we shift the source lines up */ - src_line[0] = src_line[1]; - src_line[1] = src_line[2]; - src_line[2] = src_line[3]; - - /* Read next line */ - if (src_y + y + 3 >= BufferHeight) - src_line[3] = src_line[2]; - else - src_line[3] = src_line[2] + BufferWidth; - - /* Then shift the color matrix up */ - if (PixelsPerMask == 2) - { - byte *sbp; - sbp = src_line[0]; - color[0] = ScummColors16[*sbp]; color[1] = color[0]; color[2] = ScummColors16[ *(sbp + 1) ]; color[3] = ScummColors16[*(sbp + 2)]; - sbp = src_line[1]; - color[4] = ScummColors16[*sbp]; color[5] = color[4]; color[6] = ScummColors16[ *(sbp + 1) ]; color[7] = ScummColors16[*(sbp + 2)]; - sbp = src_line[2]; - color[8] = ScummColors16[*sbp]; color[9] = color[8]; color[10] = ScummColors16[ *(sbp + 1) ]; color[11] = ScummColors16[*(sbp + 2)]; - sbp = src_line[3]; - color[12] = ScummColors16[*sbp]; color[13] = color[12]; color[14] = ScummColors16[ *(sbp + 1) ]; color[15] = ScummColors16[*(sbp + 2)]; - - if (src_x + x > 0) - { - color[0] = ScummColors16[src_line[0][-1]]; - color[4] = ScummColors16[src_line[1][-1]]; - color[8] = ScummColors16[src_line[2][-1]]; - color[12] = ScummColors16[src_line[3][-1]]; - } - } - else - { - byte *lbp; - lbp = src_line[0]; - color[0] = ScummColors[*lbp]; color[1] = color[0]; color[2] = ScummColors[ *(lbp + 1) ]; color[3] = ScummColors[*(lbp+2)]; - lbp = src_line[1]; - color[4] = ScummColors[*lbp]; color[5] = color[4]; color[6] = ScummColors[ *(lbp + 1) ]; color[7] = ScummColors[*(lbp+2)]; - lbp = src_line[2]; - color[8] = ScummColors[*lbp]; color[9] = color[8]; color[10] = ScummColors[ *(lbp + 1) ]; color[11] = ScummColors[*(lbp+2)]; - lbp = src_line[3]; - color[12] = ScummColors[*lbp]; color[13] = color[12]; color[14] = ScummColors[ *(lbp + 1) ]; color[15] = ScummColors[*(lbp+2)]; - } - - if (src_y + y < BufferHeight - 1) - { - dst_line[0] = dst_line[1]+dest_pitch; - dst_line[1] = dst_line[0]+dest_pitch; - } - } -} - -void SuperEagleScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) -{ - unsigned int x, y; - unsigned long color[12]; - byte *src; - - if (!handle) - return; - - src = (byte *)Buffer+src_y*BufferWidth+src_x; - - /* Point to the first 3 lines. */ - src_line[0] = src; - src_line[1] = src; - src_line[2] = src + BufferWidth; - src_line[3] = src + BufferWidth * 2; - - dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; - dst_line[1] = dst_line[0]+dest_pitch; - - x = 0, y = 0; - - if (PixelsPerMask == 2) - { - byte *sbp; - sbp = src_line[0]; - color[0] = ScummColors16[*sbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; - color[4] = ScummColors16[*(sbp+1)]; color[5] = ScummColors16[*(sbp+2)]; - sbp = src_line[2]; - color[6] = ScummColors16[*sbp]; color[7] = color[6]; color[8] = ScummColors16[*(sbp+1)]; color[9] = ScummColors16[*(sbp+2)]; - sbp = src_line[3]; - color[10] = ScummColors16[*sbp]; color[11] = ScummColors16[*(sbp+1)]; - } - else - { - byte *lbp; - lbp = src_line[0]; - color[0] = ScummColors[*lbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; - color[4] = ScummColors[*(lbp+1)]; color[5] = ScummColors[*(lbp+2)]; - lbp = src_line[2]; - color[6] = ScummColors[*lbp]; color[7] = color[6]; color[8] = ScummColors[*(lbp+1)]; color[9] = ScummColors[*(lbp+2)]; - lbp = src_line[3]; - color[10] = ScummColors[*lbp]; color[11] = ScummColors[*(lbp+1)]; - } - - for (y = 0; y < height; y++) - { - /* Todo: x = width - 2, x = width - 1 */ - - for (x = 0; x < width; x++) - { - unsigned long product1a, product1b, product2a, product2b; - -//--------------------------------------- B1 B2 0 1 -// 4 5 6 S2 -> 2 3 4 5 -// 1 2 3 S1 6 7 8 9 -// A1 A2 10 11 - - if (color[7] == color[4] && color[3] != color[8]) - { - product1b = product2a = color[7]; - - if ((color[6] == color[7]) || (color[4] == color[1])) - product1a = INTERPOLATE(color[7], INTERPOLATE(color[7], color[3])); - else - product1a = INTERPOLATE(color[3], color[4]); - - if ((color[4] == color[5]) || (color[7] == color[10])) - product2b = INTERPOLATE(color[7], INTERPOLATE(color[7], color[8])); - else - product2b = INTERPOLATE(color[7], color[8]); - } - else if (color[3] == color[8] && color[7] != color[4]) - { - product2b = product1a = color[3]; - - if ((color[0] == color[3]) || (color[5] == color[9])) - product1b = INTERPOLATE(color[3], INTERPOLATE(color[3], color[4])); - else - product1b = INTERPOLATE(color[3], color[1]); - - if ((color[8] == color[11]) || (color[2] == color[3])) - product2a = INTERPOLATE(color[3], INTERPOLATE(color[3], color[2])); - else - product2a = INTERPOLATE(color[7], color[8]); - - } - else if (color[3] == color[8] && color[7] == color[4]) - { - register int r = 0; - - r += GET_RESULT(color[4], color[3], color[6], color[10]); - r += GET_RESULT(color[4], color[3], color[2], color[0]); - r += GET_RESULT(color[4], color[3], color[11], color[9]); - r += GET_RESULT(color[4], color[3], color[1], color[5]); - - if (r > 0) - { - product1b = product2a = color[7]; - product1a = product2b = INTERPOLATE(color[3], color[4]); - } - else if (r < 0) - { - product2b = product1a = color[3]; - product1b = product2a = INTERPOLATE(color[3], color[4]); - } - else - { - product2b = product1a = color[3]; - product1b = product2a = color[7]; - } - } - else - { - product2b = product1a = INTERPOLATE(color[7], color[4]); - product2b = Q_INTERPOLATE(color[8], color[8], color[8], product2b); - product1a = Q_INTERPOLATE(color[3], color[3], color[3], product1a); - - product2a = product1b = INTERPOLATE(color[3], color[8]); - product2a = Q_INTERPOLATE(color[7], color[7], color[7], product2a); - product1b = Q_INTERPOLATE(color[4], color[4], color[4], product1b); - } - - if (PixelsPerMask == 2) - { - if (ScummPCMode) - { - SWAP_WORD(product1a); - SWAP_WORD(product1b); - SWAP_WORD(product2a); - SWAP_WORD(product2b); - } - *((unsigned long *) (&dst_line[0][x * 4])) = (product1a << 16) | product1b; - *((unsigned long *) (&dst_line[1][x * 4])) = (product2a << 16) | product2b; - } - else - { - if (ScummPCMode) - { - SWAP_LONG(product1a); - SWAP_LONG(product1b); - SWAP_LONG(product2a); - SWAP_LONG(product2b); - } - *((unsigned long *) (&dst_line[0][x * 8])) = product1a; - *((unsigned long *) (&dst_line[0][x * 8 + 4])) = product1b; - *((unsigned long *) (&dst_line[1][x * 8])) = product2a; - *((unsigned long *) (&dst_line[1][x * 8 + 4])) = product2b; - } - - /* Move color matrix forward */ - color[0] = color[1]; - color[2] = color[3]; color[3] = color[4]; color[4] = color[5]; - color[6] = color[7]; color[7] = color[8]; color[8] = color[9]; - color[10] = color[11]; - - if (src_x+x < BufferWidth - 2) - { - x += 2; - if (PixelsPerMask == 2) - { - color[1] = ScummColors16[ *(src_line[0] + x) ]; - if (src_x+x < BufferWidth-1) - { - color[5] = ScummColors16[*(src_line[1]+x+1)]; - color[9] = ScummColors16[*(src_line[2]+x+1)]; - } - color[11] = ScummColors16[*(src_line[3]+x)]; - } - else - { - color[1] = ScummColors[*(src_line[0]+x)]; - if (src_x+x < BufferWidth-1) - { - color[5] = ScummColors[*(src_line[1]+x+1)]; - color[9] = ScummColors[ *(src_line[2]+x+1)]; - } - color[11] = ScummColors[*(src_line[3]+x)]; - } - x -= 2; - } - } - - /* We're done with one line, so we shift the source lines up */ - src_line[0] = src_line[1]; - src_line[1] = src_line[2]; - src_line[2] = src_line[3]; - - /* Read next line */ - if (src_y+y+3 >= BufferHeight) - src_line[3] = src_line[2]; - else - src_line[3] = src_line[2] + BufferWidth; - - /* Then shift the color matrix up */ - if (PixelsPerMask == 2) - { - byte *sbp; - sbp = src_line[0]; - color[0] = ScummColors16[*sbp]; color[1] = ScummColors16[*(sbp+1)]; - sbp = src_line[1]; - color[2] = ScummColors16[*sbp]; color[3] = color[2]; color[4] = ScummColors16[*(sbp+1)]; color[5] = ScummColors16[*(sbp+2)]; - sbp = src_line[2]; - color[6] = ScummColors16[*sbp]; color[7] = color[6]; color[8] = ScummColors16[*(sbp+1)]; color[9] = ScummColors16[*(sbp+2)]; - sbp = src_line[3]; - color[10] = ScummColors16[*sbp]; color[11] = ScummColors16[*(sbp+1)]; - } - else - { - byte *lbp; - lbp = src_line[0]; - color[0] = ScummColors[*lbp]; color[1] = ScummColors[*(lbp+1)]; - lbp = src_line[1]; - color[2] = ScummColors[*lbp]; color[3] = color[2]; color[4] = ScummColors[*(lbp+1)]; color[5] = ScummColors[*(lbp+2)]; - lbp = src_line[2]; - color[6] = ScummColors[*lbp]; color[7] = color[6]; color[8] = ScummColors[*(lbp+1)]; color[9] = ScummColors[*(lbp+2)]; - lbp = src_line[3]; - color[10] = ScummColors[*lbp]; color[11] = ScummColors[*(lbp+1)]; - } - - - if (src_y + y < BufferHeight - 1) - { - dst_line[0] = dst_line[1]+dest_pitch; - dst_line[1] = dst_line[0]+dest_pitch; - } - } -} - -void AdvMame2xScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) -{ - if (!handle) - return; - - byte *src = (byte *)Buffer+src_y*BufferWidth+src_x; - - src_line[0] = src; - src_line[1] = src; - src_line[2] = src + BufferWidth; - - dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; - dst_line[1] = dst_line[0]+dest_pitch; - - for (uint32 y = 0; y < height; y++) - { - for (uint32 x = 0; x < width; x++) - { - uint32 B, D, E, F, H; - - if (PixelsPerMask == 2) - { - // short A = *(src + i - nextlineSrc - 1); - B = ScummColors16[src_line[0][x]]; - // short C = *(src + i - nextlineSrc + 1); - D = ScummColors16[src_line[1][x-1]]; - E = ScummColors16[src_line[1][x]]; - F = ScummColors16[src_line[1][x+1]]; - // short G = *(src + i + nextlineSrc - 1); - H = ScummColors16[src_line[2][x]]; - // short I = *(src + i + nextlineSrc + 1); - } - else - { - // short A = *(src + i - nextlineSrc - 1); - B = ScummColors[src_line[0][x]]; - // short C = *(src + i - nextlineSrc + 1); - D = ScummColors[src_line[1][x-1]]; - E = ScummColors[src_line[1][x]]; - F = ScummColors[src_line[1][x+1]]; - // short G = *(src + i + nextlineSrc - 1); - H = ScummColors[src_line[2][x]]; - // short I = *(src + i + nextlineSrc + 1); - } - - - if (PixelsPerMask == 2) - { - if (ScummPCMode) - { - SWAP_WORD(B); - SWAP_WORD(D); - SWAP_WORD(E); - SWAP_WORD(F); - SWAP_WORD(H); - } - *((unsigned long *) (&dst_line[0][x * 4])) = ((D == B && B != F && D != H ? D : E) << 16) | (B == F && B != D && F != H ? F : E); - *((unsigned long *) (&dst_line[1][x * 4])) = ((D == H && D != B && H != F ? D : E) << 16) | (H == F && D != H && B != F ? F : E); - } - else - { - if (ScummPCMode) - { - SWAP_LONG(B); - SWAP_LONG(D); - SWAP_LONG(E); - SWAP_LONG(F); - SWAP_LONG(H); - } - *((unsigned long *) (&dst_line[0][x * 8])) = D == B && B != F && D != H ? D : E; - *((unsigned long *) (&dst_line[0][x * 8 + 4])) = B == F && B != D && F != H ? F : E; - *((unsigned long *) (&dst_line[1][x * 8])) = D == H && D != B && H != F ? D : E; - *((unsigned long *) (&dst_line[1][x * 8 + 4])) = H == F && D != H && B != F ? F : E; - } - } - - src_line[0] = src_line[1]; - src_line[1] = src_line[2]; - if (src_y+y+2 >= BufferHeight) - src_line[2] = src_line[1]; - else - src_line[2] = src_line[1] + BufferWidth; - - if (src_y+y < BufferHeight-1) - { - dst_line[0] = dst_line[1]+dest_pitch; - dst_line[1] = dst_line[0]+dest_pitch; - } - } -} - -void PointScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) -{ - byte *src; - uint32 color; - uint32 r, g, b; - uint32 x, y; - - if (!handle) - return; - - src = (byte *)Buffer+src_y*BufferWidth+src_x; - - dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; - dst_line[1] = dst_line[0]+dest_pitch; - - for (y = 0; y < height; y++) - { - for (x = 0; x < width; x++) - { - r = (ScummColors[*(src+x)] >> 16) & 0xff; - g = (ScummColors[*(src+x)] >> 8) & 0xff; - b = ScummColors[*(src+x)] & 0xff; - - color = MakeColor(dest_pixfmt, r, g, b); - if (PixelsPerMask == 2) - { - if (ScummPCMode) - SWAP_WORD(color); - - *((unsigned long *) (&dst_line[0][x * 4])) = (color << 16) | color; - *((unsigned long *) (&dst_line[1][x * 4])) = (color << 16) | color; - } - else - { - if (ScummPCMode) - SWAP_LONG(color); - - *((unsigned long *) (&dst_line[0][x * 8])) = color; - *((unsigned long *) (&dst_line[0][x * 8 + 4])) = color; - *((unsigned long *) (&dst_line[1][x * 8])) = color; - *((unsigned long *) (&dst_line[1][x * 8 + 4])) = color; - } - } - - src += BufferWidth; - - if (src_y+y < BufferHeight-1) - { - dst_line[0] = dst_line[1]+dest_pitch; - dst_line[1] = dst_line[0]+dest_pitch; - } - } -} - -SCALERTYPE MorphOSScaler::FindByName(const char *ScalerName) -{ - int scaler = 0; - - while (ScummScalers[scaler].gs_Name) - { - if (!stricmp(ScalerName, ScummScalers[scaler].gs_Name)) - return ScummScalers[scaler].gs_Type; - scaler++; - } - - if (ScummScalers[scaler].gs_Name == NULL) - { - puts("Invalid scaler name. Please use one of the following:"); - for (scaler = 0; ScummScalers[scaler].gs_Name != NULL; scaler++) - printf(" %s\n", ScummScalers[scaler].gs_Name); - } - - return ST_INVALID; -} - -SCALERTYPE MorphOSScaler::FindByIndex(int index) -{ - if (index >= 0 && index < 10 && ScummScalers[index].gs_Name) - return ScummScalers[index].gs_Type; - - return ST_INVALID; -} - -const char *MorphOSScaler::GetParamName(SCALERTYPE type) -{ - int scaler = 0; - - while (ScummScalers[scaler].gs_Name) - { - if (ScummScalers[scaler].gs_Type == type) - return ScummScalers[scaler].gs_ParamName; - scaler++; - } - - return NULL; -} - diff --git a/backends/morphos/morphos_scaler.h b/backends/morphos/morphos_scaler.h deleted file mode 100644 index d794e361a6..0000000000 --- a/backends/morphos/morphos_scaler.h +++ /dev/null @@ -1,94 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2002-2006 The ScummVM Team - * - * 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 MORPHOS_MORPHOSSCALER_H -#define MORPHOS_MORPHOSSCALER_H - -#include - -typedef enum { ST_INVALID = 0, ST_NONE, ST_POINT, ST_ADVMAME2X, ST_SUPEREAGLE, ST_SUPER2XSAI } SCALERTYPE; - -class MorphOSScaler -{ - public: - MorphOSScaler(APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap); - virtual ~MorphOSScaler(); - - bool Prepare(BitMap *render_bmap); - void Finish(); - - virtual void Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) = 0; - - static MorphOSScaler *Create(SCALERTYPE st, APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap); - - static SCALERTYPE FindByName(const char *ScalerName); - static SCALERTYPE FindByIndex(int index); - static const char *GetParamName(SCALERTYPE type); - - protected: - struct GfxScaler - { - STRPTR gs_Name; - STRPTR gs_ParamName; - SCALERTYPE gs_Type; - }; - - static GfxScaler ScummScalers[11]; - - static uint32 MakeColor(int pixfmt, int r, int g, int b); - - byte *dest; - uint32 dest_bpp; - uint32 dest_pitch; - uint32 dest_pixfmt; - APTR handle; - - uint32 colorMask; - uint32 lowPixelMask; - uint32 qcolorMask; - uint32 qlowpixelMask; - uint32 redblueMask; - uint32 greenMask; - int PixelsPerMask; - byte *src_line[4]; - byte *dst_line[2]; - bool ScummPCMode; - - APTR Buffer; - ULONG BufferWidth; - ULONG BufferHeight; - ULONG *ScummColors; - USHORT *ScummColors16; -}; - -#define DECLARE_SCALER(scaler_name) class scaler_name ## Scaler : public MorphOSScaler \ - { public: scaler_name ## Scaler(APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap) : MorphOSScaler(buffer, width, height, col_table, col_table16, bmap) {} \ - void Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height); \ - }; - - -DECLARE_SCALER(Point) -DECLARE_SCALER(AdvMame2x) -DECLARE_SCALER(SuperEagle) -DECLARE_SCALER(Super2xSaI) - -#endif - diff --git a/backends/morphos/morphos_sound.cpp b/backends/morphos/morphos_sound.cpp deleted file mode 100644 index c5c2f3b7ad..0000000000 --- a/backends/morphos/morphos_sound.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2002 Rüdiger Hanke - * - * 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. - * - * MorphOS sound support - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "base/engine.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "morphos.h" -#include "morphos_sound.h" - -#define AHI_BUF_SIZE (8*1024) - -SignalSemaphore ScummMusicThreadRunning; -SignalSemaphore ScummSoundThreadRunning; - -static MsgPort *ahiPort = NULL; -static AHIRequest *ahiReq[2] = { NULL, NULL }; -static UWORD ahiCurBuf = 0; -static bool ahiReqSent[2] = { false, false }; -static BYTE ahiDevice = -1; - UBYTE ahiUnit = AHI_DEFAULT_UNIT; -static char *ahiBuf[2] = { NULL, NULL }; - -static MsgPort *ScummMidiPort = NULL; - IOMidiRequest *ScummMidiRequest = NULL; - - Device *EtudeBase = NULL; - -bool etude_available() -{ - bool avail = init_morphos_music(ScummMidiUnit, ETUDEF_DIRECT); - if (avail) - exit_morphos_music(); - return avail; -} - -bool init_morphos_music(ULONG MidiUnit, ULONG DevFlags) -{ - ScummMidiPort = CreateMsgPort(); - if (ScummMidiPort) - { - ScummMidiRequest = (IOMidiRequest *) CreateIORequest(ScummMidiPort, sizeof (IOMidiRequest)); - if (ScummMidiRequest) - { - ScummMidiRequest->emr_Version = 1; - if (OpenDevice(ETUDENAME, MidiUnit, (IORequest *) ScummMidiRequest, DevFlags)) - { - DeleteIORequest((IORequest *) ScummMidiRequest); - DeleteMsgPort(ScummMidiPort); - ScummMidiRequest = NULL; - ScummMidiPort = NULL; - } - else - EtudeBase = ScummMidiRequest->emr_Std.io_Device; - } - else - { - DeleteMsgPort(ScummMidiPort); - ScummMidiPort = NULL; - } - } - - if (!ScummMidiRequest) - return false; - - return true; -} - - -void exit_morphos_music() -{ - if (ScummMidiRequest) - { - CloseDevice((IORequest *) ScummMidiRequest); - DeleteIORequest((IORequest *) ScummMidiRequest); - DeleteMsgPort(ScummMidiPort); - ScummMidiRequest = NULL; - ScummMidiPort = NULL; - EtudeBase = NULL; - } -} - - -static bool init_morphos_sound() -{ - if (!(ahiPort = CreateMsgPort())) - return false; - - if (!(ahiReq[0] = (AHIRequest *) CreateIORequest(ahiPort, sizeof (AHIRequest)))) - { - DeleteMsgPort(ahiPort); - ahiPort = NULL; - return false; - } - - if (!(ahiReq[1] = (AHIRequest *) AllocVec(sizeof (AHIRequest), MEMF_PUBLIC))) - { - DeleteIORequest(ahiReq[0]); - DeleteMsgPort(ahiPort); - ahiReq[0] = NULL; - ahiPort = NULL; - return false; - } - - if (!(ahiBuf[0] = (char *) AllocVec(2*AHI_BUF_SIZE, MEMF_PUBLIC))) - { - FreeVec(ahiReq[1]); - DeleteIORequest(ahiReq[0]); - DeleteMsgPort(ahiPort); - ahiReq[0] = NULL; - ahiReq[1] = NULL; - ahiPort = NULL; - return false; - } - ahiBuf[1] = &ahiBuf[0][AHI_BUF_SIZE]; - - ahiReq[0]->ahir_Version = 4; - if ((ahiDevice = OpenDevice(AHINAME, 0, (IORequest *) ahiReq[0], 0))) - { - FreeVec(ahiBuf[0]); - FreeVec(ahiReq[1]); - DeleteIORequest(ahiReq[0]); - DeleteMsgPort(ahiPort); - ahiBuf[0] = NULL; - ahiReq[0] = NULL; - ahiReq[1] = NULL; - ahiPort = NULL; - return false; - } - - CopyMem(ahiReq[0], ahiReq[1], sizeof (AHIRequest)); - - ahiCurBuf = 0; - ahiReqSent[0] = FALSE; - ahiReqSent[1] = FALSE; - - return true; -} - - -static void exit_morphos_sound() -{ - if (ahiReq[1]) - FreeVec(ahiReq[1]); - - if (ahiReq[0]) - { - CloseDevice((IORequest *) ahiReq[0]); - DeleteIORequest(ahiReq[0]); - } - - if (ahiBuf[0]) - FreeVec((APTR) ahiBuf[0]); - - if (ahiPort) - DeleteMsgPort(ahiPort); -} - -int morphos_sound_thread(OSystem_MorphOS *syst, ULONG SampleType) -{ - ULONG signals; - bool initialized; - - initialized = init_morphos_sound(); - if (!initialized) - { - warning("Sound could not be initialized. The game may hang at some point (press Ctrl-z then)."); - Wait(SIGBREAKF_CTRL_C); - } - else - { - for (;;) - { - while (!ahiReqSent[ahiCurBuf] || CheckIO((IORequest *) ahiReq[ahiCurBuf])) - { - AHIRequest *req = ahiReq[ahiCurBuf]; - UWORD ahiOtherBuf = !ahiCurBuf; - - if (ahiReqSent[ahiCurBuf]) - WaitIO((IORequest *) req); - - syst->fill_sound((byte *) ahiBuf[ahiCurBuf], AHI_BUF_SIZE); - - req->ahir_Std.io_Message.mn_Node.ln_Pri = 0; - req->ahir_Std.io_Command = CMD_WRITE; - req->ahir_Std.io_Data = ahiBuf[ahiCurBuf]; - req->ahir_Std.io_Length = AHI_BUF_SIZE; - req->ahir_Type = SampleType; - req->ahir_Frequency = SAMPLES_PER_SEC; - req->ahir_Position = 0x8000; - req->ahir_Volume = 0x10000; - req->ahir_Link = (ahiReqSent[ahiOtherBuf] && !CheckIO((IORequest *) ahiReq[ahiOtherBuf])) ? ahiReq[ahiOtherBuf] : NULL; - SendIO((IORequest *)req); - - ahiReqSent[ahiCurBuf] = true; - ahiCurBuf = ahiOtherBuf; - } - - signals = Wait(SIGBREAKF_CTRL_C | (1 << ahiPort->mp_SigBit)); - - if (signals & SIGBREAKF_CTRL_C) - break; - } - - if (ahiReqSent[ahiCurBuf]) - { - AbortIO((IORequest *) ahiReq[ahiCurBuf]); - WaitIO((IORequest *) ahiReq[ahiCurBuf]); - ahiReqSent[ahiCurBuf] = false; - } - - if (ahiReqSent[!ahiCurBuf]) - { - AbortIO((IORequest *) ahiReq[!ahiCurBuf]); - WaitIO((IORequest *) ahiReq[!ahiCurBuf]); - ahiReqSent[!ahiCurBuf] = false; - } - } - - exit_morphos_sound(); - - return 0; -} - diff --git a/backends/morphos/morphos_sound.h b/backends/morphos/morphos_sound.h deleted file mode 100644 index a2d211a37f..0000000000 --- a/backends/morphos/morphos_sound.h +++ /dev/null @@ -1,43 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2002 Rüdiger Hanke (MorphOS port) - * - * 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. - * - * MorphOS-specific header file - * - * $URL$ - * $Id$ - * - */ - -#ifndef MORPHOS_SOUND_H -#define MORPHOS_SOUND_H - -#include -#include - -class OSystem_MorphOS; - -int morphos_sound_thread(OSystem_MorphOS *syst, ULONG SampleType); -bool init_morphos_music(ULONG MidiUnit, ULONG DevFlags); -void exit_morphos_music(); -bool etude_available(); - -extern STRPTR ScummMusicDriver; -extern LONG ScummMidiUnit; -extern IOMidiRequest *ScummMidiRequest; - -#endif - diff --git a/backends/morphos/morphos_start.cpp b/backends/morphos/morphos_start.cpp deleted file mode 100644 index ac5c16ad85..0000000000 --- a/backends/morphos/morphos_start.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2002 Rüdiger Hanke (MorphOS port) - * - * 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. - * - * MorphOS startup handling - * - * $URL$ - * $Id$ - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "common/stdafx.h" -#include "scumm/scumm.h" -#include "base/main.h" -#include "common/scaler.h" -#include "sound/mididrv.h" -#include "morphos.h" -#include "morphos_scaler.h" -#include "morphos_sound.h" - -extern "C" WBStartup *_WBenchMsg; - -// For command line parsing -static STRPTR usageTemplate = "STORY,DATAPATH/K,WINDOW/S,SCALER/K,AMIGA/S,MIDIUNIT/K/N,MUSIC/K,MASTERVOL/K/N,MUSICVOL/K/N,SFXVOL/K/N,TEMPO/K/N,TALKSPEED/K/N,LANGUAGE/K,NOSUBTITLES=NST/S, DEBUGLEVEL=DBGLVL/K/N, DUMPSCRIPTS/S"; -typedef enum { USG_STORY = 0, USG_DATAPATH, USG_WINDOW, USG_SCALER, USG_AMIGA, USG_MIDIUNIT, USG_MUSIC, USG_MASTERVOL, USG_MUSICVOL, USG_SFXVOL, USG_TEMPO, USG_TALKSPEED, USG_LANGUAGE, USG_NOSUBTITLES, USG_DEBUGLEVEL, USG_DUMPSCRIPTS, USG_MAX } usageFields; -static LONG args[USG_MAX]; -static RDArgs *ScummArgs = NULL; - -static char*ScummStory = NULL; -static char*ScummPath = NULL; -static char*ScummLang = NULL; - STRPTR ScummMusicDriver = NULL; -MidiDriver* EtudeMidiDriver = NULL; - LONG ScummMidiUnit = 0; -static LONG ScummMasterVolume = 0; -static LONG ScummMidiVolume = 0; -static LONG ScummMidiTempo = 0; -static LONG ScummSfxVolume = 0; -static LONG ScummTalkSpeed = 0; -static LONG ScummDebugLevel = 0; -static SCALERTYPE ScummGfxScaler = ST_INVALID; - -static BPTR OrigDirLock = 0; - -Library *CDDABase = NULL; -Library *TimerBase = NULL; - -OSystem_MorphOS *TheSystem = NULL; - -OSystem *OSystem_MorphOS_create() -{ - if (TheSystem) - delete TheSystem; - - TheSystem = OSystem_MorphOS::create(ST_NONE, ConfMan.getBool("fullscreen")); - - return TheSystem; -} - -void close_resources() -{ - delete TheSystem; - TheSystem = NULL; - - if (ScummPath) - { - FreeVec(ScummPath); - ScummPath = NULL; - } - - if (ScummStory) - { - FreeVec(ScummStory); - ScummStory = NULL; - } - - if (ScummArgs) - { - FreeArgs(ScummArgs); - ScummArgs = NULL; - } - - if (OrigDirLock) - { - CurrentDir(OrigDirLock); - OrigDirLock = NULL; - } - - if (CDDABase) - { - CloseLibrary(CDDABase); - CDDABase = NULL; - } -} - -static STRPTR FindMusicDriver(STRPTR argval) -{ - if (!stricmp(argval, "off")) return "-enull"; - if (!stricmp(argval, "midi")) return "-eetude"; - if (!stricmp(argval, "adlib")) return "-eadlib"; - - error("No such music driver supported. Possible values are off, Midi and Adlib."); - return NULL; -} - -static void ReadToolTypes(WBArg *OfFile) -{ - DiskObject *dobj; - char *ToolValue; - char IconPath[256]; - - NameFromLock(OfFile->wa_Lock, IconPath, 256); - AddPart(IconPath, (STRPTR) OfFile->wa_Name, 256); - - dobj = GetDiskObject(IconPath); - if (dobj == NULL) - return; - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "STORY"); - if (ToolValue) - { - if (ScummStory) - FreeVec(ScummStory); - ScummStory = (char *) AllocVec(strlen(ToolValue)+1, MEMF_PUBLIC); - strcpy(ScummStory, ToolValue); - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "DATAPATH"); - if (ToolValue) - { - if (ScummPath) - FreeVec(ScummPath); - ScummPath = (char *) AllocVec(strlen(ToolValue)+4, MEMF_PUBLIC); - strcpy(ScummPath, "-p"); - strcat(ScummPath, ToolValue); - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "WINDOW"); - if (ToolValue) - { - if (MatchToolValue(ToolValue, "YES")) - args[USG_WINDOW] = TRUE; - else if (MatchToolValue(ToolValue, "NO")) - args[USG_WINDOW] = FALSE; - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "SCALER"); - if (ToolValue) - { - if ((ScummGfxScaler = MorphOSScaler::FindByName(ToolValue)) == ST_INVALID) - { - FreeDiskObject(dobj); - exit(1); - } - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MUSIC"); - if (ToolValue) - { - if (!(ScummMusicDriver = FindMusicDriver(ToolValue))) - { - FreeDiskObject(dobj); - exit(1); - } - args[USG_MUSIC] = (ULONG) &ScummMusicDriver; - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MIDIUNIT"); - if (ToolValue) - ScummMidiUnit = atoi(ToolValue); - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MASTERVOL"); - if (ToolValue) - { - int vol = atoi(ToolValue); - if (vol >= 0 && vol <= 100) - { - ScummMasterVolume = vol; - args[USG_MASTERVOL] = (ULONG) &ScummMasterVolume; - } - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MUSICVOL"); - if (ToolValue) - { - int vol = atoi(ToolValue); - if (vol >= 0 && vol <= 100) - { - ScummMidiVolume = vol; - args[USG_MUSICVOL] = (ULONG) &ScummMidiVolume; - } - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "SFXVOL"); - if (ToolValue) - { - int vol = atoi(ToolValue); - if (vol >= 0 && vol <= 255) - { - ScummSfxVolume = vol; - args[USG_SFXVOL] = (ULONG) &ScummSfxVolume; - } - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "TEMPO"); - if (ToolValue) - { - ScummMidiTempo = atoi(ToolValue); - args[USG_TEMPO] = (ULONG) &ScummMidiTempo; - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "TALKSPEED"); - if (ToolValue) - { - ScummTalkSpeed = atoi(ToolValue); - args[USG_TALKSPEED] = (ULONG) &ScummMidiTempo; - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "LANGUAGE"); - if (ToolValue) - { - if (ScummLang) - FreeVec(ScummLang); - ScummLang = (char *) AllocVec(strlen(ToolValue)+4, MEMF_PUBLIC); - strcpy(ScummLang, "-q"); - strcat(ScummLang, ToolValue); - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "SUBTITLES"); - if (ToolValue) - { - if (MatchToolValue(ToolValue, "YES")) - args[USG_NOSUBTITLES] = FALSE; - else if (MatchToolValue(ToolValue, "NO")) - args[USG_NOSUBTITLES] = TRUE; - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "AMIGA"); - if (ToolValue) - { - if (MatchToolValue(ToolValue, "YES")) - args[USG_AMIGA] = FALSE; - else if (MatchToolValue(ToolValue, "NO")) - args[USG_AMIGA] = TRUE; - } - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "DEBUGLEVEL"); - if (ToolValue) - ScummDebugLevel = atoi(ToolValue); - - ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "DUMPSCRIPTS"); - if (ToolValue) - { - if (MatchToolValue(ToolValue, "YES")) - args[USG_DUMPSCRIPTS] = TRUE; - else if (MatchToolValue(ToolValue, "NO")) - args[USG_DUMPSCRIPTS] = FALSE; - } - - FreeDiskObject(dobj); -} - -#undef main - -int main() -{ - char *argv[30]; - char mastervol[6], musicvol[6], sfxvol[6], talkspeed[12], tempo[12], scaler[14]; - char dbglvl[6]; - int argc = 0; - - atexit(&close_resources); - - memset(args, '\0', sizeof (args)); - if (_WBenchMsg == NULL) - { - /* Parse the command line here */ - ScummArgs = ReadArgs(usageTemplate, args, NULL); - if (ScummArgs == NULL) - { - puts("Error in command line - type \"ScummVM ?\" for usage."); - exit(1); - } - - if (args[USG_STORY]) - { - ScummStory = (char *) AllocVec(strlen((char *) args[USG_STORY])+1, MEMF_PUBLIC); - strcpy(ScummStory, (char *) args[USG_STORY]); - } - - if (args[USG_DATAPATH]) - { - ScummPath = (char *) AllocVec(strlen((char *) args[USG_DATAPATH])+4, MEMF_PUBLIC); - strcpy(ScummPath, "-p"); - strcat(ScummPath, (char *) args[USG_DATAPATH]); - } - - if (args[USG_SCALER]) - { - if ((ScummGfxScaler = MorphOSScaler::FindByName((char *) args[USG_SCALER])) == ST_INVALID) - exit(1); - } - - if (args[USG_MUSIC]) - { - if (!(ScummMusicDriver = FindMusicDriver((char *) args[USG_MUSIC]))) - exit(1); - } - - if (args[USG_MIDIUNIT]) - ScummMidiUnit = *((LONG *) args[USG_MIDIUNIT]); - - if (args[USG_TEMPO]) - ScummMidiTempo = *((LONG *) args[USG_TEMPO]); - - if (args[USG_MASTERVOL]) - ScummMasterVolume = *((LONG *) args[USG_MASTERVOL]); - - if (args[USG_MUSICVOL]) - ScummMidiVolume = *((LONG *) args[USG_MUSICVOL]); - - if (args[USG_SFXVOL]) - ScummSfxVolume = *((LONG *) args[USG_SFXVOL]); - - if (args[USG_TALKSPEED]) - ScummTalkSpeed = *((LONG *) args[USG_TALKSPEED]); - - if (args[USG_LANGUAGE]) - { - ScummLang = (char *) AllocVec(strlen((char *) args[USG_LANGUAGE])+4, MEMF_PUBLIC); - strcpy(ScummLang, "-q"); - strcat(ScummLang, (char *) args[USG_LANGUAGE]); - } - - if (args[USG_DEBUGLEVEL]) - ScummDebugLevel = *((LONG *) args[USG_DEBUGLEVEL]); - } - else - { - /* We've been started from Workbench */ - ReadToolTypes(&_WBenchMsg->sm_ArgList[0]); - if (_WBenchMsg->sm_NumArgs > 1) - { - ReadToolTypes(&_WBenchMsg->sm_ArgList[1]); - OrigDirLock = CurrentDir(_WBenchMsg->sm_ArgList[1].wa_Lock); - } - } - - if (ScummPath) - { - char c = ScummPath[strlen(ScummPath)-1]; - if (c != '/' && c != ':') - strcat(ScummPath, "/"); - } - - argv[argc++] = "ScummVM"; - if (ScummPath) argv[argc++] = ScummPath; - if (!args[USG_WINDOW]) argv[argc++] = "-f"; - if (args[USG_NOSUBTITLES]) argv[argc++] = "-n"; - if (args[USG_AMIGA]) argv[argc++] = "-a"; - if (args[USG_MUSIC]) argv[argc++] = ScummMusicDriver; - else - { - if (etude_available()) - argv[argc++] = "-eetude"; - else - argv[argc++] = "-eadlib"; - } - if (ScummGfxScaler != ST_INVALID) - { - sprintf(scaler, "-g%s", MorphOSScaler::GetParamName(ScummGfxScaler)); - argv[argc++] = scaler; - } - else - argv[argc++] = "-gsuper2xsai"; - if (args[USG_MASTERVOL] && ScummMasterVolume >= 0 && ScummMasterVolume <= 255) - { - sprintf(mastervol, "-o%ld", ScummMasterVolume); - argv[argc++] = mastervol; - } - if (args[USG_MUSICVOL] && ScummMidiVolume >= 0 && ScummMidiVolume <= 255) - { - sprintf(musicvol, "-m%ld", ScummMidiVolume); - argv[argc++] = musicvol; - } - if (args[USG_SFXVOL] && ScummSfxVolume >= 0 && ScummSfxVolume <= 255) - { - sprintf(sfxvol, "-s%ld", ScummSfxVolume); - argv[argc++] = sfxvol; - } - if (args[USG_TEMPO] && ScummMidiTempo > 0) - { - sprintf(tempo, "-t%lx", ScummMidiTempo); - argv[argc++] = tempo; - } - if (args[USG_TALKSPEED] && ScummTalkSpeed >= 0 && ScummTalkSpeed <= 255) - { - sprintf(talkspeed, "-y%ld", ScummTalkSpeed); - argv[argc++] = talkspeed; - } - if (ScummLang) argv[argc++] = ScummLang; - if (args[USG_DUMPSCRIPTS]) argv[argc++] = "-u"; - if (args[USG_DEBUGLEVEL]) - { - sprintf(dbglvl, "-d%ld", ScummDebugLevel); - argv[argc++] = dbglvl; - } - if (ScummStory) - argv[argc++] = ScummStory; - - g_system = OSystem_MorphOS_create(); - assert(g_system); - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - g_system->quit(); // TODO: Consider removing / replacing this! - return res; -} - diff --git a/backends/morphos/morphos_timer.cpp b/backends/morphos/morphos_timer.cpp deleted file mode 100644 index b558c7fd66..0000000000 --- a/backends/morphos/morphos_timer.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2002-2006 The ScummVM Team - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include "common/stdafx.h" -#include "base/engine.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include "morphos.h" -#include "timer.h" - -Timer::Timer(Engine * engine) -{ - if ((TimerServicePort = CreateMsgPort())) - { - TimerServiceStartup.mn_Node.ln_Type = NT_MESSAGE; - TimerServiceStartup.mn_ReplyPort = TimerServicePort; - TimerServiceStartup.mn_Length = sizeof(TimerServiceStartup); - - TimerServiceThread = CreateNewProcTags(NP_Entry, (ULONG) TimerService, - NP_CodeType, CODETYPE_PPC, - NP_Name, (ULONG) "ScummVM Timer Service", - NP_Priority, 0, - NP_StartupMsg, &TimerServiceStartup, - NP_PPC_Arg1, (ULONG) this, - NP_PPC_Arg2, (ULONG) engine, - TAG_DONE - ); - } -} - -Timer::~Timer() -{ - if (TimerServiceThread) - { - Signal((Task *) TimerServiceThread, SIGBREAKF_CTRL_C); - WaitPort(TimerServicePort); - DeleteMsgPort(TimerServicePort); - TimerServiceThread = NULL; - } -} - -bool Timer::init() -{ - return TimerServiceThread != NULL; -} - -void Timer::release() -{ -} - -bool Timer::installTimerProc(TimerProc procedure, int32 interval) -{ - return SendMsg(TSM_MSGID_ADDTIMER, procedure, interval); -} - -void Timer::removeTimerProc(TimerProc procedure) -{ - SendMsg(TSM_MSGID_REMTIMER, procedure, 0); -} - -bool Timer::SendMsg(ULONG msg_id, TimerProc procedure, LONG interval) -{ - if (TimerServiceThread == NULL) - return false; - - TimerServiceMessage *tmsg = (TimerServiceMessage *) AllocVec(sizeof (TimerServiceMessage), MEMF_PUBLIC | MEMF_CLEAR); - if (tmsg == NULL) - return false; - - tmsg->tsm_Message.mn_Node.ln_Type = NT_MESSAGE; - tmsg->tsm_Message.mn_ReplyPort = NULL; - tmsg->tsm_Message.mn_Length = sizeof (TimerServiceMessage); - tmsg->tsm_MsgID = msg_id; - tmsg->tsm_Callback = procedure; - tmsg->tsm_Interval = interval; - PutMsg(&TimerServiceThread->pr_MsgPort, (Message*) tmsg); - - return true; -} - -void Timer::TimerService(Timer *this_ptr, Engine *engine) -{ - MsgPort *port = &((Process *) FindTask(NULL))->pr_MsgPort; - ULONG port_bit = 1 << port->mp_SigBit; - ULONG signal_mask = SIGBREAKF_CTRL_C | port_bit; - ULONG timer_bits = 0, signals; - ULONG interval, t; - timeval start_callback, end_callback; - - ULONG timers = 0; - TimerSlot timer_slots[MAX_TIMERS]; - - for (;;) - { - signals = Wait(signal_mask); - - GetSysTime(&start_callback); - - if (signals & port_bit) - { - TimerServiceMessage *tmsg; - - while ((tmsg = (TimerServiceMessage *) GetMsg(port))) - { - if (tmsg->tsm_Message.mn_Length == sizeof (TimerServiceMessage)) - { - switch (tmsg->tsm_MsgID) - { - case TSM_MSGID_ADDTIMER: - if (timers < MAX_TIMERS) - { - ULONG unit = UNIT_MICROHZ; - - if (tmsg->tsm_Interval >= 1000000) - unit = UNIT_VBLANK; - if (OSystem_MorphOS::OpenATimer(&timer_slots[timers].ts_Port, (IORequest **) &timer_slots[timers].ts_IORequest, unit)) - { - timer_slots[timers].ts_Callback = tmsg->tsm_Callback; - timer_slots[timers].ts_Interval = tmsg->tsm_Interval; - timer_slots[timers].ts_SignalBit = 1 << timer_slots[timers].ts_Port->mp_SigBit; - - signal_mask |= timer_slots[timers].ts_SignalBit; - timer_bits |= timer_slots[timers].ts_SignalBit; - - timerequest *req = timer_slots[timers].ts_IORequest; - interval = timer_slots[timers].ts_Interval; - req->tr_node.io_Command = TR_ADDREQUEST; - req->tr_time.tv_secs = interval/1000000; - req->tr_time.tv_micro = interval%1000000; - SendIO((IORequest*) req); - - timers++; - } - } - break; - - case TSM_MSGID_REMTIMER: - { - for (t = 0; t < timers; t++) - { - if (timer_slots[t].ts_Callback == tmsg->tsm_Callback) - { - AbortIO((IORequest *) timer_slots[t].ts_IORequest); - WaitIO((IORequest *) timer_slots[t].ts_IORequest); - signal_mask &= ~timer_slots[t].ts_SignalBit; - timer_bits &= ~timer_slots[t].ts_SignalBit; - CloseDevice((IORequest *) timer_slots[t].ts_IORequest); - DeleteIORequest((IORequest *) timer_slots[t].ts_IORequest); - DeleteMsgPort(timer_slots[t].ts_Port); - if (t < timers-1) - memmove(&timer_slots[t], &timer_slots[t+1], sizeof (TimerSlot)*(timers-t-1)); - timers--; - continue; - } - } - break; - } - - default: - warning("MorphOS TimerService received message of unknown type."); - } - } - - if (tmsg->tsm_Message.mn_ReplyPort) - ReplyMsg((Message *) tmsg); - else - FreeVec((Message *) tmsg); - } - } - - if (signals & SIGBREAKF_CTRL_C) - break; - - if (signals & timer_bits) - { - for (t = 0; t < timers; t++) - { - if (signals & timer_slots[t].ts_SignalBit) - { - timerequest *req = timer_slots[t].ts_IORequest; - WaitIO((IORequest *) req); - interval = timer_slots[t].ts_Interval; - (*timer_slots[t].ts_Callback)(engine); - GetSysTime(&end_callback); - SubTime(&end_callback, &start_callback); - interval -= end_callback.tv_sec*1000000+end_callback.tv_micro/1000000+40000; - if (interval < 0) - interval = 0; - - req->tr_node.io_Command = TR_ADDREQUEST; - req->tr_time.tv_secs = interval/1000000; - req->tr_time.tv_micro = interval%1000000; - SendIO((IORequest*) req); - } - } - } - } - - for (t = 0; t < timers; t++) - { - AbortIO((IORequest *) timer_slots[t].ts_IORequest); - WaitIO((IORequest *) timer_slots[t].ts_IORequest); - CloseDevice((IORequest *) timer_slots[t].ts_IORequest); - DeleteIORequest((IORequest *) timer_slots[t].ts_IORequest); - DeleteMsgPort(timer_slots[t].ts_Port); - } -} - diff --git a/backends/morphos/morphos_timer.h b/backends/morphos/morphos_timer.h deleted file mode 100644 index 1ab3259b39..0000000000 --- a/backends/morphos/morphos_timer.h +++ /dev/null @@ -1,88 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2002-2006 The ScummVM Team - * - * 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 MORPHOS_TIMER_H -#define MORPHOS_TIMER_H - -#ifndef TIMER_H -#include "timer.h" // for MAX_TIMER -#endif - -#ifndef EXEC_PORTS_H -#include -#endif - -#ifndef EXEC_IO_H -#include -#endif - -#ifndef EXEC_SEMAPHORES_H -#include -#endif - -#ifndef DOS_DOSEXTENS_H -#include -#endif - -class OSystem; - -#define TSM_MSGID_ADDTIMER 0 -#define TSM_MSGID_REMTIMER 1 - -struct TimerServiceMessage -{ - Message tsm_Message; - ULONG tsm_MsgID; - TimerProc tsm_Callback; - LONG tsm_Interval; -}; - -class Timer -{ - public: - Timer(Engine * engine); - ~Timer(); - - bool init(); - void release(); - bool installTimerProc(TimerProc procedure, int32 interval); - void removeTimerProc(TimerProc procedure); - - protected: - bool SendMsg(ULONG MsgID, TimerProc procedure, LONG interval); - static void TimerService(Timer *, Engine *); - - Process *TimerServiceThread; - MsgPort *TimerServicePort; - Message TimerServiceStartup; - - struct TimerSlot - { - MsgPort *ts_Port; - timerequest *ts_IORequest; - ULONG ts_SignalBit; - TimerProc ts_Callback; - LONG ts_Interval; - }; -}; - -#endif - diff --git a/backends/null/module.mk b/backends/null/module.mk deleted file mode 100644 index d8f2161a2e..0000000000 --- a/backends/null/module.mk +++ /dev/null @@ -1,10 +0,0 @@ -MODULE := backends/null - -MODULE_OBJS := \ - null.o - -MODULE_DIRS += \ - backends/null/ - -# We don't use the rules.mk here on purpose -OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) diff --git a/backends/null/null.cpp b/backends/null/null.cpp deleted file mode 100644 index f9943ef448..0000000000 --- a/backends/null/null.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "common/scummsys.h" -#include "common/system.h" - -#if defined(USE_NULL_DRIVER) - -#include "common/rect.h" -#include "common/savefile.h" - -class OSystem_NULL : public OSystem { -public: - static OSystem *instance(); - -public: - - OSystem_NULL(); - virtual ~OSystem_NULL(); - - virtual bool hasFeature(Feature f); - virtual void setFeatureState(Feature f, bool enable); - virtual bool getFeatureState(Feature f); - virtual const GraphicsMode *getSupportedGraphicsModes() const; - virtual int getDefaultGraphicsMode() const; - bool setGraphicsMode(const char *name); - virtual int getGraphicsMode() const; - virtual void initSize(uint width, uint height); - virtual int16 getHeight(); - virtual int16 getWidth(); - virtual void setPalette(const byte *colors, uint start, uint num); - virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); - virtual void updateScreen(); - virtual void setShakePos(int shakeOffset); - - virtual void showOverlay(); - virtual void hideOverlay(); - virtual void clearOverlay(); - virtual void grabOverlay(OverlayColor *buf, int pitch); - virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); - virtual int16 getOverlayHeight(); - virtual int16 getOverlayWidth(); - - virtual OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b); - virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b); - - virtual bool showMouse(bool visible); - - virtual void warpMouse(int x, int y); - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255); - - virtual bool pollEvent(Event &event); - virtual uint32 getMillis(); - virtual void delayMillis(uint msecs); - - virtual void setTimerCallback(TimerProc callback, int interval); - - virtual MutexRef createMutex(void); - virtual void lockMutex(MutexRef mutex); - virtual void unlockMutex(MutexRef mutex); - virtual void deleteMutex(MutexRef mutex); - - virtual bool setSoundCallback(SoundProc proc, void *param); - virtual void clearSoundCallback(); - virtual int getOutputSampleRate() const; - - virtual bool openCD(int drive); - virtual bool pollCD(); - - virtual void playCD(int track, int num_loops, int start_frame, int duration); - virtual void stopCD(); - virtual void updateCD(); - - virtual void quit(); - - virtual void setWindowCaption(const char *caption); -}; - -static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { - {0, 0, 0} -}; - -int main(int argc, char *argv[]) { - g_system = OSystem_NULL_create(); - assert(g_system); - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - g_system->quit(); // TODO: Consider removing / replacing this! - return res; -} - -OSystem_NULL::OSystem_NULL() { -} - -OSystem_NULL::~OSystem_NULL() { -} - -bool OSystem_NULL::hasFeature(Feature f) { - return false; -} - -void OSystem_NULL::setFeatureState(Feature f, bool enable) { -} - -bool OSystem_NULL::getFeatureState(Feature f) { - return false; -} - -const OSystem::GraphicsMode* OSystem_NULL::getSupportedGraphicsModes() const { - return s_supportedGraphicsModes; -} - - -int OSystem_NULL::getDefaultGraphicsMode() const { - return -1; -} - -bool OSystem_NULL::setGraphicsMode(int mode) { - return true; -} - -int OSystem_NULL::getGraphicsMode() const { - return -1; -} - -void OSystem_NULL::initSize(uint width, uint height) { -} - -int16 OSystem_NULL::getHeight() { - return 320; -} - -int16 OSystem_NULL::getWidth() { - return 200; -} - -void OSystem_NULL::setPalette(const byte *colors, uint start, uint num) { -} - -void OSystem_NULL::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { -} - -void OSystem_NULL::updateScreen() { -} - -void OSystem_NULL::setShakePos(int shakeOffset) { -} - -void OSystem_NULL::showOverlay () { -} - -void OSystem_NULL::hideOverlay () { -} - -void OSystem_NULL::clearOverlay () { -} - -void OSystem_NULL::grabOverlay (OverlayColor *buf, int pitch) { -} - -void OSystem_NULL::copyRectToOverlay (const OverlayColor *buf, int pitch, int x, int y, int w, int h) { -} - -int16 OSystem_NULL::getOverlayHeight() { - return getHeight(); -} - -int16 OSystem_NULL::getOverlayWidth() { - return getWidth(); -} - -OverlayColor OSystem_NULL::RGBToColor(uint8 r, uint8 g, uint8 b) { - return 0; -} - -void OSystem_NULL::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b) { -} - -bool OSystem_NULL::showMouse(bool visible) { - return true; -} - -void OSystem_NULL::warpMouse(int x, int y) { -} - -void OSystem_NULL::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor) { -} - -bool OSystem_NULL::pollEvent(Event &event) { - return false; -} - -uint32 OSystem_NULL::getMillis() { - return 0; -} - -void OSystem_NULL::delayMillis(uint msecs) { -} - -void OSystem_NULL::setTimerCallback(TimerProc callback, int interval) { -} - -OSystem::MutexRef OSystem_NULL::createMutex(void) { - return NULL; -} - -void OSystem_NULL::lockMutex(MutexRef mutex) { -} - -void OSystem_NULL::unlockMutex(MutexRef mutex) { -} - -void OSystem_NULL::deleteMutex(MutexRef mutex) { -} - -bool OSystem_NULL::setSoundCallback(SoundProc proc, void *param) { - return true; -} - -void OSystem_NULL::clearSoundCallback() { -} - -int OSystem_NULL::getOutputSampleRate() const { - return 22050; -} - -void OSystem_NULL::quit() { -} - -void OSystem_NULL::setWindowCaption(const char *caption) { -} - -OSystem *OSystem_NULL_create() { - return new OSystem_NULL(); -} -#else /* USE_NULL_DRIVER */ - -OSystem *OSystem_NULL_create() { - return NULL; -} - -#endif diff --git a/backends/platform/maemo/Makefile b/backends/platform/maemo/Makefile new file mode 100644 index 0000000000..ca49a35f9c --- /dev/null +++ b/backends/platform/maemo/Makefile @@ -0,0 +1,69 @@ +# ScummVM Maemo MakeFile +# $URL$ +# $Id$ + +#control build +DISABLE_HQ_SCALERS = true + +#DISABLE_SCUMM = 1 +#DISABLE_HE = 1 +DISABLE_SIMON = 1 +DISABLE_SKY = 1 +DISABLE_SWORD1 = 1 +DISABLE_SWORD2 = 1 +DISABLE_QUEEN = 1 +DISABLE_KYRA = 1 +DISABLE_SAGA = 1 +DISABLE_GOB = 1 +DISABLE_LURE = 1 +DISABLE_CINE = 1 +DISABLE_AGI = 1 + +srcdir = ../.. +VPATH = $(srcdir) + +CXX := g++ +EXECUTABLE := scummvm + +INCDIR = ../../ . $(srcdir)/engines/ + +CXXFLAGS := -g -ansi -W -Wno-unused-parameter +CXXFLAGS += `pkg-config --cflags gconf-2.0 hildon-libs gtk+-2.0 libosso gdk-2.0` +CXXFLAGS += $(addprefix -I,$(INCDIR)) -I. -Wall $(CXXFLAGS) +CXXFLAGS += -O -Wuninitialized +CXXFLAGS += -Wno-long-long -Wno-multichar -Wno-unknown-pragmas +# Even more warnings... +CXXFLAGS += -pedantic -Wpointer-arith -Wcast-qual -Wconversion +CXXFLAGS += -Wshadow -Wimplicit -Wundef -Wnon-virtual-dtor +CXXFLAGS += -Wno-reorder -Wwrite-strings -fcheck-new + +LIBS += -lz -L/usr/lib -lSDL -lpthread -lXsp -losso +LIBS += `pkg-config --libs gconf-2.0 hildon-libs gtk+-2.0 libosso gdk-2.0` +INCLUDES += -I/usr/include/SDL -D_REENTRANT -I/usr/X11R6/include +OBJS += +DEFINES += -DUNIX -DNONSTANDARD_PORT -D__MAEMO__ +LDFLAGS += + +RANLIB := ranlib +INSTALL := install +AR := ar cru +MKDIR := mkdir -p +ECHO := printf +CAT := cat +RM := rm -f +RM_REC := rm -f -r +CP := cp + +OBJS := main.o maemo-sdl.o + +MODULE_DIRS += . + + +BACKEND := sdl +MODULES += backends/platform/sdl base +MODULE_DIRS += . + +HAVE_GCC3 = 1 + +include $(srcdir)/Makefile.common + diff --git a/backends/platform/maemo/hildon.cpp b/backends/platform/maemo/hildon.cpp new file mode 100644 index 0000000000..1c9bd9162a --- /dev/null +++ b/backends/platform/maemo/hildon.cpp @@ -0,0 +1,134 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include +#include +#include + +#define OSSO_APP_NAME "scummvm" +#define OSSO_APP_VERSION "0.9.0CVS" +#define OSSO_APP_SERVICE "org.scummvm."OSSO_APP_NAME +#define OSSO_APP_OBJECT "/org/scummvm/"OSSO_APP_NAME +#define OSSO_APP_IFACE "org.scummvm."OSSO_APP_NAME + +// Application UI data struct +typedef struct _AppData AppData; +struct _AppData { + HildonApp *app; + HildonAppView *appview; + osso_context_t *osso_context; +}; + +// Callback for exit D-BUS event +void exit_event_handler(gboolean die_now, gpointer data) { + AppData *appdata; + appdata = (AppData *)data; + g_print("exit_event_handler called\n"); + /* Do whatever application needs to do before exiting */ + gtk_infoprint(GTK_WINDOW(appdata->app), "Exiting..."); +} + +// Callback for normal D-BUS messages +gint dbus_req_handler(const gchar *interface, const gchar *method, + GArray *arguments, gpointer data, + osso_rpc_t *retval) { + AppData *appdata; + appdata = (AppData *)data; + osso_system_note_infoprint(appdata->osso_context, method, retval); + return OSSO_OK; +} + + +// Main application +int main(int argc, char *argv[]) { + // Create needed variables + HildonApp *app; + HildonAppView *appview; + osso_context_t *osso_context; + osso_return_t result; + GtkWidget *main_vbox; + GtkWidget *label; + + // Initialize the GTK. + gtk_init(&argc, &argv); + + // Initialize maemo application + osso_context = osso_initialize(OSSO_APP_NAME, OSSO_APP_VERSION, TRUE, NULL); + + // Check that initialization was ok + if (osso_context == NULL) { + return OSSO_ERROR; + } + + // Create the hildon application and setup the title + app = HILDON_APP(hildon_app_new()); + hildon_app_set_title(app, "ScummVM"); + hildon_app_set_two_part_title(app, TRUE); + + // Create HildonAppView and set it to HildonApp + appview = HILDON_APPVIEW(hildon_appview_new("AppView Title")); + hildon_app_set_appview(app, appview); + + // Create AppData + AppData *appdata; + appdata = g_new0(AppData, 1); + appdata->app = app; + appdata->appview = appview; + appdata->osso_context = osso_context; + + // Add vbox to appview + main_vbox = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(appview), main_vbox); + + // Add button to vbox + label = gtk_label_new("Waiting for DBUS message..."); + gtk_box_pack_start(GTK_BOX(main_vbox), label, FALSE, TRUE, 0); + + // Add handler for hello D-BUS messages + result = osso_rpc_set_cb_f(appdata->osso_context, + OSSO_APP_SERVICE, + OSSO_APP_OBJECT, + OSSO_APP_IFACE, + dbus_req_handler, appdata); + if (result != OSSO_OK) { + g_print("Error setting D-BUS callback (%d)\n", result); + return OSSO_ERROR; + } + + // Add handler for Exit D-BUS messages + result = osso_application_set_exit_cb(appdata->osso_context, + exit_event_handler, + (gpointer) appdata); + if (result != OSSO_OK) { + g_print("Error setting exit callback (%d)\n", result); + return OSSO_ERROR; + } + + // Begin the main application + gtk_widget_show_all(GTK_WIDGET(app)); + gtk_main(); + + // Deinitialize OSSO + osso_deinitialize(osso_context); + + return 0; +} diff --git a/backends/platform/maemo/maemo-sdl.cpp b/backends/platform/maemo/maemo-sdl.cpp new file mode 100644 index 0000000000..dfb6cb7048 --- /dev/null +++ b/backends/platform/maemo/maemo-sdl.cpp @@ -0,0 +1,42 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "backends/maemo/maemo-sdl.h" + + +void OSystem_MAEMO::loadGFXMode() { + if (_fullscreen || effectiveScreenHeight() > 400) { + _overlayWidth = 800; + _overlayHeight = 480; + + _fullscreen = true; + } else { + _overlayWidth = 720; + _overlayHeight = 400; + } + + if (_screenHeight != 200) + _adjustAspectRatio = false; + + OSystem_SDL::loadGFXMode(); +} diff --git a/backends/platform/maemo/maemo-sdl.h b/backends/platform/maemo/maemo-sdl.h new file mode 100644 index 0000000000..e342ead5f9 --- /dev/null +++ b/backends/platform/maemo/maemo-sdl.h @@ -0,0 +1,41 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2006 The ScummVM project + * + * 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 MAEMO_SDL_H +#define MAEMO_SDL_H + +#include "common/stdafx.h" +#include "backends/platform/sdl/sdl-common.h" + +//#include "CEkeys.h" + +#include + + +class OSystem_MAEMO : public OSystem_SDL { +public: + OSystem_MAEMO() {}; + + void loadGFXMode(); +}; + +#endif diff --git a/backends/platform/maemo/main.cpp b/backends/platform/maemo/main.cpp new file mode 100644 index 0000000000..2631d35000 --- /dev/null +++ b/backends/platform/maemo/main.cpp @@ -0,0 +1,81 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include +#include +#include +#include + +#include +#include + +#include "backends/maemo/maemo-sdl.h" +#include "base/main.h" +#include +#include +#include + +#include +#include + +#define OSSO_APP_NAME "scummvm" +#define OSSO_APP_VERSION "0.9.0CVS" + +void set_doubling(unsigned char enable) { + return; + + SDL_SysWMinfo wminfo; + SDL_VERSION(&wminfo.version); + SDL_GetWMInfo(&wminfo); + XSPSetPixelDoubling(wminfo.info.x11.display, 0, enable); +} + +int main(int argc, char *argv[]) { + osso_context_t *osso_context; + + // Initialize maemo application + //osso_context = osso_initialize(OSSO_APP_NAME, OSSO_APP_VERSION, TRUE, NULL); + + // Check that initialization was ok + //if (osso_context == NULL) { + // return OSSO_ERROR; + //} + + // Maemo task navigator priority inheritance fix + setpriority(PRIO_PROCESS, 0, 0); + + set_doubling(0); + + g_system = new OSystem_MAEMO(); + assert(g_system); + + // Invoke the actual ScummVM main entry point: + int res = scummvm_main(argc, argv); + g_system->quit(); // TODO: Consider removing / replacing this! + + /* Deinitialize OSSO */ + //osso_deinitialize(osso_context); + + set_doubling(0); + + return res; +} diff --git a/backends/platform/maemo/portdefs.h b/backends/platform/maemo/portdefs.h new file mode 100644 index 0000000000..f825e5c4e2 --- /dev/null +++ b/backends/platform/maemo/portdefs.h @@ -0,0 +1,69 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2006 The ScummVM project + * + * 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 PORTDEFS_H +#define PORTDEFS_H + +#define SCUMM_LITTLE_ENDIAN +#define SCUMM_NEED_ALIGNMENT + +#undef HAVE_X86 + +#undef LINUPY + +/* Data types */ +typedef unsigned char byte; +typedef unsigned int uint; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef signed char int8; +typedef signed short int16; +typedef signed int int32; + +/* Libs */ +#undef USE_VORBIS +#undef USE_TREMOR +#undef USE_FLAC +#undef USE_MAD +#define USE_ZLIB +#undef USE_MPEG2 +#undef USE_MT32EMU + +/* Whether we should use i386 assembly routines */ +#undef USE_NASM + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void set_doubling(unsigned char enable); + +#endif /* PORTDEFS_H */ + + diff --git a/backends/platform/morphos/MorphOS.readme b/backends/platform/morphos/MorphOS.readme new file mode 100644 index 0000000000..201c8f32b8 --- /dev/null +++ b/backends/platform/morphos/MorphOS.readme @@ -0,0 +1,13 @@ +This directory contains the source for the MorphOS port of ScummVM. To build, you +must have a proper Geek Gadgets installation. If you don't have the includes for +Etude and cdda.library, check my webpage. If they aren't uploaded yet, feel free +to e-mail me. + +You don't have to build ScummVM yourself. The latest official and CVS binaries are +available from my website at: + +http://www.muenster.de/~tomjoad/scummvm.html + +Ruediger Hanke +tomjoad@muenster.de + diff --git a/backends/platform/morphos/build.rules b/backends/platform/morphos/build.rules new file mode 100644 index 0000000000..13b0033b8c --- /dev/null +++ b/backends/platform/morphos/build.rules @@ -0,0 +1,11 @@ +CXX = g++ +CXXFLAGS = -Wno-multichar -fstrength-reduce -fsigned-char -O2 +DEFINES = -DNDEBUG +LDFLAGS = -noixemul -s +LIBS = -lamiga -lamigastubs -lcybergraphics +INCLUDES += -Ibackends/morphos +MODULES += backends/morphos +OBJS += backends/morphos/morphos.o backends/morphos/morphos_scaler.o \ + backends/morphos/morphos_sound.o backends/morphos/morphos_start.o \ + backends/morphos/morphos_timer.o + diff --git a/backends/platform/morphos/morphos.cpp b/backends/platform/morphos/morphos.cpp new file mode 100644 index 0000000000..889976afc4 --- /dev/null +++ b/backends/platform/morphos/morphos.cpp @@ -0,0 +1,1645 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 Rüdiger Hanke + * + * 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. + * + * MorphOS interface + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "base/engine.h" +#include "common/util.h" +#include "scumm/scumm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "morphos.h" +#include "morphos_sound.h" +#include "morphos_scaler.h" + +static TagItem PlayTags[] = { { CDPA_StartTrack, 1 }, + { CDPA_StartFrame, 0 }, + { CDPA_EndTrack, 1 }, + { CDPA_EndFrame, 0 }, + { CDPA_Loops, 1 }, + { TAG_DONE, 0 } + }; + +static CONST_STRPTR MonkeyCDIDs[] = { "ID2500496F035CBC", "ID250040360345DB", NULL }; +static CONST_STRPTR LoomCDIDs[] = { NULL }; +static CONST_STRPTR MonkeyNames[] = { "Monkey1CD", "Madness", NULL }; +static CONST_STRPTR LoomNames[] = { "LoomCD", NULL }; + +#define BLOCKSIZE_X 32 +#define BLOCKSIZE_Y 8 + +#define BLOCKS_X (ScummBufferWidth/BLOCKSIZE_X) +#define BLOCKS_Y (ScummBufferHeight/BLOCKSIZE_Y) +#define BLOCK_ID(x, y) ((y/BLOCKSIZE_Y)*BLOCKS_X+(x/BLOCKSIZE_X)) + +OSystem_MorphOS *OSystem_MorphOS::create(SCALERTYPE gfx_scaler, bool full_screen) +{ + OSystem_MorphOS *syst = new OSystem_MorphOS(gfx_scaler, full_screen); + + if (!syst || !syst->Initialise()) + { + delete syst; + error("Failed to create system object. Exiting."); + } + + return syst; +} + +OSystem_MorphOS::OSystem_MorphOS(SCALERTYPE gfx_mode, bool full_screen) +{ + ScummScreen = NULL; + ScummWindow = NULL; + ScummBuffer = NULL; + ScummScreenBuffer[0] = NULL; + ScummScreenBuffer[1] = NULL; + ScummRenderTo = NULL; + ScummNoCursor = NULL; + ScummSoundThread = NULL; + ScummWinX = -1; + ScummWinY = -1; + ScummDefaultMouse = false; + ScummOrigMouse = false; + ScummShakePos = 0; + ScummScaler = gfx_mode; + ScummScale = (gfx_mode == ST_NONE) ? 0 : 1; + ScummDepth = 0; + Scumm16ColFmt16 = false; + ScummScrWidth = 0; + ScummScrHeight = 0; + ScreenChanged = false; + DirtyBlocks = NULL; + BlockColors = NULL; + UpdateRects = 0; + Scaler = NULL; + FullScreenMode = full_screen; + CDrive = NULL; + CDDATrackOffset = 0; + strcpy(ScummWndTitle, "ScummVM MorphOS"); + TimerMsgPort = NULL; + TimerIORequest = NULL; + InputMsgPort = NULL; + InputIORequest = NULL; + ThreadPort = NULL; + OvlCMap = NULL; + OvlBitMap = NULL; + OvlSavedBuffer = NULL; + TimerBase = NULL; + ScummNoCursor = NULL; + UpdateRegion = NULL; + NewUpdateRegion = NULL; + MouseImage = NULL; +} + +bool OSystem_MorphOS::Initialise() +{ + OpenATimer(&TimerMsgPort, (IORequest **) &TimerIORequest, UNIT_MICROHZ); + + if ((InputMsgPort = CreateMsgPort())) + { + if ((InputIORequest = (IOStdReq*) CreateIORequest(InputMsgPort, sizeof (IOStdReq)))) + { + if ((OpenDevice("input.device", NULL, (IORequest *) InputIORequest, NULL))) + { + DeleteIORequest(InputIORequest); + DeleteMsgPort(InputMsgPort); + InputIORequest = NULL; + InputMsgPort = NULL; + } + } + else + { + DeleteMsgPort(InputMsgPort); + InputMsgPort = NULL; + } + } + + if (!InputIORequest) + { + warning("input.device could not be opened"); + return false; + } + + ThreadPort = CreateMsgPort(); + if (!ThreadPort) + { + warning("Unable to create a message port"); + return false; + } + + OvlCMap = GetColorMap(256); + + InitSemaphore(&CritSec); + + TimerBase = (Library*) TimerIORequest->tr_node.io_Device; + ScummNoCursor = (UWORD *) AllocVec(16, MEMF_CLEAR); + UpdateRegion = NewRegion(); + NewUpdateRegion = NewRegion(); + if (!UpdateRegion || !NewUpdateRegion) + { + warning("Could not create region for screen update"); + return false; + } + if (!OvlCMap) + { + warning("Could not allocate overlay color map"); + return false; + } + if (!ScummNoCursor) + { + warning("Could not allocate empty cursor image"); + return false; + } + + return true; +} + +OSystem_MorphOS::~OSystem_MorphOS() +{ + if (DirtyBlocks) + { + FreeVec(DirtyBlocks); + + for (int b = 0; b < BLOCKS_X*BLOCKS_Y; b++) + FreeVec(BlockColors[b]); + FreeVec(BlockColors); + } + + if (OvlCMap) + FreeColorMap(OvlCMap); + + delete Scaler; + + if (UpdateRegion) + DisposeRegion(UpdateRegion); + + if (NewUpdateRegion) + DisposeRegion(NewUpdateRegion); + + if (ThreadPort) + DeleteMsgPort(ThreadPort); + + if (CDrive && CDDABase) + { + CDDA_Stop(CDrive); + CDDA_ReleaseDrive(CDrive); + } + + if (InputIORequest) + { + CloseDevice((IORequest *) InputIORequest); + DeleteIORequest((IORequest *) InputIORequest); + } + + if (InputMsgPort) + DeleteMsgPort(InputMsgPort); + + if (TimerIORequest) + { + CloseDevice((IORequest *) TimerIORequest); + DeleteIORequest((IORequest *) TimerIORequest); + } + + if (TimerMsgPort) + DeleteMsgPort(TimerMsgPort); + + if (ScummNoCursor) + FreeVec(ScummNoCursor); + + if (ScummBuffer) + FreeVec(ScummBuffer); + + if (OvlSavedBuffer) + FreeVec(OvlSavedBuffer); + + if (ScummRenderTo && !ScummScreen) + FreeBitMap(ScummRenderTo); + + if (OvlBitMap) + FreeVec(OvlBitMap); + + if (ScummWindow) + CloseWindow(ScummWindow); + + if (ScummScreen) + { + if (ScummScreenBuffer[0]) + FreeScreenBuffer(ScummScreen, ScummScreenBuffer[0]); + if( ScummScreenBuffer[1] ) + FreeScreenBuffer(ScummScreen, ScummScreenBuffer[1]); + CloseScreen(ScummScreen); + } +} + +bool OSystem_MorphOS::OpenATimer(MsgPort **port, IORequest **req, ULONG unit, bool required) +{ + *req = NULL; + const char *err_msg = NULL; + + *port = CreateMsgPort(); + if (*port) + { + *req = (IORequest *) CreateIORequest(*port, sizeof (timerequest)); + if (*req) + { + if (OpenDevice(TIMERNAME, unit, *req, 0)) + { + DeleteIORequest(*req); + *req = NULL; + err_msg = "Failed to open timer device"; + } + } + else + err_msg = "Failed to create IO request"; + } + else + err_msg = "Failed to create message port"; + + if (err_msg) + { + if (required) + error(err_msg); + warning(err_msg); + } + + return *req != NULL; +} + +uint32 OSystem_MorphOS::getMillis() +{ + int ticks = clock(); + ticks *= (1000/CLOCKS_PER_SEC); + return ticks; +} + +void OSystem_MorphOS::delayMillis(uint msecs) +{ +/* TimerIORequest->tr_node.io_Command = TR_ADDREQUEST; + TimerIORequest->tr_time.tv_secs = 0; + TimerIORequest->tr_time.tv_micro = msecs*1000; + DoIO((IORequest *) TimerIORequest);*/ + TimeDelay(UNIT_MICROHZ, 0, msecs*1000); +} + +void OSystem_MorphOS::setTimerCallback(TimerProc callback, int timer) +{ + warning("setTimerCallback() unexpectedly called"); +} + +OSystem::MutexRef OSystem_MorphOS::createMutex() +{ + SignalSemaphore *sem = (SignalSemaphore *) AllocVec(sizeof (SignalSemaphore), MEMF_PUBLIC); + + if (sem) + InitSemaphore(sem); + + return (MutexRef)sem; +} + +void OSystem_MorphOS::lockMutex(MutexRef mutex) +{ + ObtainSemaphore((SignalSemaphore *) mutex); +} + +void OSystem_MorphOS::unlockMutex(MutexRef mutex) +{ + ReleaseSemaphore((SignalSemaphore *)mutex); +} + +void OSystem_MorphOS::deleteMutex(MutexRef mutex) +{ + FreeVec(mutex); +} + +uint32 OSystem_MorphOS::property(int param, Property *value) +{ + AUTO_LOCK + + switch (param) + { + case PROP_GET_FULLSCREEN: + return ScummScreen != NULL; + + case PROP_TOGGLE_FULLSCREEN: + CreateScreen(CSDSPTYPE_TOGGLE); + return 1; + + case PROP_SET_WINDOW_CAPTION: + sprintf(ScummWndTitle, "ScummVM MorphOS - %s", value->caption); + if (ScummWindow) + SetWindowTitles(ScummWindow, ScummWndTitle, ScummWndTitle); + return 1; + + case PROP_OPEN_CD: + { + CONST_STRPTR *ids = NULL, *names = NULL; + + if (g_scumm) + GameID = g_scumm->_gameId; + + switch (GameID) + { + case GID_MONKEY: + case GID_MONKEY_SEGA: + ids = MonkeyCDIDs; + names = MonkeyNames; + break; + + case GID_LOOM256: + ids = LoomCDIDs; + names = LoomNames; + break; + } + + if (!CDDABase) CDDABase = OpenLibrary("cdda.library", 2); + if (CDDABase) + { + CDrive = NULL; + if (ids) + { + int i = 0; + + while (ids[i] && !CDrive) + { + TagItem FindCDTags[] = { { CDFA_CDID, (ULONG) ids[i] }, + { TAG_DONE, 0 } + }; + CDrive = CDDA_FindNextDriveA(NULL, FindCDTags); + i++; + } + } + + if (!CDrive && names) + { + int i = 0; + + while (names[i] && !CDrive) + { + TagItem FindCDTags[] = { { CDFA_VolumeName, (ULONG) names[i] }, + { TAG_DONE, 0 } + }; + CDrive = CDDA_FindNextDriveA(NULL, FindCDTags); + i++; + } + } + + if (CDrive) + { + if (!CDDA_ObtainDriveA(CDrive, CDDA_SHARED_ACCESS, NULL)) + { + CDrive = NULL; + warning("Failed to obtain CD drive - music will not play"); + } + else if (GameID == GID_LOOM256) + { + // Offset correction *may* be required + CDS_TrackInfo ti = { sizeof (CDS_TrackInfo) }; + + if (CDDA_GetTrackInfo(CDrive, 1, 0, &ti)) + CDDATrackOffset = ti.ti_TrackStart.tm_Format.tm_Frame-22650; + } + } + else + warning( "Could not find game CD inserted in CD-ROM drive - cd audio will not play" ); + } + else + warning( "Failed to open cdda.library - cd audio will not play" ); + break; + } + + case PROP_GET_SAMPLE_RATE: + return SAMPLES_PER_SEC; + } + + return 0; +} + +void OSystem_MorphOS::playCD(int track, int num_loops, int start_frame, int duration) +{ + if (CDrive && start_frame >= 0) + { + if (start_frame > 0) + start_frame -= CDDATrackOffset; + + PlayTags[0].ti_Data = track; + PlayTags[1].ti_Data = start_frame; + PlayTags[2].ti_Data = (duration == 0) ? track+1 : track; + PlayTags[3].ti_Data = duration ? start_frame+duration : 0; + PlayTags[4].ti_Data = (num_loops == 0) ? 1 : num_loops; + CDDA_PlayA(CDrive, PlayTags); + } +} + +void OSystem_MorphOS::stopCD() +{ + if (CDrive) + CDDA_Stop(CDrive); +} + +bool OSystem_MorphOS::pollCD() +{ + ULONG status; + + if (CDrive == NULL) + return false; + + CDDA_GetAttr(CDDA_Status, CDrive, &status); + return status == CDDA_Status_Busy; +} + +void OSystem_MorphOS::updateCD() +{ +} + +void OSystem_MorphOS::quit() +{ + int num_threads = 0; + + if (ScummSoundThread) + { + num_threads++; + Signal((Task *) ScummSoundThread, SIGBREAKF_CTRL_C); + ScummSoundThread = NULL; + } + + // TODO: this code could probably greatly simplified now that there is + // only one thread left... + while (num_threads > 0) + { + Message* msg; + + WaitPort(ThreadPort); + while (msg = GetMsg(ThreadPort)) + num_threads--; + } + + exit(0); +} + +#define CVT8TO32(col) ((col<<24) | (col<<16) | (col<<8) | col) + +void OSystem_MorphOS::setPalette(const byte *colors, uint start, uint num) +{ + const byte *data = colors; + UWORD changed_colors[256]; + UWORD num_changed = 0; + + for (uint i = start; i != start+num; i++) + { + ULONG color32 = (data[0] << 16) | (data[1] << 8) | data[2]; + if (color32 != ScummColors[i]) + { + if (ScummDepth == 8) + SetRGB32(&ScummScreen->ViewPort, i, CVT8TO32(data[0]), CVT8TO32(data[1]), CVT8TO32(data[2])); + ScummColors16[i] = Scumm16ColFmt16 ? (((data[0]*31)/255) << 11) | (((data[1]*63)/255) << 5) | ((data[ 2 ]*31)/255) : (((data[0]*31)/255) << 10) | (((data[1]*31)/255) << 5) | ((data[2]*31)/255); + ScummColors[i] = color32; + changed_colors[num_changed++] = i; + } + data += 4; + } + + if (ScummScale || ScummDepth != 8) + { + if (DirtyBlocks && num_changed < 200) + { + for (int b = 0; b < BLOCKS_X*BLOCKS_Y; b++) + { + UWORD *block_colors = BlockColors[b]; + UWORD *color_ptr = changed_colors; + for (int c = 0; c < num_changed; c++) + { + if (block_colors[*color_ptr++]) + { + UWORD x, y; + x = b % BLOCKS_X; + y = b / BLOCKS_X; + DirtyBlocks[b] = true; + AddUpdateRect(x*BLOCKSIZE_X, y*BLOCKSIZE_Y, BLOCKSIZE_X, BLOCKSIZE_Y); + break; + } + } + } + } + else + AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); + } +} + +void OSystem_MorphOS::CreateScreen(CS_DSPTYPE dspType) +{ + LONG mode = INVALID_ID; + int depths[] = { 8, 32, 16, 15, 0 }; + int i; + Screen *wb = NULL; + + if (dspType != CSDSPTYPE_KEEP) + FullScreenMode = (dspType == CSDSPTYPE_FULLSCREEN) || (dspType == CSDSPTYPE_TOGGLE && !FullScreenMode); + + if (ScummRenderTo && !ScummScreen) + FreeBitMap(ScummRenderTo); + ScummRenderTo = NULL; + + if (ScummWindow) + { + if (ScummScreen == NULL) + { + ScummWinX = ScummWindow->LeftEdge; + ScummWinY = ScummWindow->TopEdge; + } + CloseWindow (ScummWindow); + ScummWindow = NULL; + } + + if (ScummScreen) + { + if (ScummScreenBuffer[0]) + FreeScreenBuffer(ScummScreen, ScummScreenBuffer[0]); + if (ScummScreenBuffer[1]) + FreeScreenBuffer(ScummScreen, ScummScreenBuffer[1]); + CloseScreen(ScummScreen); + ScummScreen = NULL; + } + + ScummScrWidth = ScummBufferWidth << ScummScale; + ScummScrHeight = ScummBufferHeight << ScummScale; + + if (FullScreenMode) + { + for (i = ScummScale; mode == INVALID_ID && depths[i]; i++) + mode = BestCModeIDTags(CYBRBIDTG_NominalWidth, ScummScrWidth, + CYBRBIDTG_NominalHeight, ScummScrHeight, + CYBRBIDTG_Depth, depths[i], + TAG_DONE + ); + ScummDepth = depths[i-1]; + + if (mode == INVALID_ID) + error("Could not find suitable screenmode"); + + ScummScreen = OpenScreenTags(NULL, SA_AutoScroll, TRUE, + SA_Depth, ScummDepth, + SA_Width, STDSCREENWIDTH, + SA_Height, STDSCREENHEIGHT, + SA_DisplayID, mode, + SA_ShowTitle, FALSE, + SA_Type, CUSTOMSCREEN, + SA_Title, "ScummVM MorphOS", + TAG_DONE + ); + + if (ScummScreen == NULL) + error("Failed to open screen"); + + LONG RealDepth = GetBitMapAttr(&ScummScreen->BitMap, BMA_DEPTH); + if (RealDepth != ScummDepth) + { + warning("Screen did not open in expected depth"); + ScummDepth = RealDepth; + } + ScummScreenBuffer[0] = AllocScreenBuffer(ScummScreen, NULL, SB_SCREEN_BITMAP); + ScummScreenBuffer[1] = AllocScreenBuffer(ScummScreen, NULL, 0); + ScummRenderTo = ScummScreenBuffer[1]->sb_BitMap; + ScummPaintBuffer = 1; + + if (ScummScreenBuffer[0] == NULL || ScummScreenBuffer[1] == NULL) + error("Failed to allocate screen buffer"); + + // Make both buffers black to avoid grey strip on bottom of screen + RastPort rp; + InitRastPort(&rp); + SetRGB32(&ScummScreen->ViewPort, 0, 0, 0, 0); + rp.BitMap = ScummScreenBuffer[0]->sb_BitMap; + FillPixelArray(&ScummScreen->RastPort, 0, 0, ScummScreen->Width, ScummScreen->Height, 0); + rp.BitMap = ScummRenderTo; + FillPixelArray(&rp, 0, 0, ScummScreen->Width, ScummScreen->Height, 0); + + if (ScummDepth == 8) + { + for (int color = 0; color < 256; color++) + { + ULONG r, g, b; + + r = (ScummColors[color] >> 16) & 0xff; + g = (ScummColors[color] >> 8) & 0xff; + b = (ScummColors[color] >> 0) & 0xff; + SetRGB32(&ScummScreen->ViewPort, color, CVT8TO32(r), CVT8TO32(g), CVT8TO32(b)); + } + } + } + else + { + wb = LockPubScreen(NULL); + if (wb == NULL) + error("Could not lock default public screen"); + + ScreenToFront(wb); + } + + ScummWindow = OpenWindowTags(NULL, WA_Left, (wb && ScummWinX >= 0) ? ScummWinX : 0, + WA_Top, wb ? ((ScummWinY >= 0) ? ScummWinY : wb->BarHeight+1) : 0, + WA_InnerWidth, FullScreenMode ? ScummScreen->Width : ScummScrWidth, + WA_InnerHeight, FullScreenMode ? ScummScreen->Height : ScummScrHeight, + WA_Activate, TRUE, + WA_Title, wb ? ScummWndTitle : NULL, + WA_ScreenTitle, wb ? ScummWndTitle : NULL, + WA_Borderless, FullScreenMode, + WA_CloseGadget, !FullScreenMode, + WA_DepthGadget, !FullScreenMode, + WA_DragBar, !FullScreenMode, + WA_ReportMouse, TRUE, + WA_RMBTrap, TRUE, + WA_IDCMP, IDCMP_RAWKEY | + IDCMP_MOUSEMOVE | + IDCMP_CLOSEWINDOW | + IDCMP_MOUSEBUTTONS, + WA_CustomScreen, FullScreenMode ? (ULONG)ScummScreen : (ULONG)wb, + TAG_DONE + ); + + if (wb) + UnlockPubScreen(NULL, wb); + + if (ScummWindow == NULL) + error("Failed to open window"); + + if (!ScummDefaultMouse) + { + SetPointer(ScummWindow, ScummNoCursor, 1, 1, 0, 0); + ScummOrigMouse = false; + } + + if (ScummScreen == NULL) + { + ScummDepth = GetCyberMapAttr(ScummWindow->RPort->BitMap, CYBRMATTR_DEPTH); + if (ScummDepth == 8) + error("Default public screen must be 15 bit or higher if you want to play in window mode"); + + ScummRenderTo = AllocBitMap(ScummScrWidth, ScummScrHeight, ScummDepth, BMF_MINPLANES, ScummWindow->RPort->BitMap); + if (ScummRenderTo == NULL) + error("Failed to allocate bitmap"); + } + + if ((ScummDepth == 15 && Scumm16ColFmt16) || (ScummDepth == 16 && !Scumm16ColFmt16)) + { + for (int col = 0; col < 256; col++) + { + int r = (ScummColors[col] >> 16) & 0xff; + int g = (ScummColors[col] >> 8) & 0xff; + int b = ScummColors[col] & 0xff; + ScummColors16[col] = (Scumm16ColFmt16 == false) ? (((r*31)/255) << 11) | (((g*63)/255) << 5) | ((b*31)/255) : (((r*31)/255) << 10) | (((g*31)/255) << 5) | ((b*31)/255); + } + + Scumm16ColFmt16 = (ScummDepth == 16); + } + + if (OvlBitMap) + FreeVec(OvlBitMap); + + OvlBitMap = AllocVec(ScummBufferWidth*ScummBufferHeight*3, MEMF_PUBLIC | MEMF_CLEAR); + if (OvlBitMap == NULL) + error("Failed to allocated bitmap for overlay"); + + if (Scaler) + { + delete Scaler; + Scaler = NULL; + } + + if (ScummScale) + { + Scaler = MorphOSScaler::Create(ScummScaler, ScummBuffer, ScummBufferWidth, ScummBufferHeight, ScummColors, ScummColors16, ScummRenderTo); + if (Scaler == NULL) + { + warning("Failed to create scaler - scaling will be disabled"); + SwitchScalerTo(ST_NONE); + } + } + + AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); +} + +void OSystem_MorphOS::SwitchScalerTo(SCALERTYPE newScaler) +{ + if (newScaler == ST_NONE && ScummScale != 0) + { + if (Scaler) + { + delete Scaler; + Scaler = NULL; + } + ScummScale = 0; + ScummScaler = ST_NONE; + CreateScreen(ScummScreen ? CSDSPTYPE_FULLSCREEN : CSDSPTYPE_WINDOWED); + } + else + { + if (ScummScale == 0) + { + ScummScale = 1; + ScummScaler = newScaler; + CreateScreen(ScummScreen ? CSDSPTYPE_FULLSCREEN : CSDSPTYPE_WINDOWED); + } + else if (ScummScaler != newScaler) + { + ScummScaler = newScaler; + if (Scaler) + delete Scaler; + Scaler = MorphOSScaler::Create(ScummScaler, ScummBuffer, ScummBufferWidth, ScummBufferHeight, ScummColors, ScummColors16, ScummRenderTo); + if (Scaler == NULL) + { + warning("Failed to create scaler - scaling will be disabled"); + SwitchScalerTo(ST_NONE); + } + else + AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); + } + } +} + +bool OSystem_MorphOS::pollEvent(Event &event) +{ + IntuiMessage *ScummMsg; + + ScummMsg = (IntuiMessage *) GetMsg(ScummWindow->UserPort); + if (ScummMsg) + { + switch (ScummMsg->Class) + { + case IDCMP_RAWKEY: + { + InputEvent FakedIEvent; + char charbuf; + int qual = 0; + + memset(&FakedIEvent, 0, sizeof (InputEvent)); + FakedIEvent.ie_Class = IECLASS_RAWKEY; + FakedIEvent.ie_Code = ScummMsg->Code; + + if (ScummMsg->Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT)) + qual |= KBD_ALT; + if (ScummMsg->Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) + qual |= KBD_SHIFT; + if (ScummMsg->Qualifier & IEQUALIFIER_CONTROL) + qual |= KBD_CTRL; + event.kbd.flags = qual; + + event.type = (ScummMsg->Code & IECODE_UP_PREFIX) ? EVENT_KEYUP : EVENT_KEYDOWN; + ScummMsg->Code &= ~IECODE_UP_PREFIX; + + if (ScummMsg->Code >= RAWKEY_F1 && ScummMsg->Code <= RAWKEY_F10) + { + /* + * Function key + */ + event.kbd.ascii = (ScummMsg->Code-RAWKEY_F1)+315; + event.kbd.keycode = 0; + } + else if (ScummMsg->Code == RAWKEY_F11 || ScummMsg->Code == RAWKEY_F12) + { + /* + * Function key on PC keyboard + */ + event.kbd.ascii = (ScummMsg->Code == RAWKEY_F11) ? 325 : 326; + event.kbd.keycode = 0; + } + else if (ScummMsg->Code == NM_WHEEL_UP || ScummMsg->Code == NM_WHEEL_DOWN) + { + /* + * Wheelmouse event + */ + event.type = (ScummMsg->Code == NM_WHEEL_UP) ? EVENT_WHEELUP : EVENT_WHEELDOWN; + } + else if (MapRawKey(&FakedIEvent, &charbuf, 1, NULL) == 1) + { + if (qual == KBD_CTRL && charbuf == 'z') + { + event.type = EVENT_QUIT; + break; + } + else if (qual == KBD_ALT) + { + if (charbuf >= '0' && charbuf <= '9') + { + SCALERTYPE new_scaler = MorphOSScaler::FindByIndex(charbuf-'0'); + ReplyMsg((Message *) ScummMsg); + if (new_scaler != ST_INVALID) + SwitchScalerTo(new_scaler); + return false; + } + else if (charbuf == 'x') + { + event.type = EVENT_QUIT; + break; + } + else if (charbuf == 0x0d) + { + ReplyMsg((Message *) ScummMsg); + CreateScreen(CSDSPTYPE_TOGGLE); + return false; + } + } + + event.kbd.ascii = charbuf; + event.kbd.keycode = charbuf; + } + break; + } + + case IDCMP_MOUSEMOVE: + { + LONG newx, newy; + + newx = (ScummMsg->MouseX-ScummWindow->BorderLeft) >> ScummScale; + newy = (ScummMsg->MouseY-ScummWindow->BorderTop) >> ScummScale; + + if (!FullScreenMode && !ScummDefaultMouse) + { + if (newx < 0 || newx > (LONG) ScummBufferWidth || + newy < 0 || newy > (LONG) ScummBufferHeight + ) + { + if (!ScummOrigMouse) + { + ScummOrigMouse = true; + ClearPointer(ScummWindow); + } + } + else if (ScummOrigMouse) + { + ScummOrigMouse = false; + SetPointer(ScummWindow, ScummNoCursor, 1, 1, 0, 0); + } + } + else if (FullScreenMode) + newy = newy > ScummScale)-2; + + event.type = EVENT_MOUSEMOVE; + event.mouse.x = newx; + event.mouse.y = newy; + set_mouse_pos(event.mouse.x, event.mouse.y); + break; + } + + case IDCMP_MOUSEBUTTONS: + { + int newx, newy; + + newx = (ScummMsg->MouseX-ScummWindow->BorderLeft) >> ScummScale; + newy = (ScummMsg->MouseY-ScummWindow->BorderTop) >> ScummScale; + + switch (ScummMsg->Code) + { + case SELECTDOWN: + event.type = EVENT_LBUTTONDOWN; + break; + + case SELECTUP: + event.type = EVENT_LBUTTONUP; + break; + + case MENUDOWN: + event.type = EVENT_RBUTTONDOWN; + break; + + case MENUUP: + event.type = EVENT_RBUTTONUP; + break; + + default: + ReplyMsg((Message *)ScummMsg); + return false; + } + event.mouse.x = newx; + event.mouse.y = newy; + break; + } + + case IDCMP_CLOSEWINDOW: + event.type = EVENT_QUIT; + break; + } + + if (ScummMsg) + ReplyMsg((Message *) ScummMsg); + + return true; + } + + return false; +} + +void OSystem_MorphOS::warpMouse(int x, int y) +{ + if (InputIORequest) + { + InputEvent* FakeIE; + IEPointerPixel* NewPixel; + + /* + * Fake a mousemove input event + */ + if ((FakeIE = (InputEvent*) AllocVec(sizeof (InputEvent), MEMF_PUBLIC))) + { + if ((NewPixel = (IEPointerPixel*) AllocVec(sizeof (IEPointerPixel), MEMF_PUBLIC))) + { + NewPixel->iepp_Screen = ScummWindow->WScreen; + NewPixel->iepp_Position.X = (x << ScummScale) + ScummWindow->LeftEdge + ScummWindow->BorderLeft; + NewPixel->iepp_Position.Y = (y << ScummScale) + ScummWindow->TopEdge + ScummWindow->BorderTop; + + FakeIE->ie_EventAddress = NewPixel; + FakeIE->ie_NextEvent = NULL; + FakeIE->ie_Class = IECLASS_NEWPOINTERPOS; + FakeIE->ie_SubClass = IESUBCLASS_PIXEL; + FakeIE->ie_Code = IECODE_NOBUTTON; + FakeIE->ie_Qualifier = NULL; + + InputIORequest->io_Data = FakeIE; + InputIORequest->io_Length = sizeof (InputEvent); + InputIORequest->io_Command = IND_WRITEEVENT; + DoIO((IORequest *) InputIORequest); + + FreeVec(NewPixel); + } + FreeVec(FakeIE); + } + } +} + +void OSystem_MorphOS::setShakePos(int shake_pos) +{ + ScummShakePos = shake_pos; + AddUpdateRect(0, 0, ScummBufferWidth, ScummBufferHeight); +} + +#define MOUSE_INTERSECTS(x, y, w, h) \ + (!((MouseOldX+MouseOldWidth <= x ) || (MouseOldX >= x+w) || \ + (MouseOldY+MouseOldHeight <= y) || (MouseOldY >= y+h))) + +/* Copy part of bitmap */ +void OSystem_MorphOS::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) +{ + byte *dst; + + if (x < 0) { w+=x; src-=x; x = 0; } + if (y < 0) { h+=y; src-=y*pitch; y = 0; } + if (w >= ScummBufferWidth-x) { w = ScummBufferWidth - x; } + if (h >= ScummBufferHeight-y) { h = ScummBufferHeight - y; } + + if (w <= 0 || h <= 0) + return; + + AUTO_LOCK + + if (MouseDrawn) + { + if (MOUSE_INTERSECTS(x, y, w, h)) + UndrawMouse(); + } + + AddUpdateRect(x, y, w, h); + + dst = (byte *)ScummBuffer+y*ScummBufferWidth + x; + if (DirtyBlocks) + { + int cx, cy; + int block = BLOCK_ID(x, y); + int line_block = block; + int start_block = BLOCKSIZE_X-(x % BLOCKSIZE_X); + int start_y_block = BLOCKSIZE_Y-(y % BLOCKSIZE_Y); + int next_block; + int next_y_block; + UWORD *block_cols = BlockColors[block]; + + if (start_block == 0) + start_block = BLOCKSIZE_X; + if (start_y_block == 0) + start_y_block = BLOCKSIZE_Y; + + next_block = start_block; + next_y_block = start_y_block; + for (cy = 0; cy < h; cy++) + { + for (cx = 0; cx < w; cx++) + { + UWORD old_pixel = *dst; + UWORD src_pixel = *src++; + if (old_pixel != src_pixel) + { + *dst++ = src_pixel; + block_cols[old_pixel]--; + block_cols[src_pixel]++; + } + else + dst++; + if (--next_block == 0) + { + block++; + block_cols = BlockColors[block]; + next_block = BLOCKSIZE_X; + } + } + if (--next_y_block == 0) + { + line_block += BLOCKS_X; + next_y_block = BLOCKSIZE_Y; + } + block = line_block; + block_cols = BlockColors[block]; + next_block = start_block; + dst += ScummBufferWidth-w; + src += pitch-w; + } + } + else + { + do + { + memcpy(dst, src, w); + dst += ScummBufferWidth; + src += pitch; + } while (--h); + } +} + +bool OSystem_MorphOS::AddUpdateRect(WORD x, WORD y, WORD w, WORD h) +{ + if (UpdateRects > 25) + return false; + + if (x < 0) { w+=x; x = 0; } + if (y < 0) { h+=y; y = 0; } + if (w >= ScummBufferWidth-x) { w = ScummBufferWidth - x; } + if (h >= ScummBufferHeight-y) { h = ScummBufferHeight - y; } + + if (w <= 0 || h <= 0) + return false; + + if (++UpdateRects > 25) + { + x = 0; y = 0; + w = ScummBufferWidth; h = ScummBufferHeight; + } + + Rectangle update_rect = { x, y, x+w, y+h }; + OrRectRegion(NewUpdateRegion, &update_rect); + ScreenChanged = true; + + return true; +} + +void OSystem_MorphOS::updateScreen() +{ + AUTO_LOCK + + DrawMouse(); + + if (!ScreenChanged) + return; + + OrRegionRegion(NewUpdateRegion, UpdateRegion); + + if (ScummShakePos) + { + RastPort rp; + + InitRastPort(&rp); + rp.BitMap = ScummRenderTo; + + uint32 src_y = 0; + uint32 dest_y = 0; + if (ScummShakePos < 0) + src_y = -ScummShakePos; + else + dest_y = ScummShakePos; + + if (!ScummScale) + { + if (ScummDepth == 8) + WritePixelArray(ScummBuffer, 0, src_y, ScummBufferWidth, &rp, 0, dest_y, ScummBufferWidth, ScummBufferHeight-src_y-dest_y, RECTFMT_LUT8); + else + WriteLUTPixelArray(ScummBuffer, 0, src_y, ScummBufferWidth, &rp, ScummColors, 0, dest_y, ScummBufferWidth, ScummBufferHeight-src_y-dest_y, CTABFMT_XRGB8); + } + else if (Scaler->Prepare(ScummRenderTo)) + { + Scaler->Scale(0, src_y, 0, dest_y, ScummBufferWidth, ScummBufferHeight-src_y-dest_y); + Scaler->Finish(); + } + + if (ScummShakePos < 0) + FillPixelArray(&rp, 0, (ScummBufferHeight-1) << ScummScale, ScummScrWidth, -ScummShakePos << ScummScale, 0); + else + FillPixelArray(&rp, 0, 0, ScummScrWidth, ScummShakePos << ScummScale, 0); + } + else if (!ScummScale) + { + RastPort rp; + + InitRastPort(&rp); + rp.BitMap = ScummRenderTo; + + int32 src_x, src_y; + int32 src_w, src_h; + int32 reg_x, reg_y; + RegionRectangle *update_rect = UpdateRegion->RegionRectangle; + + reg_x = UpdateRegion->bounds.MinX; + reg_y = UpdateRegion->bounds.MinY; + while (update_rect) + { + src_x = update_rect->bounds.MinX; + src_y = update_rect->bounds.MinY; + src_w = update_rect->bounds.MaxX-src_x; + src_h = update_rect->bounds.MaxY-src_y; + src_x += reg_x; + src_y += reg_y; + + if (src_x) src_x--; + if (src_y) src_y--; + src_w += 2; + if (src_x+src_w >= ScummBufferWidth) + src_w = ScummBufferWidth-src_x; + src_h += 2; + if (src_y+src_h >= ScummBufferHeight) + src_h = ScummBufferHeight-src_y; + + if (ScummDepth == 8) + WritePixelArray(ScummBuffer, src_x, src_y, ScummBufferWidth, &rp, src_x, src_y, src_w, src_h, RECTFMT_LUT8); + else + WriteLUTPixelArray(ScummBuffer, src_x, src_y, ScummBufferWidth, &rp, ScummColors, src_x, src_y, src_w, src_h, CTABFMT_XRGB8); + + update_rect = update_rect->Next; + } + } + else + { + int32 src_x, src_y; + int32 src_w, src_h; + int32 reg_x, reg_y; + RegionRectangle *update_rect = UpdateRegion->RegionRectangle; + + reg_x = UpdateRegion->bounds.MinX; + reg_y = UpdateRegion->bounds.MinY; + + if (!Scaler->Prepare(ScummRenderTo)) + update_rect = NULL; + + while (update_rect) + { + src_x = update_rect->bounds.MinX; + src_y = update_rect->bounds.MinY; + src_w = update_rect->bounds.MaxX-src_x; + src_h = update_rect->bounds.MaxY-src_y; + src_x += reg_x; + src_y += reg_y; + + if (src_x) src_x--; + if (src_y) src_y--; + src_w += 2; + if (src_x+src_w >= ScummBufferWidth) + src_w = ScummBufferWidth-src_x; + src_h += 2; + if (src_y+src_h >= ScummBufferHeight) + src_h = ScummBufferHeight-src_y; + + Scaler->Scale(src_x, src_y, src_x, src_y, src_w, src_h); + update_rect = update_rect->Next; + } + Scaler->Finish(); + } + + if (ScummScreen) + { + while (!ChangeScreenBuffer(ScummScreen, ScummScreenBuffer[ScummPaintBuffer])); + ScummPaintBuffer = !ScummPaintBuffer; + ScummRenderTo = ScummScreenBuffer[ScummPaintBuffer]->sb_BitMap; + } + else + { + int32 x = (UpdateRegion->bounds.MinX-1) << ScummScale; + int32 y = (UpdateRegion->bounds.MinY-1) << ScummScale; + if (x < 0) x = 0; + if (y < 0) y = 0; + int32 w = (UpdateRegion->bounds.MaxX << ScummScale)-x+(1 << ScummScale); + int32 h = (UpdateRegion->bounds.MaxY << ScummScale)-y+(1 << ScummScale); + if (x+w > ScummScrWidth) w = ScummScrWidth-x; + if (y+h > ScummScrHeight) h = ScummScrHeight-y; + BltBitMapRastPort(ScummRenderTo, x, y, ScummWindow->RPort, ScummWindow->BorderLeft+x, ScummWindow->BorderTop+y, w, h, ABNC | ABC); + WaitBlit(); + } + + Region *new_region_part = NewUpdateRegion; + NewUpdateRegion = UpdateRegion; + ClearRegion(NewUpdateRegion); + UpdateRegion = new_region_part; + + ScreenChanged = false; + memset(DirtyBlocks, 0, BLOCKS_X*BLOCKS_Y*sizeof (bool)); + UpdateRects = 0; +} + +void OSystem_MorphOS::DrawMouse() +{ + int x,y; + byte *dst,*bak; + byte color; + + if (MouseDrawn || !MouseVisible) + return; + MouseDrawn = true; + + int ydraw = MouseY - MouseHotspotY; + int xdraw = MouseX - MouseHotspotX; + int w = MouseWidth; + int h = MouseHeight; + int x_mouseimg_offs = 0; + int y_mouseimg_offs = 0; + byte *buf; + + if (xdraw < 0) { x_mouseimg_offs = -xdraw; w += xdraw; xdraw = 0; } + if (ydraw < 0) { y_mouseimg_offs = -ydraw; h += ydraw; ydraw = 0; } + + MouseOldX = xdraw; + MouseOldY = ydraw; + MouseOldWidth = w; + MouseOldHeight = h; + + AddUpdateRect(xdraw, ydraw, w, h); + dst = (byte*)ScummBuffer + ydraw*ScummBufferWidth + xdraw; + bak = MouseBackup; + buf = MouseImage + y_mouseimg_offs*MAX_MOUSE_W + x_mouseimg_offs; + + for (y = 0; y < h; y++, dst += ScummBufferWidth, bak += MAX_MOUSE_W, buf += MouseWidth) + { + if (ydraw+y < ScummBufferHeight) + { + for (x = 0; x= 0; --b) + FreeVec(BlockColors[b]); + FreeVec(BlockColors); + BlockColors = NULL; + } + } + + if (!BlockColors) + { + FreeVec(DirtyBlocks); + DirtyBlocks = NULL; + } + } + + CreateScreen(CSDSPTYPE_KEEP); +} + +int16 OSystem_MorphOS::getWidth() +{ + return ScummScrWidth; +} + +int16 OSystem_MorphOS::getHeight() +{ + return ScummScrHeight; +} + +void OSystem_MorphOS::showOverlay() +{ + UndrawMouse(); + memcpy(OvlSavedBuffer, ScummBuffer, ScummBufferWidth*ScummBufferHeight); + clearOverlay(); + for (int c = 0; c < 256; c++) + { + ULONG r, g, b; + r = ScummColors[c] >> 16; + g = (ScummColors[c] >> 8) & 0xff; + b = ScummColors[c] & 0xff; + SetRGB32CM(OvlCMap, c, CVT8TO32(r), CVT8TO32(g), CVT8TO32(b)); + } +} + +void OSystem_MorphOS::hideOverlay() +{ + copyRectToScreen((byte *) OvlSavedBuffer, ScummBufferWidth, 0, 0, ScummBufferWidth, ScummBufferHeight); +} + +void OSystem_MorphOS::clearOverlay() +{ + AUTO_LOCK + + UBYTE *src = (UBYTE *) ScummBuffer; + UBYTE *dest = (UBYTE *) OvlBitMap; + copyRectToScreen((byte *) OvlSavedBuffer, ScummBufferWidth, 0, 0, ScummBufferWidth, ScummBufferHeight); + for (int y = 0; y < ScummBufferHeight; y++) + for (int x = 0; x < ScummBufferWidth; x++) + { + *dest++ = ScummColors[*src] >> 16; + *dest++ = (ScummColors[*src] >> 8) & 0xff; + *dest++ = ScummColors[*src++] & 0xff; + } +} + +void OSystem_MorphOS::grabOverlay(int16 *buf, int pitch) +{ + int h = ScummBufferHeight; + int x; + UBYTE *src = (UBYTE *) OvlBitMap; + + do + { + for (x = 0; x < pitch; x++) + { + *buf++ = (src[0]*31/255 << 11) | (src[1]*63/255 << 5) | src[2]*31/255; + src += 3; + } + src += (ScummBufferWidth-pitch)*3; + } while (--h); +} + +void OSystem_MorphOS::copyRectToOverlay(const int16 *ovl, int pitch, int x, int y, int w, int h) +{ + int x1, y1; + UBYTE *dest; + UBYTE *bmap, *bmap_dest; + LONG last_col[2] = { -1, -1 }; + LONG last_pen[2] = { -1, -1 }; + + if (w > pitch) w = pitch; + bmap = (UBYTE*) AllocVec(w*h, MEMF_ANY); + if (bmap) + { + bmap_dest = bmap; + dest = ((UBYTE *) OvlBitMap)+y*ScummBufferWidth*3+x*3; + for (y1 = 0; y1 < h; y1++) + { + for (x1 = 0; x1 < w; x1++) + { + uint8 r, g, b; + int16 col; + + col = *ovl++; + colorToRGB(col, r, g, b); + *dest++ = r; + *dest++ = g; + *dest++ = b; + if (col == last_col[0]) + *bmap_dest++ = last_pen[0]; + else if (col == last_col[1]) + *bmap_dest++ = last_pen[1]; + else + { + last_col[1] = last_col[0]; + last_pen[1] = last_pen[0]; + last_col[0] = col; + last_pen[0] = FindColor(OvlCMap, CVT8TO32(r), CVT8TO32(g), CVT8TO32(b), -1); + *bmap_dest++ = last_pen[0]; + } + } + dest += (ScummBufferWidth-w)*3; + ovl += pitch-w; + } + copyRectToScreen(bmap, w, x, y, w, h); + FreeVec(bmap); + } +} + diff --git a/backends/platform/morphos/morphos.h b/backends/platform/morphos/morphos.h new file mode 100644 index 0000000000..67ed8a481e --- /dev/null +++ b/backends/platform/morphos/morphos.h @@ -0,0 +1,232 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 Rüdiger Hanke (MorphOS port) + * + * 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. + * + * MorphOS-specific header file + * + * $URL$ + * $Id$ + * + */ + +#ifndef MORPHOS_MORPHOS_H +#define MORPHOS_MORPHOS_H + +#include +#include +#include +#include +#include +#include + +#include "backends/intern.h" +#include "morphos_scaler.h" + +class OSystem_MorphOS : public OSystem +{ + public: + OSystem_MorphOS(SCALERTYPE gfx_mode, bool full_screen); + virtual ~OSystem_MorphOS(); + + bool Initialise(); + + // Set colors of the palette + virtual void setPalette(const byte *colors, uint start, uint num); + + // Set the size of the video bitmap. + // Typically, 320x200 + virtual void initSize(uint w, uint h); + + // Draw a bitmap to screen. + // The screen will not be updated to reflect the new bitmap + virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); + + // Update the dirty areas of the screen + virtual void updateScreen(); + + // Either show or hide the mouse cursor + virtual bool showMouse(bool visible); + + // Set the position of the mouse cursor + virtual void set_mouse_pos(int x, int y); + + // Set the bitmap that's used when drawing the cursor. + virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor); + + // Shaking is used in SCUMM. Set current shake position. + virtual void setShakePos(int shake_pos); + + // Overlay + virtual void showOverlay(); + virtual void hideOverlay(); + virtual void clearOverlay(); + virtual void grabOverlay(int16 *buf, int pitch); + virtual void copyRectToOverlay(const int16 *buf, int pitch, int x, int y, int w, int h); + virtual int16 getHeight(); + virtual int16 getWidth(); + + // Get the number of milliseconds since the program was started. + virtual uint32 getMillis(); + + // Delay for a specified amount of milliseconds + virtual void delayMillis(uint msecs); + + // Add a new callback timer + virtual void setTimerCallback(TimerProc callback, int timer); + + // Mutex handling + virtual MutexRef createMutex(); + virtual void lockMutex(MutexRef mutex); + virtual void unlockMutex(MutexRef mutex); + virtual void deleteMutex(MutexRef mutex); + + // Get the next event. + // Returns true if an event was retrieved. + virtual bool pollEvent(Event &event); + + // Moves mouse pointer to specified position + virtual void warpMouse(int x, int y); + + // Set the function to be invoked whenever samples need to be generated + virtual bool setSoundCallback(SoundProc proc, void *param); + void fill_sound (byte * stream, int len); + void clearSoundCallback(); + + virtual uint32 property(int param, Property *value); + + // Poll cdrom status + // Returns true if cd audio is playing + virtual bool pollCD(); + + // Play cdrom audio track + virtual void playCD(int track, int num_loops, int start_frame, int duration); + + // Stop cdrom audio track + virtual void stopCD(); + + // Update cdrom audio status + virtual void updateCD(); + + // Quit + virtual void quit(); + + static OSystem_MorphOS *create(SCALERTYPE gfx_scaler, bool full_screen); + + static bool OpenATimer(MsgPort **port, IORequest **req, ULONG unit, bool required = true); + + private: + typedef enum { CSDSPTYPE_WINDOWED, CSDSPTYPE_FULLSCREEN, CSDSPTYPE_TOGGLE, CSDSPTYPE_KEEP } CS_DSPTYPE; + + static const int MAX_MOUSE_W = 80; + static const int MAX_MOUSE_H = 80; + + void CreateScreen(CS_DSPTYPE dspType); + void SwitchScalerTo(SCALERTYPE newScaler); + bool AddUpdateRect(WORD x, WORD y, WORD w, WORD h); + + void DrawMouse(); + void UndrawMouse(); + + /* Display-related attributes */ + Screen *ScummScreen; + Window *ScummWindow; + char ScummWndTitle[125]; + APTR ScummBuffer; + LONG ScummBufferWidth; + LONG ScummBufferHeight; + ScreenBuffer *ScummScreenBuffer[2]; + BitMap *ScummRenderTo; + ULONG ScummPaintBuffer; + int ScummScrWidth; + int ScummScrHeight; + int ScummDepth; + bool Scumm16ColFmt16; + UWORD *ScummNoCursor; + ULONG ScummColors[256]; + USHORT ScummColors16[256]; + WORD ScummWinX; + WORD ScummWinY; + bool ScummDefaultMouse; + bool ScummOrigMouse; + int ScummShakePos; + bool FullScreenMode; + bool ScreenChanged; + UWORD **BlockColors; + bool *DirtyBlocks; + Region *UpdateRegion; + Region *NewUpdateRegion; + ULONG UpdateRects; + SignalSemaphore CritSec; + + /* Overlay-related attributes */ + APTR OvlBitMap; + APTR OvlSavedBuffer; + ColorMap *OvlCMap; + + /* Sound-related attributes */ + Process *ScummSoundThread; + SoundProc SoundProc; + void *SoundParam; + MsgPort *ThreadPort; + Message MusicStartup; + Message SoundStartup; + + /* CD-ROM related attributes */ + CDRIVEPTR CDrive; + ULONG CDDATrackOffset; + + /* Scaling-related attributes */ + SCALERTYPE ScummScaler; + int ScummScale; + MorphOSScaler *Scaler; + + /* Mouse cursor-related attributes */ + bool MouseVisible, MouseDrawn; + int MouseX, MouseY; + int MouseWidth, MouseHeight; + int MouseOldX, MouseOldY; + int MouseOldWidth, MouseOldHeight; + int MouseHotspotX, MouseHotspotY; + byte *MouseImage, MouseBackup[MAX_MOUSE_W*MAX_MOUSE_H]; + byte MouseKeycolor; + MsgPort* InputMsgPort; + IOStdReq*InputIORequest; + + /* Timer-related attributes */ + MsgPort *TimerMsgPort; + timerequest *TimerIORequest; + + /* Game-related attributes */ + int GameID; +}; + +class AutoLock +{ + public: + AutoLock(SignalSemaphore* s) : sem(s) { ObtainSemaphore(sem); } + ~AutoLock() { ReleaseSemaphore(sem); } + + private: + SignalSemaphore* sem; +}; + +#define AUTO_LOCK AutoLock cs(&CritSec); + + +extern OSystem_MorphOS *TheSystem; + +#endif + diff --git a/backends/platform/morphos/morphos_scaler.cpp b/backends/platform/morphos/morphos_scaler.cpp new file mode 100644 index 0000000000..46d4452c0b --- /dev/null +++ b/backends/platform/morphos/morphos_scaler.cpp @@ -0,0 +1,848 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002-2006 The ScummVM Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "common/stdafx.h" +#include "base/engine.h" + +#include +#include + +#include + +#include "morphos.h" +#include "morphos_scaler.h" + +#define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D)) +#define INTERPOLATE(A, B) (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask)) +#define Q_INTERPOLATE(A, B, C, D) ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2) + ((((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2) & qlowpixelMask) +#define SWAP_WORD(word) word = ((word & 0xff) << 8) | (word >> 8) +#define SWAP_LONG(lng) lng = ((lng & 0xff) << 24) | ((lng & 0xff00) << 8) | ((lng & 0xff0000) >> 8) | (lng >> 24) + +MorphOSScaler::GfxScaler MorphOSScaler::ScummScalers[11] + = { { "none", "normal", ST_NONE }, + { "Point", "2x", ST_POINT }, + { "AdvMame2x", "advmame2x", ST_ADVMAME2X }, + { "SuperEagle", "supereagle", ST_SUPEREAGLE }, + { "Super2xSaI", "super2xsai", ST_SUPER2XSAI }, + { NULL, NULL, ST_INVALID }, + { NULL, NULL, ST_INVALID }, + { NULL, NULL, ST_INVALID }, + { NULL, NULL, ST_INVALID }, + { NULL, NULL, ST_INVALID }, + // This is the end marker ... do not assign a scaler to it! + { NULL, NULL, ST_INVALID } + }; + +MorphOSScaler::MorphOSScaler(APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap) +{ + dest = NULL; + handle = NULL; + + Buffer = buffer; + BufferWidth = width; + BufferHeight = height; + + ScummColors = col_table; + ScummColors16 = col_table16; + + /* Initialize scaling stuff */ + int minr, ming, minb; + ULONG depth = GetCyberMapAttr(bmap, CYBRMATTR_DEPTH); + + if (depth > 16) + { + minr = 1 << 16; + ming = 1 << 8; + minb = 1; + } + else + { + minr = 1 << ((depth == 15) ? 10 : 11); + ming = 1 << 5; + minb = 1; + } + + int pixfmt = GetCyberMapAttr(bmap, CYBRMATTR_PIXFMT); + + ScummPCMode = false; + if (pixfmt == PIXFMT_RGB15PC || pixfmt == PIXFMT_BGR15PC || + pixfmt == PIXFMT_RGB16PC || pixfmt == PIXFMT_BGR16PC || + pixfmt == PIXFMT_BGRA32) + ScummPCMode = true; + + colorMask = (MakeColor(pixfmt, 255, 0, 0) - minr) | (MakeColor(pixfmt, 0, 255, 0) - ming) | (MakeColor(pixfmt, 0, 0, 255) - minb); + lowPixelMask = minr | ming | minb; + qcolorMask = (MakeColor(pixfmt, 255, 0, 0) - 3*minr) | (MakeColor(pixfmt, 0, 255, 0) - 3*ming) | (MakeColor(pixfmt, 0, 0, 255) - 3*minb); + qlowpixelMask = (minr * 3) | (ming * 3) | (minb * 3); + redblueMask = MakeColor(pixfmt, 255, 0, 255); + greenMask = MakeColor(pixfmt, 0, 255, 0); + + PixelsPerMask = (depth <= 16) ? 2 : 1; + + if (PixelsPerMask == 2) + { + colorMask |= (colorMask << 16); + qcolorMask |= (qcolorMask << 16); + lowPixelMask |= (lowPixelMask << 16); + qlowpixelMask |= (qlowpixelMask << 16); + } +} + +MorphOSScaler::~MorphOSScaler() +{ + Finish(); +} + +MorphOSScaler *MorphOSScaler::Create(SCALERTYPE scaler_type, APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap) +{ + MorphOSScaler *new_scaler = NULL; + + switch (scaler_type) + { + case ST_POINT: + new_scaler = new PointScaler(buffer, width, height, col_table, col_table16, bmap); + break; + + case ST_ADVMAME2X: + new_scaler = new AdvMame2xScaler(buffer, width, height, col_table, col_table16, bmap); + break; + + case ST_SUPEREAGLE: + new_scaler = new SuperEagleScaler(buffer, width, height, col_table, col_table16, bmap); + break; + + case ST_SUPER2XSAI: + new_scaler = new Super2xSaIScaler(buffer, width, height, col_table, col_table16, bmap); + break; + + default: + warning("Invalid scaler requested - falling back to Super2xSaI"); + new_scaler = new Super2xSaIScaler(buffer, width, height, col_table, col_table16, bmap); + break; + } + + return new_scaler; +} + +bool MorphOSScaler::Prepare(BitMap *render_bmap) +{ + handle = LockBitMapTags(render_bmap, LBMI_BYTESPERPIX, &dest_bpp, + LBMI_BYTESPERROW, &dest_pitch, + LBMI_BASEADDRESS, &dest, + LBMI_PIXFMT, &dest_pixfmt, + TAG_DONE); + + return handle != NULL; +} + +void MorphOSScaler::Finish() +{ + if (handle) + { + UnLockBitMap(handle); + handle = NULL; + } +} + +uint32 MorphOSScaler::MakeColor(int pixfmt, int r, int g, int b) +{ + uint32 col = 0; + + switch (pixfmt) + { + case PIXFMT_RGB15: + case PIXFMT_RGB15PC: + col = (((r*31)/255) << 10) | (((g*31)/255) << 5) | ((b*31)/255); + break; + + case PIXFMT_BGR15: + case PIXFMT_BGR15PC: + col = (((b*31)/255) << 10) | (((g*31)/255) << 5) | ((r*31)/255); + break; + + case PIXFMT_RGB16: + case PIXFMT_RGB16PC: + col = (((r*31)/255) << 11) | (((g*63)/255) << 5) | ((b*31)/255); + break; + + case PIXFMT_BGR16: + case PIXFMT_BGR16PC: + col = (((b*31)/255) << 11) | (((g*63)/255) << 5) | ((r*31)/255); + break; + + case PIXFMT_ARGB32: + case PIXFMT_BGRA32: + col = (r << 16) | (g << 8) | b; + break; + + case PIXFMT_RGBA32: + col = (r << 24) | (g << 16) | (b << 8); + break; + + case PIXFMT_RGB24: + case PIXFMT_BGR24: + error("The scaling engines do not support 24 bit modes at the moment"); + break; + + default: + error("Unsupported pixel format: %d. Please contact author at tomjoad@muenster.de", pixfmt); + } + + return col; +} + +void Super2xSaIScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) +{ + unsigned int x, y; + unsigned long color[16]; + byte *src; + + if (!handle) + return; + + src = ((byte *)Buffer)+src_y*BufferWidth+src_x; + + /* Point to the first 3 lines. */ + src_line[0] = src; + src_line[1] = src; + src_line[2] = src + BufferWidth; + src_line[3] = src + BufferWidth * 2; + + dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; + dst_line[1] = dst_line[0]+dest_pitch; + + if (PixelsPerMask == 2) + { + byte *sbp; + sbp = src_line[0]; + color[0] = ScummColors16[*sbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; + color[4] = color[0]; color[5] = color[0]; color[6] = ScummColors16[*(sbp+1)]; color[7] = ScummColors16[*(sbp+2)]; + sbp = src_line[2]; + color[8] = ScummColors16[*sbp]; color[9] = color[8]; color[10] = ScummColors16[*(sbp+1)]; color[11] = ScummColors16[*(sbp+2)]; + sbp = src_line[3]; + color[12] = ScummColors16[*sbp]; color[13] = color[12]; color[14] = ScummColors16[*(sbp+1)]; color[15] = ScummColors16[*(sbp+2)]; + } + else + { + byte *lbp; + lbp = src_line[0]; + color[0] = ScummColors[*lbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; + color[4] = color[0]; color[5] = color[0]; color[6] = ScummColors[*(lbp+1)]; color[7] = ScummColors[*(lbp+2)]; + lbp = src_line[2]; + color[8] = ScummColors[*lbp]; color[9] = color[8]; color[10] = ScummColors[*(lbp+1)]; color[11] = ScummColors[*(lbp+2)]; + lbp = src_line[3]; + color[12] = ScummColors[*lbp]; color[13] = color[12]; color[14] = ScummColors[*(lbp+1)]; color[15] = ScummColors[*(lbp+2)]; + } + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + unsigned long product1a, product1b, product2a, product2b; + +//--------------------------------------- B0 B1 B2 B3 0 1 2 3 +// 4 5* 6 S2 -> 4 5* 6 7 +// 1 2 3 S1 8 9 10 11 +// A0 A1 A2 A3 12 13 14 15 +//-------------------------------------- + if (color[9] == color[6] && color[5] != color[10]) + { + product2b = color[9]; + product1b = product2b; + } + else if (color[5] == color[10] && color[9] != color[6]) + { + product2b = color[5]; + product1b = product2b; + } + else if (color[5] == color[10] && color[9] == color[6]) + { + int r = 0; + + r += GET_RESULT(color[6], color[5], color[8], color[13]); + r += GET_RESULT(color[6], color[5], color[4], color[1]); + r += GET_RESULT(color[6], color[5], color[14], color[11]); + r += GET_RESULT(color[6], color[5], color[2], color[7]); + + if (r > 0) + product1b = color[6]; + else if (r < 0) + product1b = color[5]; + else + product1b = INTERPOLATE(color[5], color[6]); + + product2b = product1b; + + } + else + { + if (color[6] == color[10] && color[10] == color[13] && color[9] != color[14] && color[10] != color[12]) + product2b = Q_INTERPOLATE(color[10], color[10], color[10], color[9]); + else if (color[5] == color[9] && color[9] == color[14] && color[13] != color[10] && color[9] != color[15]) + product2b = Q_INTERPOLATE(color[9], color[9], color[9], color[10]); + else + product2b = INTERPOLATE(color[9], color[10]); + + if (color[6] == color[10] && color[6] == color[1] && color[5] != color[2] && color[6] != color[0]) + product1b = Q_INTERPOLATE(color[6], color[6], color[6], color[5]); + else if (color[5] == color[9] && color[5] == color[2] && color[1] != color[6] && color[5] != color[3]) + product1b = Q_INTERPOLATE(color[6], color[5], color[5], color[5]); + else + product1b = INTERPOLATE(color[5], color[6]); + } + + if (color[5] == color[10] && color[9] != color[6] && color[4] == color[5] && color[5] != color[14]) + product2a = INTERPOLATE(color[9], color[5]); + else if (color[5] == color[8] && color[6] == color[5] && color[4] != color[9] && color[5] != color[12]) + product2a = INTERPOLATE(color[9], color[5]); + else + product2a = color[9]; + + if (color[9] == color[6] && color[5] != color[10] && color[8] == color[9] && color[9] != color[2]) + product1a = INTERPOLATE(color[9], color[5]); + else if (color[4] == color[9] && color[10] == color[9] && color[8] != color[5] && color[9] != color[0]) + product1a = INTERPOLATE(color[9], color[5]); + else + product1a = color[5]; + + if (PixelsPerMask == 2) + { + if (ScummPCMode) + { + SWAP_WORD(product1a); + SWAP_WORD(product1b); + SWAP_WORD(product2a); + SWAP_WORD(product2b); + } + *((unsigned long *) (&dst_line[0][x * 4])) = (product1a << 16) | product1b; + *((unsigned long *) (&dst_line[1][x * 4])) = (product2a << 16) | product2b; + } + else + { + if (ScummPCMode) + { + SWAP_LONG(product1a); + SWAP_LONG(product1b); + SWAP_LONG(product2a); + SWAP_LONG(product2b); + } + *((unsigned long *) (&dst_line[0][x * 8])) = product1a; + *((unsigned long *) (&dst_line[0][x * 8 + 4])) = product1b; + *((unsigned long *) (&dst_line[1][x * 8])) = product2a; + *((unsigned long *) (&dst_line[1][x * 8 + 4])) = product2b; + } + + /* Move color matrix forward */ + color[0] = color[1]; color[4] = color[5]; color[8] = color[9]; color[12] = color[13]; + color[1] = color[2]; color[5] = color[6]; color[9] = color[10]; color[13] = color[14]; + color[2] = color[3]; color[6] = color[7]; color[10] = color[11]; color[14] = color[15]; + + if (src_x+x < BufferWidth-3) + { + x += 3; + if (PixelsPerMask == 2) + { + color[3] = ScummColors16[*(src_line[0] + x) ]; + color[7] = ScummColors16[*(src_line[1] + x) ]; + color[11] = ScummColors16[*(src_line[2] + x) ]; + color[15] = ScummColors16[*(src_line[3] + x) ]; + } + else + { + color[3] = ScummColors[*(src_line[0] + x)]; + color[7] = ScummColors[*(src_line[1] + x)]; + color[11] = ScummColors[*(src_line[2] + x)]; + color[15] = ScummColors[*(src_line[3] + x)]; + } + x -= 3; + } + } + + /* We're done with one line, so we shift the source lines up */ + src_line[0] = src_line[1]; + src_line[1] = src_line[2]; + src_line[2] = src_line[3]; + + /* Read next line */ + if (src_y + y + 3 >= BufferHeight) + src_line[3] = src_line[2]; + else + src_line[3] = src_line[2] + BufferWidth; + + /* Then shift the color matrix up */ + if (PixelsPerMask == 2) + { + byte *sbp; + sbp = src_line[0]; + color[0] = ScummColors16[*sbp]; color[1] = color[0]; color[2] = ScummColors16[ *(sbp + 1) ]; color[3] = ScummColors16[*(sbp + 2)]; + sbp = src_line[1]; + color[4] = ScummColors16[*sbp]; color[5] = color[4]; color[6] = ScummColors16[ *(sbp + 1) ]; color[7] = ScummColors16[*(sbp + 2)]; + sbp = src_line[2]; + color[8] = ScummColors16[*sbp]; color[9] = color[8]; color[10] = ScummColors16[ *(sbp + 1) ]; color[11] = ScummColors16[*(sbp + 2)]; + sbp = src_line[3]; + color[12] = ScummColors16[*sbp]; color[13] = color[12]; color[14] = ScummColors16[ *(sbp + 1) ]; color[15] = ScummColors16[*(sbp + 2)]; + + if (src_x + x > 0) + { + color[0] = ScummColors16[src_line[0][-1]]; + color[4] = ScummColors16[src_line[1][-1]]; + color[8] = ScummColors16[src_line[2][-1]]; + color[12] = ScummColors16[src_line[3][-1]]; + } + } + else + { + byte *lbp; + lbp = src_line[0]; + color[0] = ScummColors[*lbp]; color[1] = color[0]; color[2] = ScummColors[ *(lbp + 1) ]; color[3] = ScummColors[*(lbp+2)]; + lbp = src_line[1]; + color[4] = ScummColors[*lbp]; color[5] = color[4]; color[6] = ScummColors[ *(lbp + 1) ]; color[7] = ScummColors[*(lbp+2)]; + lbp = src_line[2]; + color[8] = ScummColors[*lbp]; color[9] = color[8]; color[10] = ScummColors[ *(lbp + 1) ]; color[11] = ScummColors[*(lbp+2)]; + lbp = src_line[3]; + color[12] = ScummColors[*lbp]; color[13] = color[12]; color[14] = ScummColors[ *(lbp + 1) ]; color[15] = ScummColors[*(lbp+2)]; + } + + if (src_y + y < BufferHeight - 1) + { + dst_line[0] = dst_line[1]+dest_pitch; + dst_line[1] = dst_line[0]+dest_pitch; + } + } +} + +void SuperEagleScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) +{ + unsigned int x, y; + unsigned long color[12]; + byte *src; + + if (!handle) + return; + + src = (byte *)Buffer+src_y*BufferWidth+src_x; + + /* Point to the first 3 lines. */ + src_line[0] = src; + src_line[1] = src; + src_line[2] = src + BufferWidth; + src_line[3] = src + BufferWidth * 2; + + dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; + dst_line[1] = dst_line[0]+dest_pitch; + + x = 0, y = 0; + + if (PixelsPerMask == 2) + { + byte *sbp; + sbp = src_line[0]; + color[0] = ScummColors16[*sbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; + color[4] = ScummColors16[*(sbp+1)]; color[5] = ScummColors16[*(sbp+2)]; + sbp = src_line[2]; + color[6] = ScummColors16[*sbp]; color[7] = color[6]; color[8] = ScummColors16[*(sbp+1)]; color[9] = ScummColors16[*(sbp+2)]; + sbp = src_line[3]; + color[10] = ScummColors16[*sbp]; color[11] = ScummColors16[*(sbp+1)]; + } + else + { + byte *lbp; + lbp = src_line[0]; + color[0] = ScummColors[*lbp]; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; + color[4] = ScummColors[*(lbp+1)]; color[5] = ScummColors[*(lbp+2)]; + lbp = src_line[2]; + color[6] = ScummColors[*lbp]; color[7] = color[6]; color[8] = ScummColors[*(lbp+1)]; color[9] = ScummColors[*(lbp+2)]; + lbp = src_line[3]; + color[10] = ScummColors[*lbp]; color[11] = ScummColors[*(lbp+1)]; + } + + for (y = 0; y < height; y++) + { + /* Todo: x = width - 2, x = width - 1 */ + + for (x = 0; x < width; x++) + { + unsigned long product1a, product1b, product2a, product2b; + +//--------------------------------------- B1 B2 0 1 +// 4 5 6 S2 -> 2 3 4 5 +// 1 2 3 S1 6 7 8 9 +// A1 A2 10 11 + + if (color[7] == color[4] && color[3] != color[8]) + { + product1b = product2a = color[7]; + + if ((color[6] == color[7]) || (color[4] == color[1])) + product1a = INTERPOLATE(color[7], INTERPOLATE(color[7], color[3])); + else + product1a = INTERPOLATE(color[3], color[4]); + + if ((color[4] == color[5]) || (color[7] == color[10])) + product2b = INTERPOLATE(color[7], INTERPOLATE(color[7], color[8])); + else + product2b = INTERPOLATE(color[7], color[8]); + } + else if (color[3] == color[8] && color[7] != color[4]) + { + product2b = product1a = color[3]; + + if ((color[0] == color[3]) || (color[5] == color[9])) + product1b = INTERPOLATE(color[3], INTERPOLATE(color[3], color[4])); + else + product1b = INTERPOLATE(color[3], color[1]); + + if ((color[8] == color[11]) || (color[2] == color[3])) + product2a = INTERPOLATE(color[3], INTERPOLATE(color[3], color[2])); + else + product2a = INTERPOLATE(color[7], color[8]); + + } + else if (color[3] == color[8] && color[7] == color[4]) + { + register int r = 0; + + r += GET_RESULT(color[4], color[3], color[6], color[10]); + r += GET_RESULT(color[4], color[3], color[2], color[0]); + r += GET_RESULT(color[4], color[3], color[11], color[9]); + r += GET_RESULT(color[4], color[3], color[1], color[5]); + + if (r > 0) + { + product1b = product2a = color[7]; + product1a = product2b = INTERPOLATE(color[3], color[4]); + } + else if (r < 0) + { + product2b = product1a = color[3]; + product1b = product2a = INTERPOLATE(color[3], color[4]); + } + else + { + product2b = product1a = color[3]; + product1b = product2a = color[7]; + } + } + else + { + product2b = product1a = INTERPOLATE(color[7], color[4]); + product2b = Q_INTERPOLATE(color[8], color[8], color[8], product2b); + product1a = Q_INTERPOLATE(color[3], color[3], color[3], product1a); + + product2a = product1b = INTERPOLATE(color[3], color[8]); + product2a = Q_INTERPOLATE(color[7], color[7], color[7], product2a); + product1b = Q_INTERPOLATE(color[4], color[4], color[4], product1b); + } + + if (PixelsPerMask == 2) + { + if (ScummPCMode) + { + SWAP_WORD(product1a); + SWAP_WORD(product1b); + SWAP_WORD(product2a); + SWAP_WORD(product2b); + } + *((unsigned long *) (&dst_line[0][x * 4])) = (product1a << 16) | product1b; + *((unsigned long *) (&dst_line[1][x * 4])) = (product2a << 16) | product2b; + } + else + { + if (ScummPCMode) + { + SWAP_LONG(product1a); + SWAP_LONG(product1b); + SWAP_LONG(product2a); + SWAP_LONG(product2b); + } + *((unsigned long *) (&dst_line[0][x * 8])) = product1a; + *((unsigned long *) (&dst_line[0][x * 8 + 4])) = product1b; + *((unsigned long *) (&dst_line[1][x * 8])) = product2a; + *((unsigned long *) (&dst_line[1][x * 8 + 4])) = product2b; + } + + /* Move color matrix forward */ + color[0] = color[1]; + color[2] = color[3]; color[3] = color[4]; color[4] = color[5]; + color[6] = color[7]; color[7] = color[8]; color[8] = color[9]; + color[10] = color[11]; + + if (src_x+x < BufferWidth - 2) + { + x += 2; + if (PixelsPerMask == 2) + { + color[1] = ScummColors16[ *(src_line[0] + x) ]; + if (src_x+x < BufferWidth-1) + { + color[5] = ScummColors16[*(src_line[1]+x+1)]; + color[9] = ScummColors16[*(src_line[2]+x+1)]; + } + color[11] = ScummColors16[*(src_line[3]+x)]; + } + else + { + color[1] = ScummColors[*(src_line[0]+x)]; + if (src_x+x < BufferWidth-1) + { + color[5] = ScummColors[*(src_line[1]+x+1)]; + color[9] = ScummColors[ *(src_line[2]+x+1)]; + } + color[11] = ScummColors[*(src_line[3]+x)]; + } + x -= 2; + } + } + + /* We're done with one line, so we shift the source lines up */ + src_line[0] = src_line[1]; + src_line[1] = src_line[2]; + src_line[2] = src_line[3]; + + /* Read next line */ + if (src_y+y+3 >= BufferHeight) + src_line[3] = src_line[2]; + else + src_line[3] = src_line[2] + BufferWidth; + + /* Then shift the color matrix up */ + if (PixelsPerMask == 2) + { + byte *sbp; + sbp = src_line[0]; + color[0] = ScummColors16[*sbp]; color[1] = ScummColors16[*(sbp+1)]; + sbp = src_line[1]; + color[2] = ScummColors16[*sbp]; color[3] = color[2]; color[4] = ScummColors16[*(sbp+1)]; color[5] = ScummColors16[*(sbp+2)]; + sbp = src_line[2]; + color[6] = ScummColors16[*sbp]; color[7] = color[6]; color[8] = ScummColors16[*(sbp+1)]; color[9] = ScummColors16[*(sbp+2)]; + sbp = src_line[3]; + color[10] = ScummColors16[*sbp]; color[11] = ScummColors16[*(sbp+1)]; + } + else + { + byte *lbp; + lbp = src_line[0]; + color[0] = ScummColors[*lbp]; color[1] = ScummColors[*(lbp+1)]; + lbp = src_line[1]; + color[2] = ScummColors[*lbp]; color[3] = color[2]; color[4] = ScummColors[*(lbp+1)]; color[5] = ScummColors[*(lbp+2)]; + lbp = src_line[2]; + color[6] = ScummColors[*lbp]; color[7] = color[6]; color[8] = ScummColors[*(lbp+1)]; color[9] = ScummColors[*(lbp+2)]; + lbp = src_line[3]; + color[10] = ScummColors[*lbp]; color[11] = ScummColors[*(lbp+1)]; + } + + + if (src_y + y < BufferHeight - 1) + { + dst_line[0] = dst_line[1]+dest_pitch; + dst_line[1] = dst_line[0]+dest_pitch; + } + } +} + +void AdvMame2xScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) +{ + if (!handle) + return; + + byte *src = (byte *)Buffer+src_y*BufferWidth+src_x; + + src_line[0] = src; + src_line[1] = src; + src_line[2] = src + BufferWidth; + + dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; + dst_line[1] = dst_line[0]+dest_pitch; + + for (uint32 y = 0; y < height; y++) + { + for (uint32 x = 0; x < width; x++) + { + uint32 B, D, E, F, H; + + if (PixelsPerMask == 2) + { + // short A = *(src + i - nextlineSrc - 1); + B = ScummColors16[src_line[0][x]]; + // short C = *(src + i - nextlineSrc + 1); + D = ScummColors16[src_line[1][x-1]]; + E = ScummColors16[src_line[1][x]]; + F = ScummColors16[src_line[1][x+1]]; + // short G = *(src + i + nextlineSrc - 1); + H = ScummColors16[src_line[2][x]]; + // short I = *(src + i + nextlineSrc + 1); + } + else + { + // short A = *(src + i - nextlineSrc - 1); + B = ScummColors[src_line[0][x]]; + // short C = *(src + i - nextlineSrc + 1); + D = ScummColors[src_line[1][x-1]]; + E = ScummColors[src_line[1][x]]; + F = ScummColors[src_line[1][x+1]]; + // short G = *(src + i + nextlineSrc - 1); + H = ScummColors[src_line[2][x]]; + // short I = *(src + i + nextlineSrc + 1); + } + + + if (PixelsPerMask == 2) + { + if (ScummPCMode) + { + SWAP_WORD(B); + SWAP_WORD(D); + SWAP_WORD(E); + SWAP_WORD(F); + SWAP_WORD(H); + } + *((unsigned long *) (&dst_line[0][x * 4])) = ((D == B && B != F && D != H ? D : E) << 16) | (B == F && B != D && F != H ? F : E); + *((unsigned long *) (&dst_line[1][x * 4])) = ((D == H && D != B && H != F ? D : E) << 16) | (H == F && D != H && B != F ? F : E); + } + else + { + if (ScummPCMode) + { + SWAP_LONG(B); + SWAP_LONG(D); + SWAP_LONG(E); + SWAP_LONG(F); + SWAP_LONG(H); + } + *((unsigned long *) (&dst_line[0][x * 8])) = D == B && B != F && D != H ? D : E; + *((unsigned long *) (&dst_line[0][x * 8 + 4])) = B == F && B != D && F != H ? F : E; + *((unsigned long *) (&dst_line[1][x * 8])) = D == H && D != B && H != F ? D : E; + *((unsigned long *) (&dst_line[1][x * 8 + 4])) = H == F && D != H && B != F ? F : E; + } + } + + src_line[0] = src_line[1]; + src_line[1] = src_line[2]; + if (src_y+y+2 >= BufferHeight) + src_line[2] = src_line[1]; + else + src_line[2] = src_line[1] + BufferWidth; + + if (src_y+y < BufferHeight-1) + { + dst_line[0] = dst_line[1]+dest_pitch; + dst_line[1] = dst_line[0]+dest_pitch; + } + } +} + +void PointScaler::Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) +{ + byte *src; + uint32 color; + uint32 r, g, b; + uint32 x, y; + + if (!handle) + return; + + src = (byte *)Buffer+src_y*BufferWidth+src_x; + + dst_line[0] = dest+dest_y*2*dest_pitch+dest_x*2*dest_bpp; + dst_line[1] = dst_line[0]+dest_pitch; + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + r = (ScummColors[*(src+x)] >> 16) & 0xff; + g = (ScummColors[*(src+x)] >> 8) & 0xff; + b = ScummColors[*(src+x)] & 0xff; + + color = MakeColor(dest_pixfmt, r, g, b); + if (PixelsPerMask == 2) + { + if (ScummPCMode) + SWAP_WORD(color); + + *((unsigned long *) (&dst_line[0][x * 4])) = (color << 16) | color; + *((unsigned long *) (&dst_line[1][x * 4])) = (color << 16) | color; + } + else + { + if (ScummPCMode) + SWAP_LONG(color); + + *((unsigned long *) (&dst_line[0][x * 8])) = color; + *((unsigned long *) (&dst_line[0][x * 8 + 4])) = color; + *((unsigned long *) (&dst_line[1][x * 8])) = color; + *((unsigned long *) (&dst_line[1][x * 8 + 4])) = color; + } + } + + src += BufferWidth; + + if (src_y+y < BufferHeight-1) + { + dst_line[0] = dst_line[1]+dest_pitch; + dst_line[1] = dst_line[0]+dest_pitch; + } + } +} + +SCALERTYPE MorphOSScaler::FindByName(const char *ScalerName) +{ + int scaler = 0; + + while (ScummScalers[scaler].gs_Name) + { + if (!stricmp(ScalerName, ScummScalers[scaler].gs_Name)) + return ScummScalers[scaler].gs_Type; + scaler++; + } + + if (ScummScalers[scaler].gs_Name == NULL) + { + puts("Invalid scaler name. Please use one of the following:"); + for (scaler = 0; ScummScalers[scaler].gs_Name != NULL; scaler++) + printf(" %s\n", ScummScalers[scaler].gs_Name); + } + + return ST_INVALID; +} + +SCALERTYPE MorphOSScaler::FindByIndex(int index) +{ + if (index >= 0 && index < 10 && ScummScalers[index].gs_Name) + return ScummScalers[index].gs_Type; + + return ST_INVALID; +} + +const char *MorphOSScaler::GetParamName(SCALERTYPE type) +{ + int scaler = 0; + + while (ScummScalers[scaler].gs_Name) + { + if (ScummScalers[scaler].gs_Type == type) + return ScummScalers[scaler].gs_ParamName; + scaler++; + } + + return NULL; +} + diff --git a/backends/platform/morphos/morphos_scaler.h b/backends/platform/morphos/morphos_scaler.h new file mode 100644 index 0000000000..d794e361a6 --- /dev/null +++ b/backends/platform/morphos/morphos_scaler.h @@ -0,0 +1,94 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002-2006 The ScummVM Team + * + * 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 MORPHOS_MORPHOSSCALER_H +#define MORPHOS_MORPHOSSCALER_H + +#include + +typedef enum { ST_INVALID = 0, ST_NONE, ST_POINT, ST_ADVMAME2X, ST_SUPEREAGLE, ST_SUPER2XSAI } SCALERTYPE; + +class MorphOSScaler +{ + public: + MorphOSScaler(APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap); + virtual ~MorphOSScaler(); + + bool Prepare(BitMap *render_bmap); + void Finish(); + + virtual void Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height) = 0; + + static MorphOSScaler *Create(SCALERTYPE st, APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap); + + static SCALERTYPE FindByName(const char *ScalerName); + static SCALERTYPE FindByIndex(int index); + static const char *GetParamName(SCALERTYPE type); + + protected: + struct GfxScaler + { + STRPTR gs_Name; + STRPTR gs_ParamName; + SCALERTYPE gs_Type; + }; + + static GfxScaler ScummScalers[11]; + + static uint32 MakeColor(int pixfmt, int r, int g, int b); + + byte *dest; + uint32 dest_bpp; + uint32 dest_pitch; + uint32 dest_pixfmt; + APTR handle; + + uint32 colorMask; + uint32 lowPixelMask; + uint32 qcolorMask; + uint32 qlowpixelMask; + uint32 redblueMask; + uint32 greenMask; + int PixelsPerMask; + byte *src_line[4]; + byte *dst_line[2]; + bool ScummPCMode; + + APTR Buffer; + ULONG BufferWidth; + ULONG BufferHeight; + ULONG *ScummColors; + USHORT *ScummColors16; +}; + +#define DECLARE_SCALER(scaler_name) class scaler_name ## Scaler : public MorphOSScaler \ + { public: scaler_name ## Scaler(APTR buffer, int width, int height, ULONG *col_table, UWORD *col_table16, BitMap *bmap) : MorphOSScaler(buffer, width, height, col_table, col_table16, bmap) {} \ + void Scale(uint32 src_x, uint32 src_y, uint32 dest_x, uint32 dest_y, uint32 width, uint32 height); \ + }; + + +DECLARE_SCALER(Point) +DECLARE_SCALER(AdvMame2x) +DECLARE_SCALER(SuperEagle) +DECLARE_SCALER(Super2xSaI) + +#endif + diff --git a/backends/platform/morphos/morphos_sound.cpp b/backends/platform/morphos/morphos_sound.cpp new file mode 100644 index 0000000000..c5c2f3b7ad --- /dev/null +++ b/backends/platform/morphos/morphos_sound.cpp @@ -0,0 +1,254 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 Rüdiger Hanke + * + * 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. + * + * MorphOS sound support + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "base/engine.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "morphos.h" +#include "morphos_sound.h" + +#define AHI_BUF_SIZE (8*1024) + +SignalSemaphore ScummMusicThreadRunning; +SignalSemaphore ScummSoundThreadRunning; + +static MsgPort *ahiPort = NULL; +static AHIRequest *ahiReq[2] = { NULL, NULL }; +static UWORD ahiCurBuf = 0; +static bool ahiReqSent[2] = { false, false }; +static BYTE ahiDevice = -1; + UBYTE ahiUnit = AHI_DEFAULT_UNIT; +static char *ahiBuf[2] = { NULL, NULL }; + +static MsgPort *ScummMidiPort = NULL; + IOMidiRequest *ScummMidiRequest = NULL; + + Device *EtudeBase = NULL; + +bool etude_available() +{ + bool avail = init_morphos_music(ScummMidiUnit, ETUDEF_DIRECT); + if (avail) + exit_morphos_music(); + return avail; +} + +bool init_morphos_music(ULONG MidiUnit, ULONG DevFlags) +{ + ScummMidiPort = CreateMsgPort(); + if (ScummMidiPort) + { + ScummMidiRequest = (IOMidiRequest *) CreateIORequest(ScummMidiPort, sizeof (IOMidiRequest)); + if (ScummMidiRequest) + { + ScummMidiRequest->emr_Version = 1; + if (OpenDevice(ETUDENAME, MidiUnit, (IORequest *) ScummMidiRequest, DevFlags)) + { + DeleteIORequest((IORequest *) ScummMidiRequest); + DeleteMsgPort(ScummMidiPort); + ScummMidiRequest = NULL; + ScummMidiPort = NULL; + } + else + EtudeBase = ScummMidiRequest->emr_Std.io_Device; + } + else + { + DeleteMsgPort(ScummMidiPort); + ScummMidiPort = NULL; + } + } + + if (!ScummMidiRequest) + return false; + + return true; +} + + +void exit_morphos_music() +{ + if (ScummMidiRequest) + { + CloseDevice((IORequest *) ScummMidiRequest); + DeleteIORequest((IORequest *) ScummMidiRequest); + DeleteMsgPort(ScummMidiPort); + ScummMidiRequest = NULL; + ScummMidiPort = NULL; + EtudeBase = NULL; + } +} + + +static bool init_morphos_sound() +{ + if (!(ahiPort = CreateMsgPort())) + return false; + + if (!(ahiReq[0] = (AHIRequest *) CreateIORequest(ahiPort, sizeof (AHIRequest)))) + { + DeleteMsgPort(ahiPort); + ahiPort = NULL; + return false; + } + + if (!(ahiReq[1] = (AHIRequest *) AllocVec(sizeof (AHIRequest), MEMF_PUBLIC))) + { + DeleteIORequest(ahiReq[0]); + DeleteMsgPort(ahiPort); + ahiReq[0] = NULL; + ahiPort = NULL; + return false; + } + + if (!(ahiBuf[0] = (char *) AllocVec(2*AHI_BUF_SIZE, MEMF_PUBLIC))) + { + FreeVec(ahiReq[1]); + DeleteIORequest(ahiReq[0]); + DeleteMsgPort(ahiPort); + ahiReq[0] = NULL; + ahiReq[1] = NULL; + ahiPort = NULL; + return false; + } + ahiBuf[1] = &ahiBuf[0][AHI_BUF_SIZE]; + + ahiReq[0]->ahir_Version = 4; + if ((ahiDevice = OpenDevice(AHINAME, 0, (IORequest *) ahiReq[0], 0))) + { + FreeVec(ahiBuf[0]); + FreeVec(ahiReq[1]); + DeleteIORequest(ahiReq[0]); + DeleteMsgPort(ahiPort); + ahiBuf[0] = NULL; + ahiReq[0] = NULL; + ahiReq[1] = NULL; + ahiPort = NULL; + return false; + } + + CopyMem(ahiReq[0], ahiReq[1], sizeof (AHIRequest)); + + ahiCurBuf = 0; + ahiReqSent[0] = FALSE; + ahiReqSent[1] = FALSE; + + return true; +} + + +static void exit_morphos_sound() +{ + if (ahiReq[1]) + FreeVec(ahiReq[1]); + + if (ahiReq[0]) + { + CloseDevice((IORequest *) ahiReq[0]); + DeleteIORequest(ahiReq[0]); + } + + if (ahiBuf[0]) + FreeVec((APTR) ahiBuf[0]); + + if (ahiPort) + DeleteMsgPort(ahiPort); +} + +int morphos_sound_thread(OSystem_MorphOS *syst, ULONG SampleType) +{ + ULONG signals; + bool initialized; + + initialized = init_morphos_sound(); + if (!initialized) + { + warning("Sound could not be initialized. The game may hang at some point (press Ctrl-z then)."); + Wait(SIGBREAKF_CTRL_C); + } + else + { + for (;;) + { + while (!ahiReqSent[ahiCurBuf] || CheckIO((IORequest *) ahiReq[ahiCurBuf])) + { + AHIRequest *req = ahiReq[ahiCurBuf]; + UWORD ahiOtherBuf = !ahiCurBuf; + + if (ahiReqSent[ahiCurBuf]) + WaitIO((IORequest *) req); + + syst->fill_sound((byte *) ahiBuf[ahiCurBuf], AHI_BUF_SIZE); + + req->ahir_Std.io_Message.mn_Node.ln_Pri = 0; + req->ahir_Std.io_Command = CMD_WRITE; + req->ahir_Std.io_Data = ahiBuf[ahiCurBuf]; + req->ahir_Std.io_Length = AHI_BUF_SIZE; + req->ahir_Type = SampleType; + req->ahir_Frequency = SAMPLES_PER_SEC; + req->ahir_Position = 0x8000; + req->ahir_Volume = 0x10000; + req->ahir_Link = (ahiReqSent[ahiOtherBuf] && !CheckIO((IORequest *) ahiReq[ahiOtherBuf])) ? ahiReq[ahiOtherBuf] : NULL; + SendIO((IORequest *)req); + + ahiReqSent[ahiCurBuf] = true; + ahiCurBuf = ahiOtherBuf; + } + + signals = Wait(SIGBREAKF_CTRL_C | (1 << ahiPort->mp_SigBit)); + + if (signals & SIGBREAKF_CTRL_C) + break; + } + + if (ahiReqSent[ahiCurBuf]) + { + AbortIO((IORequest *) ahiReq[ahiCurBuf]); + WaitIO((IORequest *) ahiReq[ahiCurBuf]); + ahiReqSent[ahiCurBuf] = false; + } + + if (ahiReqSent[!ahiCurBuf]) + { + AbortIO((IORequest *) ahiReq[!ahiCurBuf]); + WaitIO((IORequest *) ahiReq[!ahiCurBuf]); + ahiReqSent[!ahiCurBuf] = false; + } + } + + exit_morphos_sound(); + + return 0; +} + diff --git a/backends/platform/morphos/morphos_sound.h b/backends/platform/morphos/morphos_sound.h new file mode 100644 index 0000000000..a2d211a37f --- /dev/null +++ b/backends/platform/morphos/morphos_sound.h @@ -0,0 +1,43 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 Rüdiger Hanke (MorphOS port) + * + * 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. + * + * MorphOS-specific header file + * + * $URL$ + * $Id$ + * + */ + +#ifndef MORPHOS_SOUND_H +#define MORPHOS_SOUND_H + +#include +#include + +class OSystem_MorphOS; + +int morphos_sound_thread(OSystem_MorphOS *syst, ULONG SampleType); +bool init_morphos_music(ULONG MidiUnit, ULONG DevFlags); +void exit_morphos_music(); +bool etude_available(); + +extern STRPTR ScummMusicDriver; +extern LONG ScummMidiUnit; +extern IOMidiRequest *ScummMidiRequest; + +#endif + diff --git a/backends/platform/morphos/morphos_start.cpp b/backends/platform/morphos/morphos_start.cpp new file mode 100644 index 0000000000..ac5c16ad85 --- /dev/null +++ b/backends/platform/morphos/morphos_start.cpp @@ -0,0 +1,444 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002 Rüdiger Hanke (MorphOS port) + * + * 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. + * + * MorphOS startup handling + * + * $URL$ + * $Id$ + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "common/stdafx.h" +#include "scumm/scumm.h" +#include "base/main.h" +#include "common/scaler.h" +#include "sound/mididrv.h" +#include "morphos.h" +#include "morphos_scaler.h" +#include "morphos_sound.h" + +extern "C" WBStartup *_WBenchMsg; + +// For command line parsing +static STRPTR usageTemplate = "STORY,DATAPATH/K,WINDOW/S,SCALER/K,AMIGA/S,MIDIUNIT/K/N,MUSIC/K,MASTERVOL/K/N,MUSICVOL/K/N,SFXVOL/K/N,TEMPO/K/N,TALKSPEED/K/N,LANGUAGE/K,NOSUBTITLES=NST/S, DEBUGLEVEL=DBGLVL/K/N, DUMPSCRIPTS/S"; +typedef enum { USG_STORY = 0, USG_DATAPATH, USG_WINDOW, USG_SCALER, USG_AMIGA, USG_MIDIUNIT, USG_MUSIC, USG_MASTERVOL, USG_MUSICVOL, USG_SFXVOL, USG_TEMPO, USG_TALKSPEED, USG_LANGUAGE, USG_NOSUBTITLES, USG_DEBUGLEVEL, USG_DUMPSCRIPTS, USG_MAX } usageFields; +static LONG args[USG_MAX]; +static RDArgs *ScummArgs = NULL; + +static char*ScummStory = NULL; +static char*ScummPath = NULL; +static char*ScummLang = NULL; + STRPTR ScummMusicDriver = NULL; +MidiDriver* EtudeMidiDriver = NULL; + LONG ScummMidiUnit = 0; +static LONG ScummMasterVolume = 0; +static LONG ScummMidiVolume = 0; +static LONG ScummMidiTempo = 0; +static LONG ScummSfxVolume = 0; +static LONG ScummTalkSpeed = 0; +static LONG ScummDebugLevel = 0; +static SCALERTYPE ScummGfxScaler = ST_INVALID; + +static BPTR OrigDirLock = 0; + +Library *CDDABase = NULL; +Library *TimerBase = NULL; + +OSystem_MorphOS *TheSystem = NULL; + +OSystem *OSystem_MorphOS_create() +{ + if (TheSystem) + delete TheSystem; + + TheSystem = OSystem_MorphOS::create(ST_NONE, ConfMan.getBool("fullscreen")); + + return TheSystem; +} + +void close_resources() +{ + delete TheSystem; + TheSystem = NULL; + + if (ScummPath) + { + FreeVec(ScummPath); + ScummPath = NULL; + } + + if (ScummStory) + { + FreeVec(ScummStory); + ScummStory = NULL; + } + + if (ScummArgs) + { + FreeArgs(ScummArgs); + ScummArgs = NULL; + } + + if (OrigDirLock) + { + CurrentDir(OrigDirLock); + OrigDirLock = NULL; + } + + if (CDDABase) + { + CloseLibrary(CDDABase); + CDDABase = NULL; + } +} + +static STRPTR FindMusicDriver(STRPTR argval) +{ + if (!stricmp(argval, "off")) return "-enull"; + if (!stricmp(argval, "midi")) return "-eetude"; + if (!stricmp(argval, "adlib")) return "-eadlib"; + + error("No such music driver supported. Possible values are off, Midi and Adlib."); + return NULL; +} + +static void ReadToolTypes(WBArg *OfFile) +{ + DiskObject *dobj; + char *ToolValue; + char IconPath[256]; + + NameFromLock(OfFile->wa_Lock, IconPath, 256); + AddPart(IconPath, (STRPTR) OfFile->wa_Name, 256); + + dobj = GetDiskObject(IconPath); + if (dobj == NULL) + return; + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "STORY"); + if (ToolValue) + { + if (ScummStory) + FreeVec(ScummStory); + ScummStory = (char *) AllocVec(strlen(ToolValue)+1, MEMF_PUBLIC); + strcpy(ScummStory, ToolValue); + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "DATAPATH"); + if (ToolValue) + { + if (ScummPath) + FreeVec(ScummPath); + ScummPath = (char *) AllocVec(strlen(ToolValue)+4, MEMF_PUBLIC); + strcpy(ScummPath, "-p"); + strcat(ScummPath, ToolValue); + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "WINDOW"); + if (ToolValue) + { + if (MatchToolValue(ToolValue, "YES")) + args[USG_WINDOW] = TRUE; + else if (MatchToolValue(ToolValue, "NO")) + args[USG_WINDOW] = FALSE; + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "SCALER"); + if (ToolValue) + { + if ((ScummGfxScaler = MorphOSScaler::FindByName(ToolValue)) == ST_INVALID) + { + FreeDiskObject(dobj); + exit(1); + } + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MUSIC"); + if (ToolValue) + { + if (!(ScummMusicDriver = FindMusicDriver(ToolValue))) + { + FreeDiskObject(dobj); + exit(1); + } + args[USG_MUSIC] = (ULONG) &ScummMusicDriver; + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MIDIUNIT"); + if (ToolValue) + ScummMidiUnit = atoi(ToolValue); + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MASTERVOL"); + if (ToolValue) + { + int vol = atoi(ToolValue); + if (vol >= 0 && vol <= 100) + { + ScummMasterVolume = vol; + args[USG_MASTERVOL] = (ULONG) &ScummMasterVolume; + } + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "MUSICVOL"); + if (ToolValue) + { + int vol = atoi(ToolValue); + if (vol >= 0 && vol <= 100) + { + ScummMidiVolume = vol; + args[USG_MUSICVOL] = (ULONG) &ScummMidiVolume; + } + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "SFXVOL"); + if (ToolValue) + { + int vol = atoi(ToolValue); + if (vol >= 0 && vol <= 255) + { + ScummSfxVolume = vol; + args[USG_SFXVOL] = (ULONG) &ScummSfxVolume; + } + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "TEMPO"); + if (ToolValue) + { + ScummMidiTempo = atoi(ToolValue); + args[USG_TEMPO] = (ULONG) &ScummMidiTempo; + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "TALKSPEED"); + if (ToolValue) + { + ScummTalkSpeed = atoi(ToolValue); + args[USG_TALKSPEED] = (ULONG) &ScummMidiTempo; + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "LANGUAGE"); + if (ToolValue) + { + if (ScummLang) + FreeVec(ScummLang); + ScummLang = (char *) AllocVec(strlen(ToolValue)+4, MEMF_PUBLIC); + strcpy(ScummLang, "-q"); + strcat(ScummLang, ToolValue); + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "SUBTITLES"); + if (ToolValue) + { + if (MatchToolValue(ToolValue, "YES")) + args[USG_NOSUBTITLES] = FALSE; + else if (MatchToolValue(ToolValue, "NO")) + args[USG_NOSUBTITLES] = TRUE; + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "AMIGA"); + if (ToolValue) + { + if (MatchToolValue(ToolValue, "YES")) + args[USG_AMIGA] = FALSE; + else if (MatchToolValue(ToolValue, "NO")) + args[USG_AMIGA] = TRUE; + } + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "DEBUGLEVEL"); + if (ToolValue) + ScummDebugLevel = atoi(ToolValue); + + ToolValue = (char *) FindToolType(dobj->do_ToolTypes, "DUMPSCRIPTS"); + if (ToolValue) + { + if (MatchToolValue(ToolValue, "YES")) + args[USG_DUMPSCRIPTS] = TRUE; + else if (MatchToolValue(ToolValue, "NO")) + args[USG_DUMPSCRIPTS] = FALSE; + } + + FreeDiskObject(dobj); +} + +#undef main + +int main() +{ + char *argv[30]; + char mastervol[6], musicvol[6], sfxvol[6], talkspeed[12], tempo[12], scaler[14]; + char dbglvl[6]; + int argc = 0; + + atexit(&close_resources); + + memset(args, '\0', sizeof (args)); + if (_WBenchMsg == NULL) + { + /* Parse the command line here */ + ScummArgs = ReadArgs(usageTemplate, args, NULL); + if (ScummArgs == NULL) + { + puts("Error in command line - type \"ScummVM ?\" for usage."); + exit(1); + } + + if (args[USG_STORY]) + { + ScummStory = (char *) AllocVec(strlen((char *) args[USG_STORY])+1, MEMF_PUBLIC); + strcpy(ScummStory, (char *) args[USG_STORY]); + } + + if (args[USG_DATAPATH]) + { + ScummPath = (char *) AllocVec(strlen((char *) args[USG_DATAPATH])+4, MEMF_PUBLIC); + strcpy(ScummPath, "-p"); + strcat(ScummPath, (char *) args[USG_DATAPATH]); + } + + if (args[USG_SCALER]) + { + if ((ScummGfxScaler = MorphOSScaler::FindByName((char *) args[USG_SCALER])) == ST_INVALID) + exit(1); + } + + if (args[USG_MUSIC]) + { + if (!(ScummMusicDriver = FindMusicDriver((char *) args[USG_MUSIC]))) + exit(1); + } + + if (args[USG_MIDIUNIT]) + ScummMidiUnit = *((LONG *) args[USG_MIDIUNIT]); + + if (args[USG_TEMPO]) + ScummMidiTempo = *((LONG *) args[USG_TEMPO]); + + if (args[USG_MASTERVOL]) + ScummMasterVolume = *((LONG *) args[USG_MASTERVOL]); + + if (args[USG_MUSICVOL]) + ScummMidiVolume = *((LONG *) args[USG_MUSICVOL]); + + if (args[USG_SFXVOL]) + ScummSfxVolume = *((LONG *) args[USG_SFXVOL]); + + if (args[USG_TALKSPEED]) + ScummTalkSpeed = *((LONG *) args[USG_TALKSPEED]); + + if (args[USG_LANGUAGE]) + { + ScummLang = (char *) AllocVec(strlen((char *) args[USG_LANGUAGE])+4, MEMF_PUBLIC); + strcpy(ScummLang, "-q"); + strcat(ScummLang, (char *) args[USG_LANGUAGE]); + } + + if (args[USG_DEBUGLEVEL]) + ScummDebugLevel = *((LONG *) args[USG_DEBUGLEVEL]); + } + else + { + /* We've been started from Workbench */ + ReadToolTypes(&_WBenchMsg->sm_ArgList[0]); + if (_WBenchMsg->sm_NumArgs > 1) + { + ReadToolTypes(&_WBenchMsg->sm_ArgList[1]); + OrigDirLock = CurrentDir(_WBenchMsg->sm_ArgList[1].wa_Lock); + } + } + + if (ScummPath) + { + char c = ScummPath[strlen(ScummPath)-1]; + if (c != '/' && c != ':') + strcat(ScummPath, "/"); + } + + argv[argc++] = "ScummVM"; + if (ScummPath) argv[argc++] = ScummPath; + if (!args[USG_WINDOW]) argv[argc++] = "-f"; + if (args[USG_NOSUBTITLES]) argv[argc++] = "-n"; + if (args[USG_AMIGA]) argv[argc++] = "-a"; + if (args[USG_MUSIC]) argv[argc++] = ScummMusicDriver; + else + { + if (etude_available()) + argv[argc++] = "-eetude"; + else + argv[argc++] = "-eadlib"; + } + if (ScummGfxScaler != ST_INVALID) + { + sprintf(scaler, "-g%s", MorphOSScaler::GetParamName(ScummGfxScaler)); + argv[argc++] = scaler; + } + else + argv[argc++] = "-gsuper2xsai"; + if (args[USG_MASTERVOL] && ScummMasterVolume >= 0 && ScummMasterVolume <= 255) + { + sprintf(mastervol, "-o%ld", ScummMasterVolume); + argv[argc++] = mastervol; + } + if (args[USG_MUSICVOL] && ScummMidiVolume >= 0 && ScummMidiVolume <= 255) + { + sprintf(musicvol, "-m%ld", ScummMidiVolume); + argv[argc++] = musicvol; + } + if (args[USG_SFXVOL] && ScummSfxVolume >= 0 && ScummSfxVolume <= 255) + { + sprintf(sfxvol, "-s%ld", ScummSfxVolume); + argv[argc++] = sfxvol; + } + if (args[USG_TEMPO] && ScummMidiTempo > 0) + { + sprintf(tempo, "-t%lx", ScummMidiTempo); + argv[argc++] = tempo; + } + if (args[USG_TALKSPEED] && ScummTalkSpeed >= 0 && ScummTalkSpeed <= 255) + { + sprintf(talkspeed, "-y%ld", ScummTalkSpeed); + argv[argc++] = talkspeed; + } + if (ScummLang) argv[argc++] = ScummLang; + if (args[USG_DUMPSCRIPTS]) argv[argc++] = "-u"; + if (args[USG_DEBUGLEVEL]) + { + sprintf(dbglvl, "-d%ld", ScummDebugLevel); + argv[argc++] = dbglvl; + } + if (ScummStory) + argv[argc++] = ScummStory; + + g_system = OSystem_MorphOS_create(); + assert(g_system); + + // Invoke the actual ScummVM main entry point: + int res = scummvm_main(argc, argv); + g_system->quit(); // TODO: Consider removing / replacing this! + return res; +} + diff --git a/backends/platform/morphos/morphos_timer.cpp b/backends/platform/morphos/morphos_timer.cpp new file mode 100644 index 0000000000..b558c7fd66 --- /dev/null +++ b/backends/platform/morphos/morphos_timer.cpp @@ -0,0 +1,234 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002-2006 The ScummVM Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "common/stdafx.h" +#include "base/engine.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "morphos.h" +#include "timer.h" + +Timer::Timer(Engine * engine) +{ + if ((TimerServicePort = CreateMsgPort())) + { + TimerServiceStartup.mn_Node.ln_Type = NT_MESSAGE; + TimerServiceStartup.mn_ReplyPort = TimerServicePort; + TimerServiceStartup.mn_Length = sizeof(TimerServiceStartup); + + TimerServiceThread = CreateNewProcTags(NP_Entry, (ULONG) TimerService, + NP_CodeType, CODETYPE_PPC, + NP_Name, (ULONG) "ScummVM Timer Service", + NP_Priority, 0, + NP_StartupMsg, &TimerServiceStartup, + NP_PPC_Arg1, (ULONG) this, + NP_PPC_Arg2, (ULONG) engine, + TAG_DONE + ); + } +} + +Timer::~Timer() +{ + if (TimerServiceThread) + { + Signal((Task *) TimerServiceThread, SIGBREAKF_CTRL_C); + WaitPort(TimerServicePort); + DeleteMsgPort(TimerServicePort); + TimerServiceThread = NULL; + } +} + +bool Timer::init() +{ + return TimerServiceThread != NULL; +} + +void Timer::release() +{ +} + +bool Timer::installTimerProc(TimerProc procedure, int32 interval) +{ + return SendMsg(TSM_MSGID_ADDTIMER, procedure, interval); +} + +void Timer::removeTimerProc(TimerProc procedure) +{ + SendMsg(TSM_MSGID_REMTIMER, procedure, 0); +} + +bool Timer::SendMsg(ULONG msg_id, TimerProc procedure, LONG interval) +{ + if (TimerServiceThread == NULL) + return false; + + TimerServiceMessage *tmsg = (TimerServiceMessage *) AllocVec(sizeof (TimerServiceMessage), MEMF_PUBLIC | MEMF_CLEAR); + if (tmsg == NULL) + return false; + + tmsg->tsm_Message.mn_Node.ln_Type = NT_MESSAGE; + tmsg->tsm_Message.mn_ReplyPort = NULL; + tmsg->tsm_Message.mn_Length = sizeof (TimerServiceMessage); + tmsg->tsm_MsgID = msg_id; + tmsg->tsm_Callback = procedure; + tmsg->tsm_Interval = interval; + PutMsg(&TimerServiceThread->pr_MsgPort, (Message*) tmsg); + + return true; +} + +void Timer::TimerService(Timer *this_ptr, Engine *engine) +{ + MsgPort *port = &((Process *) FindTask(NULL))->pr_MsgPort; + ULONG port_bit = 1 << port->mp_SigBit; + ULONG signal_mask = SIGBREAKF_CTRL_C | port_bit; + ULONG timer_bits = 0, signals; + ULONG interval, t; + timeval start_callback, end_callback; + + ULONG timers = 0; + TimerSlot timer_slots[MAX_TIMERS]; + + for (;;) + { + signals = Wait(signal_mask); + + GetSysTime(&start_callback); + + if (signals & port_bit) + { + TimerServiceMessage *tmsg; + + while ((tmsg = (TimerServiceMessage *) GetMsg(port))) + { + if (tmsg->tsm_Message.mn_Length == sizeof (TimerServiceMessage)) + { + switch (tmsg->tsm_MsgID) + { + case TSM_MSGID_ADDTIMER: + if (timers < MAX_TIMERS) + { + ULONG unit = UNIT_MICROHZ; + + if (tmsg->tsm_Interval >= 1000000) + unit = UNIT_VBLANK; + if (OSystem_MorphOS::OpenATimer(&timer_slots[timers].ts_Port, (IORequest **) &timer_slots[timers].ts_IORequest, unit)) + { + timer_slots[timers].ts_Callback = tmsg->tsm_Callback; + timer_slots[timers].ts_Interval = tmsg->tsm_Interval; + timer_slots[timers].ts_SignalBit = 1 << timer_slots[timers].ts_Port->mp_SigBit; + + signal_mask |= timer_slots[timers].ts_SignalBit; + timer_bits |= timer_slots[timers].ts_SignalBit; + + timerequest *req = timer_slots[timers].ts_IORequest; + interval = timer_slots[timers].ts_Interval; + req->tr_node.io_Command = TR_ADDREQUEST; + req->tr_time.tv_secs = interval/1000000; + req->tr_time.tv_micro = interval%1000000; + SendIO((IORequest*) req); + + timers++; + } + } + break; + + case TSM_MSGID_REMTIMER: + { + for (t = 0; t < timers; t++) + { + if (timer_slots[t].ts_Callback == tmsg->tsm_Callback) + { + AbortIO((IORequest *) timer_slots[t].ts_IORequest); + WaitIO((IORequest *) timer_slots[t].ts_IORequest); + signal_mask &= ~timer_slots[t].ts_SignalBit; + timer_bits &= ~timer_slots[t].ts_SignalBit; + CloseDevice((IORequest *) timer_slots[t].ts_IORequest); + DeleteIORequest((IORequest *) timer_slots[t].ts_IORequest); + DeleteMsgPort(timer_slots[t].ts_Port); + if (t < timers-1) + memmove(&timer_slots[t], &timer_slots[t+1], sizeof (TimerSlot)*(timers-t-1)); + timers--; + continue; + } + } + break; + } + + default: + warning("MorphOS TimerService received message of unknown type."); + } + } + + if (tmsg->tsm_Message.mn_ReplyPort) + ReplyMsg((Message *) tmsg); + else + FreeVec((Message *) tmsg); + } + } + + if (signals & SIGBREAKF_CTRL_C) + break; + + if (signals & timer_bits) + { + for (t = 0; t < timers; t++) + { + if (signals & timer_slots[t].ts_SignalBit) + { + timerequest *req = timer_slots[t].ts_IORequest; + WaitIO((IORequest *) req); + interval = timer_slots[t].ts_Interval; + (*timer_slots[t].ts_Callback)(engine); + GetSysTime(&end_callback); + SubTime(&end_callback, &start_callback); + interval -= end_callback.tv_sec*1000000+end_callback.tv_micro/1000000+40000; + if (interval < 0) + interval = 0; + + req->tr_node.io_Command = TR_ADDREQUEST; + req->tr_time.tv_secs = interval/1000000; + req->tr_time.tv_micro = interval%1000000; + SendIO((IORequest*) req); + } + } + } + } + + for (t = 0; t < timers; t++) + { + AbortIO((IORequest *) timer_slots[t].ts_IORequest); + WaitIO((IORequest *) timer_slots[t].ts_IORequest); + CloseDevice((IORequest *) timer_slots[t].ts_IORequest); + DeleteIORequest((IORequest *) timer_slots[t].ts_IORequest); + DeleteMsgPort(timer_slots[t].ts_Port); + } +} + diff --git a/backends/platform/morphos/morphos_timer.h b/backends/platform/morphos/morphos_timer.h new file mode 100644 index 0000000000..1ab3259b39 --- /dev/null +++ b/backends/platform/morphos/morphos_timer.h @@ -0,0 +1,88 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2002-2006 The ScummVM Team + * + * 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 MORPHOS_TIMER_H +#define MORPHOS_TIMER_H + +#ifndef TIMER_H +#include "timer.h" // for MAX_TIMER +#endif + +#ifndef EXEC_PORTS_H +#include +#endif + +#ifndef EXEC_IO_H +#include +#endif + +#ifndef EXEC_SEMAPHORES_H +#include +#endif + +#ifndef DOS_DOSEXTENS_H +#include +#endif + +class OSystem; + +#define TSM_MSGID_ADDTIMER 0 +#define TSM_MSGID_REMTIMER 1 + +struct TimerServiceMessage +{ + Message tsm_Message; + ULONG tsm_MsgID; + TimerProc tsm_Callback; + LONG tsm_Interval; +}; + +class Timer +{ + public: + Timer(Engine * engine); + ~Timer(); + + bool init(); + void release(); + bool installTimerProc(TimerProc procedure, int32 interval); + void removeTimerProc(TimerProc procedure); + + protected: + bool SendMsg(ULONG MsgID, TimerProc procedure, LONG interval); + static void TimerService(Timer *, Engine *); + + Process *TimerServiceThread; + MsgPort *TimerServicePort; + Message TimerServiceStartup; + + struct TimerSlot + { + MsgPort *ts_Port; + timerequest *ts_IORequest; + ULONG ts_SignalBit; + TimerProc ts_Callback; + LONG ts_Interval; + }; +}; + +#endif + diff --git a/backends/platform/null/module.mk b/backends/platform/null/module.mk new file mode 100644 index 0000000000..12a2cbc510 --- /dev/null +++ b/backends/platform/null/module.mk @@ -0,0 +1,10 @@ +MODULE := backends/platform/null + +MODULE_OBJS := \ + null.o + +MODULE_DIRS += \ + backends/platform/null/ + +# We don't use the rules.mk here on purpose +OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) diff --git a/backends/platform/null/null.cpp b/backends/platform/null/null.cpp new file mode 100644 index 0000000000..f9943ef448 --- /dev/null +++ b/backends/platform/null/null.cpp @@ -0,0 +1,263 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "common/scummsys.h" +#include "common/system.h" + +#if defined(USE_NULL_DRIVER) + +#include "common/rect.h" +#include "common/savefile.h" + +class OSystem_NULL : public OSystem { +public: + static OSystem *instance(); + +public: + + OSystem_NULL(); + virtual ~OSystem_NULL(); + + virtual bool hasFeature(Feature f); + virtual void setFeatureState(Feature f, bool enable); + virtual bool getFeatureState(Feature f); + virtual const GraphicsMode *getSupportedGraphicsModes() const; + virtual int getDefaultGraphicsMode() const; + bool setGraphicsMode(const char *name); + virtual int getGraphicsMode() const; + virtual void initSize(uint width, uint height); + virtual int16 getHeight(); + virtual int16 getWidth(); + virtual void setPalette(const byte *colors, uint start, uint num); + virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); + virtual void updateScreen(); + virtual void setShakePos(int shakeOffset); + + virtual void showOverlay(); + virtual void hideOverlay(); + virtual void clearOverlay(); + virtual void grabOverlay(OverlayColor *buf, int pitch); + virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); + virtual int16 getOverlayHeight(); + virtual int16 getOverlayWidth(); + + virtual OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b); + virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b); + + virtual bool showMouse(bool visible); + + virtual void warpMouse(int x, int y); + virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor = 255); + + virtual bool pollEvent(Event &event); + virtual uint32 getMillis(); + virtual void delayMillis(uint msecs); + + virtual void setTimerCallback(TimerProc callback, int interval); + + virtual MutexRef createMutex(void); + virtual void lockMutex(MutexRef mutex); + virtual void unlockMutex(MutexRef mutex); + virtual void deleteMutex(MutexRef mutex); + + virtual bool setSoundCallback(SoundProc proc, void *param); + virtual void clearSoundCallback(); + virtual int getOutputSampleRate() const; + + virtual bool openCD(int drive); + virtual bool pollCD(); + + virtual void playCD(int track, int num_loops, int start_frame, int duration); + virtual void stopCD(); + virtual void updateCD(); + + virtual void quit(); + + virtual void setWindowCaption(const char *caption); +}; + +static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {0, 0, 0} +}; + +int main(int argc, char *argv[]) { + g_system = OSystem_NULL_create(); + assert(g_system); + + // Invoke the actual ScummVM main entry point: + int res = scummvm_main(argc, argv); + g_system->quit(); // TODO: Consider removing / replacing this! + return res; +} + +OSystem_NULL::OSystem_NULL() { +} + +OSystem_NULL::~OSystem_NULL() { +} + +bool OSystem_NULL::hasFeature(Feature f) { + return false; +} + +void OSystem_NULL::setFeatureState(Feature f, bool enable) { +} + +bool OSystem_NULL::getFeatureState(Feature f) { + return false; +} + +const OSystem::GraphicsMode* OSystem_NULL::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + + +int OSystem_NULL::getDefaultGraphicsMode() const { + return -1; +} + +bool OSystem_NULL::setGraphicsMode(int mode) { + return true; +} + +int OSystem_NULL::getGraphicsMode() const { + return -1; +} + +void OSystem_NULL::initSize(uint width, uint height) { +} + +int16 OSystem_NULL::getHeight() { + return 320; +} + +int16 OSystem_NULL::getWidth() { + return 200; +} + +void OSystem_NULL::setPalette(const byte *colors, uint start, uint num) { +} + +void OSystem_NULL::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { +} + +void OSystem_NULL::updateScreen() { +} + +void OSystem_NULL::setShakePos(int shakeOffset) { +} + +void OSystem_NULL::showOverlay () { +} + +void OSystem_NULL::hideOverlay () { +} + +void OSystem_NULL::clearOverlay () { +} + +void OSystem_NULL::grabOverlay (OverlayColor *buf, int pitch) { +} + +void OSystem_NULL::copyRectToOverlay (const OverlayColor *buf, int pitch, int x, int y, int w, int h) { +} + +int16 OSystem_NULL::getOverlayHeight() { + return getHeight(); +} + +int16 OSystem_NULL::getOverlayWidth() { + return getWidth(); +} + +OverlayColor OSystem_NULL::RGBToColor(uint8 r, uint8 g, uint8 b) { + return 0; +} + +void OSystem_NULL::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b) { +} + +bool OSystem_NULL::showMouse(bool visible) { + return true; +} + +void OSystem_NULL::warpMouse(int x, int y) { +} + +void OSystem_NULL::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, byte keycolor) { +} + +bool OSystem_NULL::pollEvent(Event &event) { + return false; +} + +uint32 OSystem_NULL::getMillis() { + return 0; +} + +void OSystem_NULL::delayMillis(uint msecs) { +} + +void OSystem_NULL::setTimerCallback(TimerProc callback, int interval) { +} + +OSystem::MutexRef OSystem_NULL::createMutex(void) { + return NULL; +} + +void OSystem_NULL::lockMutex(MutexRef mutex) { +} + +void OSystem_NULL::unlockMutex(MutexRef mutex) { +} + +void OSystem_NULL::deleteMutex(MutexRef mutex) { +} + +bool OSystem_NULL::setSoundCallback(SoundProc proc, void *param) { + return true; +} + +void OSystem_NULL::clearSoundCallback() { +} + +int OSystem_NULL::getOutputSampleRate() const { + return 22050; +} + +void OSystem_NULL::quit() { +} + +void OSystem_NULL::setWindowCaption(const char *caption) { +} + +OSystem *OSystem_NULL_create() { + return new OSystem_NULL(); +} +#else /* USE_NULL_DRIVER */ + +OSystem *OSystem_NULL_create() { + return NULL; +} + +#endif diff --git a/backends/platform/sdl/build.rules b/backends/platform/sdl/build.rules new file mode 100644 index 0000000000..14cfe0ebdf --- /dev/null +++ b/backends/platform/sdl/build.rules @@ -0,0 +1,9 @@ +# Build settings for the SDL backend +MODULES += backends/sdl +DEFINES += -DUNIX +INCLUDES += `sdl-config --cflags` +LIBS += `sdl-config --libs` + +# Uncomment this in addition to the above if you compile on Mac OS X +# DEFINES += -DMACOSX +# LIBS += -framework QuickTime -framework AudioUnit diff --git a/backends/platform/sdl/events.cpp b/backends/platform/sdl/events.cpp new file mode 100644 index 0000000000..4fa02907db --- /dev/null +++ b/backends/platform/sdl/events.cpp @@ -0,0 +1,510 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "backends/platform/sdl/sdl-common.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 3200 + +#ifndef __SYMBIAN32__ // Symbian wants dialog joystick i.e cursor for movement/selection + #define JOY_ANALOG +#endif + +// #define JOY_INVERT_Y +#define JOY_XAXIS 0 +#define JOY_YAXIS 1 +// buttons +#define JOY_BUT_LMOUSE 0 +#define JOY_BUT_RMOUSE 2 +#define JOY_BUT_ESCAPE 3 +#define JOY_BUT_PERIOD 1 +#define JOY_BUT_SPACE 4 +#define JOY_BUT_F5 5 + + + + +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_SDL::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_SDL::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; +} + +bool OSystem_SDL::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; + return true; + } + + 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); +#ifdef USE_OSD + if (_fullscreen) + displayMessageOnOSD("Fullscreen mode"); + else + displayMessageOnOSD("Windowed mode"); +#endif + + 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- 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- 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; + + case SDL_JOYBUTTONDOWN: + if (ev.jbutton.button == JOY_BUT_LMOUSE) { + 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 { + event.type = EVENT_KEYDOWN; + switch (ev.jbutton.button) { + case JOY_BUT_ESCAPE: + event.kbd.keycode = SDLK_ESCAPE; + event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); + break; + case JOY_BUT_PERIOD: + event.kbd.keycode = SDLK_PERIOD; + event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0); + break; + case JOY_BUT_SPACE: + event.kbd.keycode = SDLK_SPACE; + event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); + break; + case JOY_BUT_F5: + event.kbd.keycode = SDLK_F5; + event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); + break; + } + } + return true; + + case SDL_JOYBUTTONUP: + 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 { + event.type = EVENT_KEYUP; + switch (ev.jbutton.button) { + case JOY_BUT_ESCAPE: + event.kbd.keycode = SDLK_ESCAPE; + event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); + break; + case JOY_BUT_PERIOD: + event.kbd.keycode = SDLK_PERIOD; + event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0); + break; + case JOY_BUT_SPACE: + event.kbd.keycode = SDLK_SPACE; + event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); + break; + case JOY_BUT_F5: + event.kbd.keycode = SDLK_F5; + event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); + 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_SDL::remapKey(SDL_Event &ev,Event &event) { +#ifdef LINUPY + // On Yopy map the End button to quit + if ((ev.key.keysym.sym == 293)) { + event.type = EVENT_QUIT; + return true; + } + // Map menu key to f5 (scumm menu) + if (ev.key.keysym.sym == 306) { + event.type = EVENT_KEYDOWN; + event.kbd.keycode = SDLK_F5; + event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); + return true; + } + // Map action key to action + if (ev.key.keysym.sym == 291) { + event.type = EVENT_KEYDOWN; + event.kbd.keycode = SDLK_TAB; + event.kbd.ascii = mapKey(SDLK_TAB, ev.key.keysym.mod, 0); + return true; + } + // Map OK key to skip cinematic + if (ev.key.keysym.sym == 292) { + event.type = EVENT_KEYDOWN; + event.kbd.keycode = SDLK_ESCAPE; + event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); + return true; + } +#endif + +#ifdef QTOPIA + // Quit on fn+backspace on zaurus + if (ev.key.keysym.sym == 127) { + event.type = EVENT_QUIT; + return true; + } + + // Map menu key (f11) to f5 (scumm menu) + if (ev.key.keysym.sym == SDLK_F11) { + event.type = EVENT_KEYDOWN; + event.kbd.keycode = SDLK_F5; + event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); + } + // Nap center (space) to tab (default action ) + // I wanted to map the calendar button but the calendar comes up + // + else if (ev.key.keysym.sym == SDLK_SPACE) { + event.type = EVENT_KEYDOWN; + event.kbd.keycode = SDLK_TAB; + event.kbd.ascii = mapKey(SDLK_TAB, ev.key.keysym.mod, 0); + } + // Since we stole space (pause) above we'll rebind it to the tab key on the keyboard + else if (ev.key.keysym.sym == SDLK_TAB) { + event.type = EVENT_KEYDOWN; + event.kbd.keycode = SDLK_SPACE; + event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); + } else { + // Let the events fall through if we didn't change them, this may not be the best way to + // set it up, but i'm not sure how sdl would like it if we let if fall through then redid it though. + // and yes i have an huge terminal size so i dont wrap soon enough. + 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); + } +#endif + return false; +} + diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp new file mode 100644 index 0000000000..eb560c5769 --- /dev/null +++ b/backends/platform/sdl/graphics.cpp @@ -0,0 +1,1745 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "backends/platform/sdl/sdl-common.h" +#include "common/util.h" +#include "graphics/font.h" +#include "graphics/fontman.h" +#include "graphics/scaler.h" +#include "graphics/surface.h" + +static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {"1x", "Normal (no scaling)", GFX_NORMAL}, + {"2x", "2x", GFX_DOUBLESIZE}, + {"3x", "3x", GFX_TRIPLESIZE}, + {"2xsai", "2xSAI", GFX_2XSAI}, + {"super2xsai", "Super2xSAI", GFX_SUPER2XSAI}, + {"supereagle", "SuperEagle", GFX_SUPEREAGLE}, + {"advmame2x", "AdvMAME2x", GFX_ADVMAME2X}, + {"advmame3x", "AdvMAME3x", GFX_ADVMAME3X}, +#ifndef DISABLE_HQ_SCALERS + {"hq2x", "HQ2x", GFX_HQ2X}, + {"hq3x", "HQ3x", GFX_HQ3X}, +#endif + {"tv2x", "TV2x", GFX_TV2X}, + {"dotmatrix", "DotMatrix", GFX_DOTMATRIX}, + {0, 0, 0} +}; + +// Table of relative scalers magnitudes +// [definedScale - 1][_scaleFactor - 1] +static ScalerProc *scalersMagn[3][3] = { +#ifndef DISABLE_SCALERS + { Normal1x, AdvMame2x, AdvMame3x }, + { Normal1x, Normal1x, Normal1o5x }, + { Normal1x, Normal1x, Normal1x } +#else // remove dependencies on other scalers + { Normal1x, Normal1x, Normal1x }, + { Normal1x, Normal1x, Normal1x }, + { Normal1x, Normal1x, Normal1x } +#endif +}; + +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 } + }; + +#ifndef DISABLE_SCALERS +static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY); +#endif + +const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +int OSystem_SDL::getDefaultGraphicsMode() const { + return GFX_DOUBLESIZE; +} + +void OSystem_SDL::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_SDL::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_SDL::setGraphicsMode(int mode) { + Common::StackLock lock(_graphicsMutex); + + int newScaleFactor = 1; + ScalerProc *newScalerProc; + + switch(mode) { + case GFX_NORMAL: + newScaleFactor = 1; + newScalerProc = Normal1x; + break; +#ifndef DISABLE_SCALERS + case GFX_DOUBLESIZE: + newScaleFactor = 2; + newScalerProc = Normal2x; + break; + case GFX_TRIPLESIZE: + newScaleFactor = 3; + newScalerProc = Normal3x; + break; + + case GFX_2XSAI: + newScaleFactor = 2; + newScalerProc = _2xSaI; + break; + case GFX_SUPER2XSAI: + newScaleFactor = 2; + newScalerProc = Super2xSaI; + break; + case GFX_SUPEREAGLE: + newScaleFactor = 2; + newScalerProc = SuperEagle; + break; + case GFX_ADVMAME2X: + newScaleFactor = 2; + newScalerProc = AdvMame2x; + break; + case GFX_ADVMAME3X: + newScaleFactor = 3; + newScalerProc = AdvMame3x; + break; +#ifndef DISABLE_HQ_SCALERS + case GFX_HQ2X: + newScaleFactor = 2; + newScalerProc = HQ2x; + break; + case GFX_HQ3X: + newScaleFactor = 3; + newScalerProc = HQ3x; + break; +#endif + case GFX_TV2X: + newScaleFactor = 2; + newScalerProc = TV2x; + break; + case GFX_DOTMATRIX: + newScaleFactor = 2; + newScalerProc = DotMatrix; + break; +#endif // DISABLE_SCALERS + + default: + warning("unknown gfx mode %d", mode); + return false; + } + + _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_SDL::getGraphicsMode() const { + assert (_transactionMode == kTransactionNone); + return _mode; +} + +void OSystem_SDL::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_SDL::loadGFXMode() { + 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 scaled graphics in 16 bit mode + // + + _hwscreen = SDL_SetVideoMode(hwW, hwH, 16, + _fullscreen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE + ); + if (_hwscreen == NULL) { + // DON'T use error(), as this tries to bring up the debug + // console, which WON'T WORK now that _hwscreen is hosed. + + // FIXME: We should be able to continue the game without + // shutting down or bringing up the debug console, but at + // this point we've already screwed up all our member vars. + // We need to find a way to call SDL_SetVideoMode *before* + // that happens and revert to all the old settings if we + // can't pull off the switch to the new settings. + // + // Fingolfin says: the "easy" way to do that is not to modify + // the member vars before we are sure everything is fine. Think + // of "transactions, commit, rollback" style... we use local vars + // in place of the member vars, do everything etc. etc.. In case + // of a failure, rollback is trivial. Only if everything worked fine + // do we "commit" the changed values to the member vars. + warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError()); + quit(); + } + + // + // 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"); + +#ifdef USE_OSD + _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); +#endif + + // 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_SDL::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; + } + +#ifdef USE_OSD + if (_osdSurface) { + SDL_FreeSurface(_osdSurface); + _osdSurface = NULL; + } +#endif +} + +void OSystem_SDL::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); + +#ifdef USE_OSD + // Release the OSD surface + SDL_FreeSurface(_osdSurface); +#endif + + // 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_SDL::updateScreen() { + assert (_transactionMode == kTransactionNone); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + internUpdateScreen(); +} + +void OSystem_SDL::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 (_paletteDirtyEnd != 0) { + SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, + _paletteDirtyStart, + _paletteDirtyEnd - _paletteDirtyStart); + + _paletteDirtyEnd = 0; + + _forceFull = true; + } + +#ifdef USE_OSD + // 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; + } + } +#endif + + 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(); + +#ifdef USE_OSD + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); + } +#endif + // 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_SDL::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_SDL::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_SDL::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_SDL::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_SDL::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_SDL::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_SDL::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_SDL::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). + // 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_SDL::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_SDL::getHeight() { + return _screenHeight; +} + +int16 OSystem_SDL::getWidth() { + return _screenWidth; +} + +void OSystem_SDL::setPalette(const byte *colors, uint start, uint num) { + assert(colors); + 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_SDL::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_SDL::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_SDL::setShakePos(int shake_pos) { + assert (_transactionMode == kTransactionNone); + + _newShakePos = shake_pos; +} + + +#pragma mark - +#pragma mark --- Overlays --- +#pragma mark - + +void OSystem_SDL::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_SDL::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_SDL::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_SDL::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_SDL::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_SDL::RGBToColor(uint8 r, uint8 g, uint8 b) { + return SDL_MapRGB(_overlayscreen->format, r, g, b); +} + +void OSystem_SDL::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_SDL::showMouse(bool visible) { + if (_mouseVisible == visible) + return visible; + + bool last = _mouseVisible; + _mouseVisible = visible; + + return last; +} + +void OSystem_SDL::setMousePos(int x, int y) { + if (x != _mouseCurState.x || y != _mouseCurState.y) { + _mouseCurState.x = x; + _mouseCurState.y = y; + } +} + +void OSystem_SDL::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_SDL::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_SDL::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); + +#ifndef DISABLE_SCALERS + if (_adjustAspectRatio && _cursorTargetScale == 1) + cursorStretch200To240((uint8 *)_mouseSurface->pixels, _mouseSurface->pitch, rW, rH1, 0, 0, 0); +#endif + + SDL_UnlockSurface(_mouseSurface); + SDL_UnlockSurface(_mouseOrigSurface); +} + +#ifndef DISABLE_SCALERS +// 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; +} +#endif + +void OSystem_SDL::toggleMouseGrab() { + if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) + SDL_WM_GrabInput(SDL_GRAB_ON); + else + SDL_WM_GrabInput(SDL_GRAB_OFF); +} + +void OSystem_SDL::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_SDL::drawMouse() { + if (!_mouseVisible || !_mouseSurface) { + _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0; + return; + } + + SDL_Rect dst; + int scale; + int width, height; + int hotX, hotY; + + 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; + + // 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 - + +#ifdef USE_OSD +void OSystem_SDL::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; +} +#endif + + +#pragma mark - +#pragma mark --- Misc --- +#pragma mark - + +void OSystem_SDL::handleScalerHotkeys(const SDL_KeyboardEvent &key) { + // Ctrl-Alt-a toggles aspect ratio correction + if (key.keysym.sym == 'a') { + setFeatureState(kFeatureAspectRatioCorrection, !_adjustAspectRatio); +#ifdef USE_OSD + 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); +#endif + + 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); +#ifdef USE_OSD + 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); + } + } +#endif + + } + +} diff --git a/backends/platform/sdl/module.mk b/backends/platform/sdl/module.mk new file mode 100644 index 0000000000..18e56bc4fe --- /dev/null +++ b/backends/platform/sdl/module.mk @@ -0,0 +1,12 @@ +MODULE := backends/platform/sdl + +MODULE_OBJS := \ + events.o \ + graphics.o \ + sdl.o + +MODULE_DIRS += \ + backends/platform/sdl/ + +# We don't use the rules.mk here on purpose +OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) diff --git a/backends/platform/sdl/sdl-common.h b/backends/platform/sdl/sdl-common.h new file mode 100644 index 0000000000..f4c9383c63 --- /dev/null +++ b/backends/platform/sdl/sdl-common.h @@ -0,0 +1,392 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * 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 SDL_COMMON_H +#define SDL_COMMON_H + +#include + +#include "common/stdafx.h" +#include "common/scummsys.h" +#include "common/system.h" +#include "graphics/scaler.h" +#include "backends/intern.h" + + +#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) +// Uncomment this to enable the 'on screen display' code. +#define USE_OSD 1 +#endif + + +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_SDL : public OSystem { +public: + OSystem_SDL(); + virtual ~OSystem_SDL(); + + virtual void initBackend(); + + void beginGFXTransaction(void); + void endGFXTransaction(void); + + // Set the size of the video bitmap. + // Typically, 320x200 + virtual void initSize(uint w, uint h); // overloaded by CE backend + + // 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 + virtual void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); // overloaded by CE backend (FIXME) + + // 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. + virtual void warpMouse(int x, int y); // overloaded by CE backend (FIXME) + + // Set the bitmap that's used when drawing the cursor. + virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale); // overloaded by CE backend (FIXME) + + // 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 + virtual void showOverlay(); // WinCE FIXME + virtual void hideOverlay(); // WinCE FIXME + virtual void clearOverlay(); + virtual void grabOverlay(OverlayColor *buf, int pitch); + virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); // WinCE FIXME + virtual int16 getHeight(); + virtual int16 getWidth(); + virtual int16 getOverlayHeight() { return _overlayHeight; } + virtual int16 getOverlayWidth() { return _overlayWidth; } + + // Methods that convert RGB to/from colors suitable for the overlay. + virtual OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b); + virtual 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); + +#ifdef USE_OSD + void displayMessageOnOSD(const char *msg); +#endif + +protected: + bool _inited; + +#ifdef USE_OSD + 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 + }; +#endif + + // 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; + + /** True if aspect ratio correction is enabled. */ + bool _adjustAspectRatio; + + 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; + byte _mouseKeyColor; + int _cursorTargetScale; + bool _cursorPaletteDisabled; + SDL_Surface *_mouseOrigSurface; + SDL_Surface *_mouseSurface; + enum { + kMouseColorKey = 1 + }; + + // joystick + SDL_Joystick *_joystick; + + // 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); // overloaded by CE backend + + virtual void drawMouse(); // overloaded by CE backend + virtual void undrawMouse(); // overloaded by CE backend (FIXME) + virtual void blitCursor(); // overloaded by CE backend (FIXME) + + /** Set the position of the virtual mouse cursor. */ + void setMousePos(int x, int y); + virtual void fillMouseEvent(Event &event, int x, int y); // overloaded by CE backend + void toggleMouseGrab(); + + virtual void internUpdateScreen(); // overloaded by CE backend + + virtual void loadGFXMode(); // overloaded by CE backend + virtual void unloadGFXMode(); // overloaded by CE backend + virtual void hotswapGFXMode(); // overloaded by CE backend + + void setFullscreenMode(bool enable); + void setAspectRatioCorrection(bool enable); + + virtual bool saveScreenshot(const char *filename); // overloaded by CE backend + + 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); +}; + +#endif diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp new file mode 100644 index 0000000000..b6d2d675df --- /dev/null +++ b/backends/platform/sdl/sdl.cpp @@ -0,0 +1,488 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "backends/platform/sdl/sdl-common.h" +#include "common/config-manager.h" +#include "common/util.h" +#include "base/main.h" + +#include "icons/scummvm.xpm" + +#if defined(__SYMBIAN32__) +#include "SymbianOs.h" +#endif + +#if !defined(_WIN32_WCE) && !defined(__MAEMO__) + +#if defined (WIN32) +int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpCmdLine*/, int /*iShowCmd*/) { + SDL_SetModuleHandle(GetModuleHandle(NULL)); + return main(__argc, __argv); +} +#endif + +int main(int argc, char *argv[]) { + +#if defined(__SYMBIAN32__) + // + // Set up redirects for stdout/stderr under Windows and Symbian. + // Code copied from SDL_main. + // + + // Symbian does not like any output to the console through any *print* function + char STDOUT_FILE[256], STDERR_FILE[256]; // shhh, don't tell anybody :) + strcpy(STDOUT_FILE, Symbian::GetExecutablePath()); + strcpy(STDERR_FILE, Symbian::GetExecutablePath()); + strcat(STDOUT_FILE, "scummvm.stdout.txt"); + strcat(STDERR_FILE, "scummvm.stderr.txt"); + + /* Flush the output in case anything is queued */ + fclose(stdout); + fclose(stderr); + + /* Redirect standard input and standard output */ + FILE *newfp = freopen(STDOUT_FILE, "w", stdout); + if (newfp == NULL) { /* This happens on NT */ +#if !defined(stdout) + stdout = fopen(STDOUT_FILE, "w"); +#else + newfp = fopen(STDOUT_FILE, "w"); + if (newfp) { + *stdout = *newfp; + } +#endif + } + newfp = freopen(STDERR_FILE, "w", stderr); + if (newfp == NULL) { /* This happens on NT */ +#if !defined(stderr) + stderr = fopen(STDERR_FILE, "w"); +#else + newfp = fopen(STDERR_FILE, "w"); + if (newfp) { + *stderr = *newfp; + } +#endif + } + setbuf(stderr, NULL); /* No buffering */ + +#endif // defined(__SYMBIAN32__) + + // Create our OSystem instance +#if defined(__SYMBIAN32__) + g_system = new OSystem_SDL_Symbian(); +#else + g_system = new OSystem_SDL(); +#endif + assert(g_system); + + // Invoke the actual ScummVM main entry point: + int res = scummvm_main(argc, argv); + g_system->quit(); // TODO: Consider removing / replacing this! + return res; +} +#endif + +void OSystem_SDL::initBackend() { + assert(!_inited); + + 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; + +#ifdef _WIN32_WCE + if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) { + SDL_VideoInit("windib", 0); + sdlFlags ^= SDL_INIT_VIDEO; + } +#endif + + if (joystick_num > -1) + sdlFlags |= SDL_INIT_JOYSTICK; + + if (SDL_Init(sdlFlags) == -1) { + error("Could not initialize SDL: %s", SDL_GetError()); + } + + _graphicsMutex = createMutex(); + + SDL_ShowCursor(SDL_DISABLE); + + // Enable unicode support if possible + SDL_EnableUNICODE(1); + + _cksumValid = false; +#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) && !defined(DISABLE_SCALERS) + _mode = GFX_DOUBLESIZE; + _scaleFactor = 2; + _scalerProc = Normal2x; + _fullscreen = ConfMan.getBool("fullscreen"); + _adjustAspectRatio = ConfMan.getBool("aspect_ratio"); +#else // for small screen platforms + _mode = GFX_NORMAL; + _scaleFactor = 1; + _scalerProc = Normal1x; + +#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) + _fullscreen = ConfMan.getBool("fullscreen"); +#else + _fullscreen = true; +#endif + + _adjustAspectRatio = false; +#endif + _scalerType = 0; + _modeFlags = 0; + +#if !defined(MACOSX) && !defined(__SYMBIAN32__) // Don't set icon on OS X, as we use a nicer external icon there + setupIcon(); // Don't for Symbian: it uses the EScummVM.aif file for the icon +#endif + + // enable joystick + if (joystick_num > -1 && SDL_NumJoysticks() > 0) { + printf("Using joystick: %s\n", SDL_JoystickName(0)); + _joystick = SDL_JoystickOpen(joystick_num); + } + + _inited = true; +} + +OSystem_SDL::OSystem_SDL() + : +#ifdef USE_OSD + _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0), +#endif + _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), _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_SDL::~OSystem_SDL() { + free(_dirtyChecksums); + free(_currentPalette); + free(_cursorPalette); + free(_mouseData); +} + +uint32 OSystem_SDL::getMillis() { + return SDL_GetTicks(); +} + +void OSystem_SDL::delayMillis(uint msecs) { + SDL_Delay(msecs); +} + +void OSystem_SDL::setTimerCallback(TimerProc callback, int timer) { + SDL_SetTimer(timer, (SDL_TimerCallback) callback); +} + +void OSystem_SDL::setWindowCaption(const char *caption) { + SDL_WM_SetCaption(caption, caption); +} + +bool OSystem_SDL::hasFeature(Feature f) { + return + (f == kFeatureFullscreenMode) || + (f == kFeatureAspectRatioCorrection) || + (f == kFeatureAutoComputeDirtyRects) || + (f == kFeatureCursorHasPalette); +} + +void OSystem_SDL::setFeatureState(Feature f, bool enable) { + switch (f) { + case kFeatureFullscreenMode: + setFullscreenMode(enable); + break; + 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_SDL::getFeatureState(Feature f) { + assert (_transactionMode == kTransactionNone); + + switch (f) { + case kFeatureFullscreenMode: + return _fullscreen; + case kFeatureAspectRatioCorrection: + return _adjustAspectRatio; + case kFeatureAutoComputeDirtyRects: + return _modeFlags & DF_WANT_RECT_OPTIM; + default: + return false; + } +} + +void OSystem_SDL::quit() { + if (_cdrom) { + SDL_CDStop(_cdrom); + SDL_CDClose(_cdrom); + } + unloadGFXMode(); + deleteMutex(_graphicsMutex); + + if (_joystick) + SDL_JoystickClose(_joystick); + SDL_ShowCursor(SDL_ENABLE); + SDL_Quit(); + + exit(0); +} + +void OSystem_SDL::setupIcon() { + int w, h, ncols, nbytes, i; + unsigned int rgba[256], icon[32 * 32]; + unsigned char mask[32][4]; + + sscanf(scummvm_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes); + if ((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1)) { + warning("Could not load the icon (%d %d %d %d)", w, h, ncols, nbytes); + return; + } + for (i = 0; i < ncols; i++) { + unsigned char code; + char color[32]; + unsigned int col; + sscanf(scummvm_icon[1 + i], "%c c %s", &code, color); + if (!strcmp(color, "None")) + col = 0x00000000; + else if (!strcmp(color, "black")) + col = 0xFF000000; + else if (color[0] == '#') { + sscanf(color + 1, "%06x", &col); + col |= 0xFF000000; + } else { + warning("Could not load the icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]); + return; + } + + rgba[code] = col; + } + memset(mask, 0, sizeof(mask)); + for (h = 0; h < 32; h++) { + const char *line = scummvm_icon[1 + ncols + h]; + for (w = 0; w < 32; w++) { + icon[w + 32 * h] = rgba[(int)line[w]]; + if (rgba[(int)line[w]] & 0xFF000000) { + mask[h][w >> 3] |= 1 << (7 - (w & 0x07)); + } + } + } + + SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); + SDL_WM_SetIcon(sdl_surf, (unsigned char *) mask); + SDL_FreeSurface(sdl_surf); +} + +OSystem::MutexRef OSystem_SDL::createMutex(void) { + return (MutexRef) SDL_CreateMutex(); +} + +void OSystem_SDL::lockMutex(MutexRef mutex) { + SDL_mutexP((SDL_mutex *) mutex); +} + +void OSystem_SDL::unlockMutex(MutexRef mutex) { + SDL_mutexV((SDL_mutex *) mutex); +} + +void OSystem_SDL::deleteMutex(MutexRef mutex) { + SDL_DestroyMutex((SDL_mutex *) mutex); +} + +#pragma mark - +#pragma mark --- Audio --- +#pragma mark - + +bool OSystem_SDL::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; + + // Originally, we always used 2048 samples. This loop will produce the + // same result at 22050 Hz, and should hopefully produce something + // sensible for other frequencies. Note that it must be a power of two. + + uint32 samples = 0x8000; + + for (;;) { + if ((1000 * samples) / _samplesPerSec < 100) + break; + samples >>= 1; + } + + desired.freq = _samplesPerSec; + desired.format = AUDIO_S16SYS; + desired.channels = 2; + desired.samples = (uint16)samples; + desired.callback = proc; + desired.userdata = param; + if (SDL_OpenAudio(&desired, &obtained) != 0) { + warning("Could not open audio device: %s", SDL_GetError()); + return false; + } + // Note: This should be the obtained output rate, but it seems that at + // least on some platforms SDL will lie and claim it did get the rate + // even if it didn't. Probably only happens for "weird" rates, though. + _samplesPerSec = obtained.freq; + SDL_PauseAudio(0); + return true; +} + +void OSystem_SDL::clearSoundCallback() { + SDL_CloseAudio(); +} + +int OSystem_SDL::getOutputSampleRate() const { + return _samplesPerSec; +} + +#pragma mark - +#pragma mark --- CD Audio --- +#pragma mark - + +bool OSystem_SDL::openCD(int drive) { + if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1) + _cdrom = NULL; + else { + _cdrom = SDL_CDOpen(drive); + // Did it open? Check if _cdrom is NULL + if (!_cdrom) { + warning("Couldn't open drive: %s", SDL_GetError()); + } else { + _cdNumLoops = 0; + _cdStopTime = 0; + _cdEndTime = 0; + } + } + + return (_cdrom != NULL); +} + +void OSystem_SDL::stopCD() { /* Stop CD Audio in 1/10th of a second */ + _cdStopTime = SDL_GetTicks() + 100; + _cdNumLoops = 0; +} + +void OSystem_SDL::playCD(int track, int num_loops, int start_frame, int duration) { + if (!num_loops && !start_frame) + return; + + if (!_cdrom) + return; + + if (duration > 0) + duration += 5; + + _cdTrack = track; + _cdNumLoops = num_loops; + _cdStartFrame = start_frame; + + SDL_CDStatus(_cdrom); + if (start_frame == 0 && duration == 0) + SDL_CDPlayTracks(_cdrom, track, 0, 1, 0); + else + SDL_CDPlayTracks(_cdrom, track, start_frame, 0, duration); + _cdDuration = duration; + _cdStopTime = 0; + _cdEndTime = SDL_GetTicks() + _cdrom->track[track].length * 1000 / CD_FPS; +} + +bool OSystem_SDL::pollCD() { + if (!_cdrom) + return false; + + return (_cdNumLoops != 0 && (SDL_GetTicks() < _cdEndTime || SDL_CDStatus(_cdrom) != CD_STOPPED)); +} + +void OSystem_SDL::updateCD() { + if (!_cdrom) + return; + + if (_cdStopTime != 0 && SDL_GetTicks() >= _cdStopTime) { + SDL_CDStop(_cdrom); + _cdNumLoops = 0; + _cdStopTime = 0; + return; + } + + if (_cdNumLoops == 0 || SDL_GetTicks() < _cdEndTime) + return; + + if (_cdNumLoops != 1 && SDL_CDStatus(_cdrom) != CD_STOPPED) { + // Wait another second for it to be done + _cdEndTime += 1000; + return; + } + + if (_cdNumLoops > 0) + _cdNumLoops--; + + if (_cdNumLoops != 0) { + if (_cdStartFrame == 0 && _cdDuration == 0) + SDL_CDPlayTracks(_cdrom, _cdTrack, 0, 1, 0); + else + SDL_CDPlayTracks(_cdrom, _cdTrack, _cdStartFrame, 0, _cdDuration); + _cdEndTime = SDL_GetTicks() + _cdrom->track[_cdTrack].length * 1000 / CD_FPS; + } +} diff --git a/backends/platform/x11/build.rules b/backends/platform/x11/build.rules new file mode 100644 index 0000000000..1540d452d6 --- /dev/null +++ b/backends/platform/x11/build.rules @@ -0,0 +1,7 @@ +# Build settings for the X11 backend +MODULES += backends/x11 +OBJS += backends/x11/x11.o +DEFINES += -DUNIX -DX11_BACKEND +LDFLAGS += -L/usr/X11R6/lib -L/usr/local/lib +INCLUDES+= -I/usr/X11R6/include +LIBS += -lpthread -lXext -lX11 diff --git a/backends/platform/x11/module.mk b/backends/platform/x11/module.mk new file mode 100644 index 0000000000..22015b53be --- /dev/null +++ b/backends/platform/x11/module.mk @@ -0,0 +1,10 @@ +MODULE := backends/platform/x11 + +MODULE_OBJS := \ + x11.o + +MODULE_DIRS += \ + backends/platform/x11/ + +# We don't use the rules.mk here on purpose +OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) diff --git a/backends/platform/x11/x11.cpp b/backends/platform/x11/x11.cpp new file mode 100644 index 0000000000..ce020c7a8e --- /dev/null +++ b/backends/platform/x11/x11.cpp @@ -0,0 +1,1037 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * 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$ + * + */ + +/* The bare pure X11 port done by Lionel 'BBrox' Ulmer */ + +#include "common/stdafx.h" +#include "common/scummsys.h" +#include "common/system.h" +#include "common/util.h" +#include "base/main.h" +#include "backends/intern.h" +#include "backends/platform/x11/x11.h" + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#ifdef __linux__ +#include +#else +#include +#endif + +#include +#include + +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + g_system = OSystem_X11::create(0, 0); + assert(g_system); + + // Invoke the actual ScummVM main entry point: + int res = scummvm_main(argc, argv); + g_system->quit(); // TODO: Consider removing / replacing this! + return res; +} + +OSystem *OSystem_X11::create(int gfx_mode, bool full_screen) { + OSystem_X11 *syst = new OSystem_X11(); + return syst; +} + +OSystem_X11::OSystem_X11() { + /* Some members initialization */ + _fake_right_mouse = 0; + _report_presses = 1; + _current_shake_pos = 0; + _new_shake_pos = 0; + _palette_changed = false; + _num_of_dirty_rects = 0; + _overlay_visible = false; + _mouse_state_changed = true; + _mouse_visible = true; + _ms_buf = NULL; + _curMouseState.x = 0; + _curMouseState.y = 0; + _curMouseState.hot_x = 0; + _curMouseState.hot_y = 0; + _curMouseState.w = 0; + _curMouseState.h = 0; + _palette16 = 0; + _palette32 = 0; + _bytesPerPixel = 0; + _image = 0; + _local_fb = 0; + _local_fb_overlay = 0; +} + +OSystem_X11::~OSystem_X11() { + XFree(_image); + if (_palette16) + free(_palette16); + + if (_palette32) + free(_palette32); + + if (_ms_buf) + free(_ms_buf); + + free(_local_fb_overlay); + free(_local_fb); +} + +void OSystem_X11::initBackend() { + char buf[512]; + XWMHints *wm_hints; + XGCValues values; + XTextProperty window_name; + char *name = (char *)&buf; + /* For the_window title */ + sprintf(buf, "ScummVM"); + + _display = XOpenDisplay(NULL); + if (_display == NULL) { + error("Could not open display !\n"); + exit(1); + } + + if (XShmQueryExtension(_display)!=True) + error("No Shared Memory Extension present"); + + _screen = DefaultScreen(_display); + _depth = DefaultDepth(_display, _screen); + switch (_depth) { + case 16 : + _bytesPerPixel = 2; + break; + case 24 : + case 32 : + _bytesPerPixel = 4; + break; + } + + if (!_bytesPerPixel) + error("Your screen depth is %ibit. Values other than 16, 24 and 32bit are currently not supported", _depth); + + _window_width = 320; + _window_height = 200; + _scumm_x = 0; + _scumm_y = 0; + _window = XCreateSimpleWindow(_display, XRootWindow(_display, _screen), 0, 0, 320, 200, 0, 0, 0); + wm_hints = XAllocWMHints(); + if (wm_hints == NULL) { + error("Not enough memory to allocate Hints !\n"); + exit(1); + } + wm_hints->flags = InputHint | StateHint; + wm_hints->input = True; + wm_hints->initial_state = NormalState; + XStringListToTextProperty(&name, 1, &window_name); + XSetWMProperties(_display, _window, &window_name, &window_name, + NULL /* argv */ , 0 /* argc */ , NULL /* size hints */ , + wm_hints, NULL /* class hints */ ); + XFree(wm_hints); + + XSelectInput(_display, _window, + ExposureMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask); + + values.foreground = BlackPixel(_display, _screen); + _black_gc = XCreateGC(_display, _window, GCForeground, &values); + + XMapWindow(_display, _window); + XFlush(_display); + + _fb_width = 0; + _fb_height = 0; + + if (!_palette16) + _palette16 = (uint16 *)calloc(256, sizeof(uint16)); + if (!_palette32 && _bytesPerPixel == 4) + _palette32 = (uint32 *)calloc(256, sizeof(uint32)); + + while (1) { + XEvent event; + XNextEvent(_display, &event); + switch (event.type) { + case Expose: + goto out_of_loop; + } + } +out_of_loop: + create_empty_cursor(); + + /* Initialize the timer routines */ + _timer_active = false; + + /* And finally start the local timer */ + gettimeofday(&_start_time, NULL); + +} + +#undef CAPTURE_SOUND +#define FRAG_SIZE 4096 + +static void *sound_and_music_thread(void *params) { + /* Init sound */ + int sound_fd, param, frag_size; + uint8 sound_buffer[FRAG_SIZE]; + OSystem::SoundProc sound_proc = ((THREAD_PARAM *)params)->sound_proc; + void *proc_param = ((THREAD_PARAM *)params)->param; + +#ifdef CAPTURE_SOUND + FILE *f = fopen("sound.raw", "wb"); +#endif + + sound_fd = open("/dev/dsp", O_WRONLY); + audio_buf_info info; + if (sound_fd < 0) { + warning("Error opening sound device!\n"); + return NULL; + } + param = 0; + frag_size = FRAG_SIZE /* audio fragment size */ ; + while (frag_size) { + frag_size >>= 1; + param++; + } + param--; + param |= /* audio_fragment_num */ 3 << 16; + if (ioctl(sound_fd, SNDCTL_DSP_SETFRAGMENT, ¶m) != 0) { + warning("Error in the SNDCTL_DSP_SETFRAGMENT ioctl!\n"); + return NULL; + } + param = AFMT_S16_LE; + if (ioctl(sound_fd, SNDCTL_DSP_SETFMT, ¶m) == -1) { + warning("Error in the SNDCTL_DSP_SETFMT ioctl!\n"); + return NULL;; + } + if (param != AFMT_S16_LE) { + warning("AFMT_S16_LE not supported!\n"); + return NULL; + } + param = 2; + if (ioctl(sound_fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) { + warning("Error in the SNDCTL_DSP_CHANNELS ioctl!\n"); + return NULL; + } + if (param != 2) { + warning("Stereo mode not supported!\n"); + return NULL; + } + param = SAMPLES_PER_SEC; + if (ioctl(sound_fd, SNDCTL_DSP_SPEED, ¶m) == -1) { + warning("Error in the SNDCTL_DSP_SPEED ioctl!\n"); + return NULL; + } + if (param != SAMPLES_PER_SEC) { + warning("%d kHz not supported!\n", SAMPLES_PER_SEC); + return NULL; + } + if (ioctl(sound_fd, SNDCTL_DSP_GETOSPACE, &info) != 0) { + warning("SNDCTL_DSP_GETOSPACE"); + return NULL; + } + + sched_yield(); + while (1) { + uint8 *buf = (uint8 *)sound_buffer; + int size, written; + + sound_proc(proc_param, (byte *)sound_buffer, FRAG_SIZE); +#ifdef CAPTURE_SOUND + fwrite(buf, 2, FRAG_SIZE >> 1, f); + fflush(f); +#endif + size = FRAG_SIZE; + while (size > 0) { + written = write(sound_fd, buf, size); + buf += written; + size -= written; + } + } + + return NULL; +} + +/* Function used to hide the mouse cursor */ +void OSystem_X11::create_empty_cursor() { + XColor bg; + Pixmap pixmapBits; + Cursor cursor = None; + static const char data[] = { 0 }; + + bg.red = bg.green = bg.blue = 0x0000; + pixmapBits = XCreateBitmapFromData(_display, XRootWindow(_display, _screen), data, 1, 1); + if (pixmapBits) { + cursor = XCreatePixmapCursor(_display, pixmapBits, pixmapBits, &bg, &bg, 0, 0); + XFreePixmap(_display, pixmapBits); + } + XDefineCursor(_display, _window, cursor); +} + +bool OSystem_X11::hasFeature(Feature f) { + return false; +} + +void OSystem_X11::setFeatureState(Feature f, bool enable) { +} + +bool OSystem_X11::getFeatureState(Feature f) { + return false; +} + +const OSystem::GraphicsMode *OSystem_X11::getSupportedGraphicsModes() const { + static const OSystem::GraphicsMode mode = {"1x", "Normal mode", 0}; + return &mode; +} + +int OSystem_X11::getDefaultGraphicsMode() const { + return 0; +} + +bool OSystem_X11::setGraphicsMode(int mode) { + return (mode == 0); +} + +int OSystem_X11::getGraphicsMode() const { + return 0; +} + + +uint32 OSystem_X11::getMillis() { + struct timeval current_time; + gettimeofday(¤t_time, NULL); + return (uint32)(((current_time.tv_sec - _start_time.tv_sec) * 1000) + + ((current_time.tv_usec - _start_time.tv_usec) / 1000)); +} + +void OSystem_X11::initSize(uint w, uint h) { + //debug("initSize(%i, %i)", w, h); + static XShmSegmentInfo shminfo; + + if (((uint)_fb_width != w) || ((uint)_fb_height != w)) { + _fb_width = w; + _fb_height = h; + + /* We need to change the size of the X11_window */ + XWindowChanges new_values; + + new_values.width = _fb_width; + new_values.height = _fb_height; + + XConfigureWindow(_display,_window, CWWidth | CWHeight, &new_values); + + if (_image) + XFree(_image); + _image = XShmCreateImage(_display, DefaultVisual(_display, _screen), _depth, ZPixmap, NULL, &shminfo,_fb_width,_fb_height); + if (!_image) + error("Couldn't get image by XShmCreateImage()"); + + shminfo.shmid = shmget(IPC_PRIVATE, _image->bytes_per_line * _image->height, IPC_CREAT | 0700); + if (shminfo.shmid < 0) + error("Couldn't allocate image data by shmget()"); + + _image->data = shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0); + shminfo.readOnly = False; + if (XShmAttach(_display, &shminfo) == 0) { + error("Could not attach shared memory segment !\n"); + exit(1); + } + shmctl(shminfo.shmid, IPC_RMID, 0); + + if (_local_fb) + free(_local_fb); + if (_local_fb_overlay) + free(_local_fb_overlay); + /* Initialize the 'local' frame buffer and the palette */ + _local_fb = (uint8 *)calloc(_fb_width * _fb_height, sizeof(uint8)); + _local_fb_overlay = (uint16 *)calloc(_fb_width * _fb_height, sizeof(uint16)); + + } +} + +bool OSystem_X11::setSoundCallback(SoundProc proc, void *param) { + static THREAD_PARAM thread_param; + + /* And finally start the music thread */ + thread_param.param = param; + thread_param.sound_proc = proc; + + pthread_create(&_sound_thread, NULL, sound_and_music_thread, (void *)&thread_param); + + return true; +} + +void OSystem_X11::clearSoundCallback() { + // TODO implement this... + // The sound_thread has to be stopped in a nice way. In particular, + // using pthread_kill would be a bad idea. Rather, use pthread_cancel, + // or maybe a global variable, to achieve this. + // This method shouldn't return until the sound thread really has stopped. +} + + +void OSystem_X11::setPalette(const byte *colors, uint start, uint num) { + uint16 *pal = &(_palette16[start]); + const byte *data = colors; + + if (_bytesPerPixel == 4) { + for (uint i = start; i < start+num; i++) { + //_palette32[i] = ((uint32 *)colors)[i]; + _palette32[i] = (colors[i * 4 + 0] << 16) | (colors[i * 4 + 1] << 8) | (colors[i * 4 + 2] << 0); + } + } + + do { + *pal++ = ((data[0] & 0xF8) << 8) | ((data[1] & 0xFC) << 3) | (data[2] >> 3); + data += 4; + num--; + } while (num > 0); + + _palette_changed = true; +} + +#define AddDirtyRec(xi,yi,wi,hi) \ + if (_num_of_dirty_rects < MAX_NUMBER_OF_DIRTY_RECTS) { \ + _ds[_num_of_dirty_rects].x = xi; \ + _ds[_num_of_dirty_rects].y = yi; \ + _ds[_num_of_dirty_rects].w = wi; \ + _ds[_num_of_dirty_rects].h = hi; \ + _num_of_dirty_rects++; \ + } + +void OSystem_X11::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { + uint8 *dst; + + if (y < 0) { + h += y; + buf -= y * pitch; + y = 0; + } + if (h > (_fb_height - y)) { + h = _fb_height - y; + } + + dst = _local_fb + _fb_width * y + x; + + if (h <= 0) + return; + + AddDirtyRec(x, y, w, h); + while (h-- > 0) { + memcpy(dst, buf, w); + dst +=_fb_width; + buf += pitch; + } +} + +void OSystem_X11::blit(const DirtyRect *d, uint16 *dst, int pitch) { + uint8 *ptr_src = _local_fb + (_fb_width * d->y) + d->x; + uint16 *ptr_dst = dst + ((_fb_width * d->y) + d->x); + int x, y; + + for (y = 0; y < d->h; y++) { + for (x = 0; x < d->w; x++) { + *ptr_dst++ = _palette16[*ptr_src++]; + } + ptr_dst += pitch - d->w; + ptr_src +=_fb_width - d->w; + } +} + +void OSystem_X11::blit_convert(const DirtyRect *d, uint8 *dst, int pitch) { + uint8 *ptr_src = _local_fb + (_fb_width * d->y) + d->x; + uint8 *ptr_dst = dst + ((_fb_width * d->y) + d->x) * _bytesPerPixel; + int x, y; + + switch (_bytesPerPixel) { + case 2: + for (y = 0; y < d->h; y++) { + for (x = 0; x < d->w; x++) { + *ptr_dst = _palette16[*ptr_src++]; + ptr_dst += _bytesPerPixel; + } + ptr_dst += (pitch - d->w) * _bytesPerPixel; + ptr_src +=_fb_width - d->w; + } + break; + case 4: + for (y = 0; y < d->h; y++) { + for (x = 0; x < d->w; x++) { + *(uint32 *)ptr_dst = _palette32[*ptr_src]; + ptr_dst += _bytesPerPixel; + ptr_src++; + } + ptr_dst += (pitch - d->w) * _bytesPerPixel; + ptr_src += _fb_width - d->w; + } + } +} + +void OSystem_X11::updateScreen_helper(const DirtyRect *d, DirtyRect *dout) { + + if (_overlay_visible == false) { + blit_convert(d, (uint8 *)_image->data, _fb_width); + } else { + uint16 *ptr_src = _local_fb_overlay + (_fb_width * d->y) + d->x; + uint8 *ptr_dst = (uint8 *)_image->data + ((_fb_width * d->y) + d->x) * _bytesPerPixel; + + int y; + + switch (_bytesPerPixel) { + case 2: + for (y = 0; y < d->h; y++) { + memcpy(ptr_dst, ptr_src, d->w * sizeof(uint16)); + ptr_dst += _fb_width * sizeof(uint16); + ptr_src += _fb_width; + } + break; + case 4: + uint16 currLine, x; + register uint16 currPixel; + for (y = d->y; y < d->y + d->h; y++) { + currLine = y * _fb_width; + for (x = d->x; x < d->x + d->w; x++) { + currPixel = _local_fb_overlay[(currLine + x)]; + *(uint32 *)ptr_dst = ((currPixel & 0xF800) << 8) + ((currPixel & 0x07E0) << 5) + + ((currPixel & 0x001F) << 3); + ptr_dst += sizeof(uint32); + } + ptr_dst += (_fb_width - d->w) * _bytesPerPixel; + } + + } + } + if (d->x < dout->x) + dout->x = d->x; + if (d->y < dout->y) + dout->y = d->y; + if ((d->x + d->w) > dout->w) + dout->w = d->x + d->w; + if ((d->y + d->h) > dout->h) + dout->h = d->y + d->h; +} + +void OSystem_X11::updateScreen() { + bool full_redraw = false; + bool need_redraw = false; + static const DirtyRect ds_full = { 0, 0, _fb_width, _fb_height }; + DirtyRect dout = {_fb_width, _fb_height, 0, 0 }; + + if (_palette_changed) { + full_redraw = true; + _num_of_dirty_rects = 0; + _palette_changed = false; + } else if (_num_of_dirty_rects >= MAX_NUMBER_OF_DIRTY_RECTS) { + full_redraw = true; + _num_of_dirty_rects = 0; + } + + if (full_redraw) { + updateScreen_helper(&ds_full, &dout); + need_redraw = true; + } else if ((_num_of_dirty_rects > 0) || (_mouse_state_changed == true)) { + need_redraw = true; + while (_num_of_dirty_rects > 0) { + _num_of_dirty_rects--; + updateScreen_helper(&(_ds[_num_of_dirty_rects]), &dout); + } + } + + /* Then 'overlay' the mouse on the image */ + draw_mouse(&dout); + + if (_current_shake_pos != _new_shake_pos) { + /* Redraw first the 'black borders' in case of resize */ + if (_current_shake_pos < _new_shake_pos) + XFillRectangle(_display,_window, _black_gc, 0, _current_shake_pos, _window_width, _new_shake_pos); + else + XFillRectangle(_display,_window, _black_gc, 0, _window_height - _current_shake_pos, + _window_width,_window_height - _new_shake_pos); + XShmPutImage(_display, _window, DefaultGC(_display, _screen), _image, + 0, 0, _scumm_x, _scumm_y + _new_shake_pos, _fb_width, _fb_height, 0); + _current_shake_pos = _new_shake_pos; + } else if (need_redraw == true) { + XShmPutImage(_display, _window, DefaultGC(_display, _screen), _image, + dout.x, dout.y, _scumm_x + dout.x, _scumm_y + dout.y + _current_shake_pos, + dout.w - dout.x, dout.h - dout.y, 0); + XFlush(_display); + } +} + +bool OSystem_X11::showMouse(bool visible) +{ + if (_mouse_visible == visible) + return visible; + + bool last = _mouse_visible; + _mouse_visible = visible; + + if ((visible == false) && (_mouse_state_changed == false)) { + undraw_mouse(); + } + _mouse_state_changed = true; + + return last; +} + +void OSystem_X11::quit() { + exit(0); +} + +void OSystem_X11::setWindowCaption(const char *caption) { + //debug("setWindowCaption('%s')", caption); +} + +void OSystem_X11::undraw_mouse() { + AddDirtyRec(_oldMouseState.x, _oldMouseState.y, _oldMouseState.w, _oldMouseState.h); +} + +void OSystem_X11::draw_mouse(DirtyRect *dout) { + //debug("draw_mouse()"); + _mouse_state_changed = false; + + if (_mouse_visible == false) + return; + + int xdraw = _curMouseState.x - _curMouseState.hot_x; + int ydraw = _curMouseState.y - _curMouseState.hot_y; + int w = _curMouseState.w; + int h = _curMouseState.h; + int real_w; + int real_h; + + uint8 *dst; + const byte *buf = _ms_buf; + + if (ydraw < 0) { + real_h = h + ydraw; + buf += (-ydraw) * w; + ydraw = 0; + } else { + real_h = (ydraw + h) > _fb_height ? (_fb_height - ydraw) : h; + } + if (xdraw < 0) { + real_w = w + xdraw; + buf += (-xdraw); + xdraw = 0; + } else { + real_w = (xdraw + w) > _fb_width ? (_fb_width - xdraw) : w; + } + + dst = (uint8 *)_image->data + ((ydraw *_fb_width) + xdraw) * _bytesPerPixel; + + if ((real_h == 0) || (real_w == 0)) { + return; + } + + + if (xdraw < dout->x) + dout->x = xdraw; + if (ydraw < dout->y) + dout->y = ydraw; + if ((xdraw + real_w) > dout->w) + dout->w = xdraw + real_w; + if ((ydraw + real_h) > dout->h) + dout->h = ydraw + real_h; + + _oldMouseState.x = xdraw; + _oldMouseState.y = ydraw; + _oldMouseState.w = real_w; + _oldMouseState.h = real_h; + + while (real_h > 0) { + int width = real_w; + while (width > 0) { + byte color = *buf; + if (color != _mouseKeycolor) { + if (_depth == 16) + *(uint16 *)dst = _palette16[color]; + else { + *(uint32 *)dst = _palette32[color]; + } + } + buf++; + dst += _bytesPerPixel; + width--; + } + buf += w - real_w; + dst += (_fb_width - real_w) * _bytesPerPixel; + real_h--; + } +} + +void OSystem_X11::set_mouse_pos(int x, int y) { + if ((x != _curMouseState.x) || (y != _curMouseState.y)) { + _curMouseState.x = x; + _curMouseState.y = y; + if (_mouse_state_changed == false) { + undraw_mouse(); + } + _mouse_state_changed = true; + } +} + +void OSystem_X11::warpMouse(int x, int y) { + set_mouse_pos(x, y); +} + +void OSystem_X11::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) { + _curMouseState.w = w; + _curMouseState.h = h; + _curMouseState.hot_x = hotspot_x; + _curMouseState.hot_y = hotspot_y; + + if (_ms_buf) + free(_ms_buf); + _ms_buf = (byte *) malloc(w * h); + memcpy(_ms_buf, buf, w * h); + + if (_mouse_state_changed == false) { + undraw_mouse(); + } + _mouseKeycolor = keycolor; + _mouse_state_changed = true; +} + +void OSystem_X11::setShakePos(int shake_pos) { + if (_new_shake_pos != shake_pos) { + if (_mouse_state_changed == false) { + undraw_mouse(); + } + _mouse_state_changed = true; + } + _new_shake_pos = shake_pos; +} + +int OSystem_X11::getOutputSampleRate() const { + return SAMPLES_PER_SEC; +} + +void OSystem_X11::delayMillis(uint msecs) { + usleep(msecs * 1000); +} + +bool OSystem_X11::pollEvent(Event &scumm_event) { + /* First, handle timers */ + uint32 current_msecs = getMillis(); + + if (_timer_active && (current_msecs >= _timer_next_expiry)) { + _timer_duration = _timer_callback(_timer_duration); + _timer_next_expiry = current_msecs + _timer_duration; + } + + while (XPending(_display)) { + XEvent event; + + XNextEvent(_display, &event); + switch (event.type) { + case Expose:{ + int real_w, real_h; + int real_x, real_y; + real_x = event.xexpose.x; + real_y = event.xexpose.y; + real_w = event.xexpose.width; + real_h = event.xexpose.height; + if (real_x < _scumm_x) { + real_w -= _scumm_x - real_x; + real_x = 0; + } else { + real_x -= _scumm_x; + } + if (real_y < _scumm_y) { + real_h -= _scumm_y - real_y; + real_y = 0; + } else { + real_y -= _scumm_y; + } + if ((real_h <= 0) || (real_w <= 0)) + break; + if ((real_x >=_fb_width) || (real_y >=_fb_height)) + break; + + if ((real_x + real_w) >=_fb_width) { + real_w =_fb_width - real_x; + } + if ((real_y + real_h) >=_fb_height) { + real_h =_fb_height - real_y; + } + + /* Compute the intersection of the expose event with the real ScummVM display zone */ + AddDirtyRec(real_x, real_y, real_w, real_h); + } + break; + + case KeyPress:{ + /* I am using keycodes here and NOT keysyms to be sure that even if the user + remaps his iPAQ's keyboard, it will still work. + */ + int keycode = -1; + int ascii = -1; + byte mode = 0; + + if (event.xkey.state & 0x01) + mode |= KBD_SHIFT; + if (event.xkey.state & 0x04) + mode |= KBD_CTRL; + if (event.xkey.state & 0x08) + mode |= KBD_ALT; + switch (event.xkey.keycode) { + + case 9: /* Escape on my PC */ + case 130: /* Calendar on the iPAQ */ + keycode = 27; + break; + + case 71: /* F5 on my PC */ + case 128: /* Record on the iPAQ */ + keycode = 319; + break; + + case 65: /* Space on my PC */ + case 131: /* Schedule on the iPAQ */ + keycode = 32; + break; + + case 132: + _report_presses = 0; + break; + + case 133: + _fake_right_mouse = 1; + break; + + default:{ + KeySym xsym; + xsym = XKeycodeToKeysym(_display, event.xkey.keycode, 0); + keycode = xsym; + if ((xsym >= 'a') && (xsym <= 'z') && (event.xkey.state & 0x01)) + xsym &= ~0x20; /* Handle shifted keys */ + ascii = xsym; + } + } + if (keycode != -1) { + scumm_event.type = EVENT_KEYDOWN; + scumm_event.kbd.keycode = keycode; + scumm_event.kbd.ascii = (ascii != -1 ? ascii : keycode); + scumm_event.kbd.flags = mode; + return true; + } + } + break; + + case KeyRelease:{ + /* I am using keycodes here and NOT keysyms to be sure that even if the user + remaps his iPAQ's keyboard, it will still work. + */ + int keycode = -1; + int ascii = -1; + byte mode = 0; + + if (event.xkey.state & 0x01) + mode |= KBD_SHIFT; + if (event.xkey.state & 0x04) + mode |= KBD_CTRL; + if (event.xkey.state & 0x08) + mode |= KBD_ALT; + switch (event.xkey.keycode) { + case 132: /* 'Q' on the iPAQ */ + _report_presses = 1; + break; + + case 133: /* Arrow on the iPAQ */ + _fake_right_mouse = 0; + break; + + default:{ + KeySym xsym; + xsym = XKeycodeToKeysym(_display, event.xkey.keycode, 0); + keycode = xsym; + if ((xsym >= 'a') && (xsym <= 'z') && (event.xkey.state & 0x01)) + xsym &= ~0x20; /* Handle shifted keys */ + ascii = xsym; + } + } + if (keycode != -1) { + scumm_event.type = EVENT_KEYUP; + scumm_event.kbd.keycode = keycode; + scumm_event.kbd.ascii = (ascii != -1 ? ascii : keycode); + scumm_event.kbd.flags = mode; + return true; + } + } + break; + + case ButtonPress: + if (_report_presses != 0) { + if (event.xbutton.button == 1) { + if (_fake_right_mouse == 0) { + scumm_event.type = EVENT_LBUTTONDOWN; + } else { + scumm_event.type = EVENT_RBUTTONDOWN; + } + } else if (event.xbutton.button == 3) + scumm_event.type = EVENT_RBUTTONDOWN; + scumm_event.mouse.x = event.xbutton.x - _scumm_x; + scumm_event.mouse.y = event.xbutton.y - _scumm_y; + return true; + } + break; + + case ButtonRelease: + if (_report_presses != 0) { + if (event.xbutton.button == 1) { + if (_fake_right_mouse == 0) { + scumm_event.type = EVENT_LBUTTONUP; + } else { + scumm_event.type = EVENT_RBUTTONUP; + } + } else if (event.xbutton.button == 3) + scumm_event.type = EVENT_RBUTTONUP; + scumm_event.mouse.x = event.xbutton.x - _scumm_x; + scumm_event.mouse.y = event.xbutton.y - _scumm_y; + return true; + } + break; + + case MotionNotify: + scumm_event.type = EVENT_MOUSEMOVE; + scumm_event.mouse.x = event.xmotion.x - _scumm_x; + scumm_event.mouse.y = event.xmotion.y - _scumm_y; + set_mouse_pos(scumm_event.mouse.x, scumm_event.mouse.y); + return true; + + case ConfigureNotify:{ + if ((_window_width != event.xconfigure.width) || (_window_height != event.xconfigure.height)) { + _window_width = event.xconfigure.width; + _window_height = event.xconfigure.height; + _scumm_x = (_window_width -_fb_width) / 2; + _scumm_y = (_window_height -_fb_height) / 2; + XFillRectangle(_display, _window, _black_gc, 0, 0, _window_width, _window_height); + } + } + break; + + default: + printf("Unhandled event : %d\n", event.type); + break; + } + } + + return false; +} + +void OSystem_X11::setTimerCallback(TimerProc callback, int interval) { + if (callback != NULL) { + _timer_duration = interval; + _timer_next_expiry = getMillis() + interval; + _timer_callback = callback; + _timer_active = true; + } else { + _timer_active = false; + } +} + +OSystem::MutexRef OSystem_X11::createMutex(void) { + pthread_mutex_t *mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(mutex, NULL); + return (MutexRef)mutex; +} + +void OSystem_X11::lockMutex(MutexRef mutex) { + pthread_mutex_lock((pthread_mutex_t *) mutex); +} + +void OSystem_X11::unlockMutex(MutexRef mutex) { + pthread_mutex_unlock((pthread_mutex_t *) mutex); +} + +void OSystem_X11::deleteMutex(MutexRef mutex) { + pthread_mutex_destroy((pthread_mutex_t *) mutex); + free(mutex); +} + +void OSystem_X11::showOverlay() { + _overlay_visible = true; +} + +void OSystem_X11::hideOverlay() { + _overlay_visible = false; + _palette_changed = true; // This is to force a full redraw to hide the overlay +} + +void OSystem_X11::clearOverlay() { + if (_overlay_visible == false) + return; + DirtyRect d = { 0, 0, _fb_width, _fb_height }; + AddDirtyRec(0, 0, _fb_width, _fb_height); + blit(&d, _local_fb_overlay, _fb_width); +} + +void OSystem_X11::grabOverlay(int16 *dest, int pitch) { + if (_overlay_visible == false) + return; + + DirtyRect d = { 0, 0, _fb_width, _fb_height }; + blit(&d, (uint16 *)dest, pitch); +} + +void OSystem_X11::copyRectToOverlay(const int16 *src, int pitch, int x, int y, int w, int h) { + if (_overlay_visible == false) + return; + uint16 *dst = _local_fb_overlay + x + (y * _fb_width); + AddDirtyRec(x, y, w, h); + while (h > 0) { + memcpy(dst, src, w * sizeof(*dst)); + dst +=_fb_width; + src += pitch; + h--; + } +} + +int16 OSystem_X11::getHeight() { + return _fb_height; +} + +int16 OSystem_X11::getWidth() { + return _fb_width; +} + +void OSystem_X11::grabPalette(byte *colors, uint start, uint num) { + warning("Dummy: grabPalette()"); +} diff --git a/backends/platform/x11/x11.h b/backends/platform/x11/x11.h new file mode 100644 index 0000000000..ba29bc7eab --- /dev/null +++ b/backends/platform/x11/x11.h @@ -0,0 +1,195 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * 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$ + * + */ + +class OSystem_X11:public OSystem { +public: + OSystem_X11(); + ~OSystem_X11(); + + void initBackend(); + + // Determine whether the backend supports the specified feature. + bool hasFeature(Feature f); + + // En-/disable the specified feature. + void setFeatureState(Feature f, bool enable); + + // Query the state of the specified feature. + bool getFeatureState(Feature f); + + // Retrieve a list of all graphics modes supported by this backend. + const GraphicsMode *getSupportedGraphicsModes() const; + + // Return the ID of the 'default' graphics mode. + int getDefaultGraphicsMode() const; + + // Switch to the specified graphics mode. + bool setGraphicsMode(int mode); + + // Determine which graphics mode is currently active. + int getGraphicsMode() const; + + // Set colors of the palette + void setPalette(const byte *colors, uint start, uint num); + + // Set the size of the video bitmap. + // Typically, 320x200 + void initSize(uint w, uint h); + + // Draw a bitmap to screen. + // The screen will not be updated to reflect the new bitmap + void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); + + // Update the dirty areas of the screen + void updateScreen(); + + // Either show or hide the mouse cursor + bool showMouse(bool visible); + + // Set the position of the mouse cursor + void set_mouse_pos(int x, int y); + + // 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 hotspotX, int hotspotY, byte keycolor = 255, int cursorTargetScale = 1); + + // 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. + bool pollEvent(Event &event); + + // Set function that generates samples + bool setSoundCallback(SoundProc proc, void *param); + void clearSoundCallback(); + + // Determine the output sample rate. Audio data provided by the sound + // callback will be played using this rate. + int getOutputSampleRate() const; + + // Quit + void quit(); + + // Add a callback timer + void setTimerCallback(TimerProc callback, int interval); + + // Mutex handling + MutexRef createMutex(); + void lockMutex(MutexRef mutex); + void unlockMutex(MutexRef mutex); + void deleteMutex(MutexRef mutex); + + // Overlay handling for the new menu system + void showOverlay(); + void hideOverlay(); + void clearOverlay(); + void grabOverlay(int16 *, int); + void copyRectToOverlay(const int16 *, int, int, int, int, int); + virtual int16 getHeight(); + virtual int16 getWidth(); + + virtual void grabPalette(byte *colors, uint start, uint num); + + // Set a window caption or any other comparable status display to the + // given value. + void setWindowCaption(const char *caption); + + static OSystem *create(int gfx_mode, bool full_screen); + +private: + typedef struct { + int x, y; + int w, h; + int hot_x, hot_y; + } MouseState; + + typedef struct { + int x, y, w, h; + } DirtyRect; + + enum { + MAX_NUMBER_OF_DIRTY_RECTS = 32 + }; + + void create_empty_cursor(); + void draw_mouse(DirtyRect *dout); + void undraw_mouse(); + void updateScreen_helper(const DirtyRect *d, DirtyRect *dout); + void blit_convert(const DirtyRect *d, uint8 *dst, int pitch); + void blit(const DirtyRect *d, uint16 *dst, int pitch); + + uint8 *_local_fb; + uint16 *_local_fb_overlay; + bool _overlay_visible; + + int _window_width, _window_height; + int _fb_width, _fb_height; + int _scumm_x, _scumm_y; + + uint16 *_palette16; + uint32 *_palette32; + + bool _palette_changed; + Display *_display; + int _screen, _depth; + uint8 _bytesPerPixel; + Window _window; + GC _black_gc; + XImage *_image; + pthread_t _sound_thread; + + struct timeval _start_time; + + int _fake_right_mouse; + int _report_presses; + int _current_shake_pos; + int _new_shake_pos; + DirtyRect _ds[MAX_NUMBER_OF_DIRTY_RECTS]; + int _num_of_dirty_rects; + + MouseState _oldMouseState, _curMouseState; + byte *_ms_buf; + bool _mouse_visible; + bool _mouse_state_changed; + byte _mouseKeycolor; + + uint32 _timer_duration, _timer_next_expiry; + bool _timer_active; + int (*_timer_callback) (int); +}; + +typedef struct { + OSystem::SoundProc sound_proc; + void *param; +} THREAD_PARAM; diff --git a/backends/sdl/build.rules b/backends/sdl/build.rules deleted file mode 100644 index 14cfe0ebdf..0000000000 --- a/backends/sdl/build.rules +++ /dev/null @@ -1,9 +0,0 @@ -# Build settings for the SDL backend -MODULES += backends/sdl -DEFINES += -DUNIX -INCLUDES += `sdl-config --cflags` -LIBS += `sdl-config --libs` - -# Uncomment this in addition to the above if you compile on Mac OS X -# DEFINES += -DMACOSX -# LIBS += -framework QuickTime -framework AudioUnit diff --git a/backends/sdl/events.cpp b/backends/sdl/events.cpp deleted file mode 100644 index 3c296b8a45..0000000000 --- a/backends/sdl/events.cpp +++ /dev/null @@ -1,510 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "backends/sdl/sdl-common.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 3200 - -#ifndef __SYMBIAN32__ // Symbian wants dialog joystick i.e cursor for movement/selection - #define JOY_ANALOG -#endif - -// #define JOY_INVERT_Y -#define JOY_XAXIS 0 -#define JOY_YAXIS 1 -// buttons -#define JOY_BUT_LMOUSE 0 -#define JOY_BUT_RMOUSE 2 -#define JOY_BUT_ESCAPE 3 -#define JOY_BUT_PERIOD 1 -#define JOY_BUT_SPACE 4 -#define JOY_BUT_F5 5 - - - - -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_SDL::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_SDL::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; -} - -bool OSystem_SDL::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; - return true; - } - - 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); -#ifdef USE_OSD - if (_fullscreen) - displayMessageOnOSD("Fullscreen mode"); - else - displayMessageOnOSD("Windowed mode"); -#endif - - 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- 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- 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; - - case SDL_JOYBUTTONDOWN: - if (ev.jbutton.button == JOY_BUT_LMOUSE) { - 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 { - event.type = EVENT_KEYDOWN; - switch (ev.jbutton.button) { - case JOY_BUT_ESCAPE: - event.kbd.keycode = SDLK_ESCAPE; - event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); - break; - case JOY_BUT_PERIOD: - event.kbd.keycode = SDLK_PERIOD; - event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0); - break; - case JOY_BUT_SPACE: - event.kbd.keycode = SDLK_SPACE; - event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); - break; - case JOY_BUT_F5: - event.kbd.keycode = SDLK_F5; - event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); - break; - } - } - return true; - - case SDL_JOYBUTTONUP: - 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 { - event.type = EVENT_KEYUP; - switch (ev.jbutton.button) { - case JOY_BUT_ESCAPE: - event.kbd.keycode = SDLK_ESCAPE; - event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); - break; - case JOY_BUT_PERIOD: - event.kbd.keycode = SDLK_PERIOD; - event.kbd.ascii = mapKey(SDLK_PERIOD, ev.key.keysym.mod, 0); - break; - case JOY_BUT_SPACE: - event.kbd.keycode = SDLK_SPACE; - event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); - break; - case JOY_BUT_F5: - event.kbd.keycode = SDLK_F5; - event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); - 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_SDL::remapKey(SDL_Event &ev,Event &event) { -#ifdef LINUPY - // On Yopy map the End button to quit - if ((ev.key.keysym.sym == 293)) { - event.type = EVENT_QUIT; - return true; - } - // Map menu key to f5 (scumm menu) - if (ev.key.keysym.sym == 306) { - event.type = EVENT_KEYDOWN; - event.kbd.keycode = SDLK_F5; - event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); - return true; - } - // Map action key to action - if (ev.key.keysym.sym == 291) { - event.type = EVENT_KEYDOWN; - event.kbd.keycode = SDLK_TAB; - event.kbd.ascii = mapKey(SDLK_TAB, ev.key.keysym.mod, 0); - return true; - } - // Map OK key to skip cinematic - if (ev.key.keysym.sym == 292) { - event.type = EVENT_KEYDOWN; - event.kbd.keycode = SDLK_ESCAPE; - event.kbd.ascii = mapKey(SDLK_ESCAPE, ev.key.keysym.mod, 0); - return true; - } -#endif - -#ifdef QTOPIA - // Quit on fn+backspace on zaurus - if (ev.key.keysym.sym == 127) { - event.type = EVENT_QUIT; - return true; - } - - // Map menu key (f11) to f5 (scumm menu) - if (ev.key.keysym.sym == SDLK_F11) { - event.type = EVENT_KEYDOWN; - event.kbd.keycode = SDLK_F5; - event.kbd.ascii = mapKey(SDLK_F5, ev.key.keysym.mod, 0); - } - // Nap center (space) to tab (default action ) - // I wanted to map the calendar button but the calendar comes up - // - else if (ev.key.keysym.sym == SDLK_SPACE) { - event.type = EVENT_KEYDOWN; - event.kbd.keycode = SDLK_TAB; - event.kbd.ascii = mapKey(SDLK_TAB, ev.key.keysym.mod, 0); - } - // Since we stole space (pause) above we'll rebind it to the tab key on the keyboard - else if (ev.key.keysym.sym == SDLK_TAB) { - event.type = EVENT_KEYDOWN; - event.kbd.keycode = SDLK_SPACE; - event.kbd.ascii = mapKey(SDLK_SPACE, ev.key.keysym.mod, 0); - } else { - // Let the events fall through if we didn't change them, this may not be the best way to - // set it up, but i'm not sure how sdl would like it if we let if fall through then redid it though. - // and yes i have an huge terminal size so i dont wrap soon enough. - 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); - } -#endif - return false; -} - diff --git a/backends/sdl/graphics.cpp b/backends/sdl/graphics.cpp deleted file mode 100644 index 30c7a4aa9b..0000000000 --- a/backends/sdl/graphics.cpp +++ /dev/null @@ -1,1745 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "backends/sdl/sdl-common.h" -#include "common/util.h" -#include "graphics/font.h" -#include "graphics/fontman.h" -#include "graphics/scaler.h" -#include "graphics/surface.h" - -static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { - {"1x", "Normal (no scaling)", GFX_NORMAL}, - {"2x", "2x", GFX_DOUBLESIZE}, - {"3x", "3x", GFX_TRIPLESIZE}, - {"2xsai", "2xSAI", GFX_2XSAI}, - {"super2xsai", "Super2xSAI", GFX_SUPER2XSAI}, - {"supereagle", "SuperEagle", GFX_SUPEREAGLE}, - {"advmame2x", "AdvMAME2x", GFX_ADVMAME2X}, - {"advmame3x", "AdvMAME3x", GFX_ADVMAME3X}, -#ifndef DISABLE_HQ_SCALERS - {"hq2x", "HQ2x", GFX_HQ2X}, - {"hq3x", "HQ3x", GFX_HQ3X}, -#endif - {"tv2x", "TV2x", GFX_TV2X}, - {"dotmatrix", "DotMatrix", GFX_DOTMATRIX}, - {0, 0, 0} -}; - -// Table of relative scalers magnitudes -// [definedScale - 1][_scaleFactor - 1] -static ScalerProc *scalersMagn[3][3] = { -#ifndef DISABLE_SCALERS - { Normal1x, AdvMame2x, AdvMame3x }, - { Normal1x, Normal1x, Normal1o5x }, - { Normal1x, Normal1x, Normal1x } -#else // remove dependencies on other scalers - { Normal1x, Normal1x, Normal1x }, - { Normal1x, Normal1x, Normal1x }, - { Normal1x, Normal1x, Normal1x } -#endif -}; - -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 } - }; - -#ifndef DISABLE_SCALERS -static int cursorStretch200To240(uint8 *buf, uint32 pitch, int width, int height, int srcX, int srcY, int origSrcY); -#endif - -const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const { - return s_supportedGraphicsModes; -} - -int OSystem_SDL::getDefaultGraphicsMode() const { - return GFX_DOUBLESIZE; -} - -void OSystem_SDL::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_SDL::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_SDL::setGraphicsMode(int mode) { - Common::StackLock lock(_graphicsMutex); - - int newScaleFactor = 1; - ScalerProc *newScalerProc; - - switch(mode) { - case GFX_NORMAL: - newScaleFactor = 1; - newScalerProc = Normal1x; - break; -#ifndef DISABLE_SCALERS - case GFX_DOUBLESIZE: - newScaleFactor = 2; - newScalerProc = Normal2x; - break; - case GFX_TRIPLESIZE: - newScaleFactor = 3; - newScalerProc = Normal3x; - break; - - case GFX_2XSAI: - newScaleFactor = 2; - newScalerProc = _2xSaI; - break; - case GFX_SUPER2XSAI: - newScaleFactor = 2; - newScalerProc = Super2xSaI; - break; - case GFX_SUPEREAGLE: - newScaleFactor = 2; - newScalerProc = SuperEagle; - break; - case GFX_ADVMAME2X: - newScaleFactor = 2; - newScalerProc = AdvMame2x; - break; - case GFX_ADVMAME3X: - newScaleFactor = 3; - newScalerProc = AdvMame3x; - break; -#ifndef DISABLE_HQ_SCALERS - case GFX_HQ2X: - newScaleFactor = 2; - newScalerProc = HQ2x; - break; - case GFX_HQ3X: - newScaleFactor = 3; - newScalerProc = HQ3x; - break; -#endif - case GFX_TV2X: - newScaleFactor = 2; - newScalerProc = TV2x; - break; - case GFX_DOTMATRIX: - newScaleFactor = 2; - newScalerProc = DotMatrix; - break; -#endif // DISABLE_SCALERS - - default: - warning("unknown gfx mode %d", mode); - return false; - } - - _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_SDL::getGraphicsMode() const { - assert (_transactionMode == kTransactionNone); - return _mode; -} - -void OSystem_SDL::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_SDL::loadGFXMode() { - 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 scaled graphics in 16 bit mode - // - - _hwscreen = SDL_SetVideoMode(hwW, hwH, 16, - _fullscreen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE - ); - if (_hwscreen == NULL) { - // DON'T use error(), as this tries to bring up the debug - // console, which WON'T WORK now that _hwscreen is hosed. - - // FIXME: We should be able to continue the game without - // shutting down or bringing up the debug console, but at - // this point we've already screwed up all our member vars. - // We need to find a way to call SDL_SetVideoMode *before* - // that happens and revert to all the old settings if we - // can't pull off the switch to the new settings. - // - // Fingolfin says: the "easy" way to do that is not to modify - // the member vars before we are sure everything is fine. Think - // of "transactions, commit, rollback" style... we use local vars - // in place of the member vars, do everything etc. etc.. In case - // of a failure, rollback is trivial. Only if everything worked fine - // do we "commit" the changed values to the member vars. - warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError()); - quit(); - } - - // - // 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"); - -#ifdef USE_OSD - _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); -#endif - - // 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_SDL::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; - } - -#ifdef USE_OSD - if (_osdSurface) { - SDL_FreeSurface(_osdSurface); - _osdSurface = NULL; - } -#endif -} - -void OSystem_SDL::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); - -#ifdef USE_OSD - // Release the OSD surface - SDL_FreeSurface(_osdSurface); -#endif - - // 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_SDL::updateScreen() { - assert (_transactionMode == kTransactionNone); - - Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends - - internUpdateScreen(); -} - -void OSystem_SDL::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 (_paletteDirtyEnd != 0) { - SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, - _paletteDirtyStart, - _paletteDirtyEnd - _paletteDirtyStart); - - _paletteDirtyEnd = 0; - - _forceFull = true; - } - -#ifdef USE_OSD - // 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; - } - } -#endif - - 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(); - -#ifdef USE_OSD - if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { - SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); - } -#endif - // 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_SDL::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_SDL::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_SDL::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_SDL::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_SDL::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_SDL::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_SDL::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_SDL::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). - // 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_SDL::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_SDL::getHeight() { - return _screenHeight; -} - -int16 OSystem_SDL::getWidth() { - return _screenWidth; -} - -void OSystem_SDL::setPalette(const byte *colors, uint start, uint num) { - assert(colors); - 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_SDL::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_SDL::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_SDL::setShakePos(int shake_pos) { - assert (_transactionMode == kTransactionNone); - - _newShakePos = shake_pos; -} - - -#pragma mark - -#pragma mark --- Overlays --- -#pragma mark - - -void OSystem_SDL::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_SDL::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_SDL::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_SDL::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_SDL::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_SDL::RGBToColor(uint8 r, uint8 g, uint8 b) { - return SDL_MapRGB(_overlayscreen->format, r, g, b); -} - -void OSystem_SDL::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_SDL::showMouse(bool visible) { - if (_mouseVisible == visible) - return visible; - - bool last = _mouseVisible; - _mouseVisible = visible; - - return last; -} - -void OSystem_SDL::setMousePos(int x, int y) { - if (x != _mouseCurState.x || y != _mouseCurState.y) { - _mouseCurState.x = x; - _mouseCurState.y = y; - } -} - -void OSystem_SDL::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_SDL::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_SDL::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); - -#ifndef DISABLE_SCALERS - if (_adjustAspectRatio && _cursorTargetScale == 1) - cursorStretch200To240((uint8 *)_mouseSurface->pixels, _mouseSurface->pitch, rW, rH1, 0, 0, 0); -#endif - - SDL_UnlockSurface(_mouseSurface); - SDL_UnlockSurface(_mouseOrigSurface); -} - -#ifndef DISABLE_SCALERS -// 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; -} -#endif - -void OSystem_SDL::toggleMouseGrab() { - if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) - SDL_WM_GrabInput(SDL_GRAB_ON); - else - SDL_WM_GrabInput(SDL_GRAB_OFF); -} - -void OSystem_SDL::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_SDL::drawMouse() { - if (!_mouseVisible || !_mouseSurface) { - _mouseBackup.x = _mouseBackup.y = _mouseBackup.w = _mouseBackup.h = 0; - return; - } - - SDL_Rect dst; - int scale; - int width, height; - int hotX, hotY; - - 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; - - // 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 - - -#ifdef USE_OSD -void OSystem_SDL::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; -} -#endif - - -#pragma mark - -#pragma mark --- Misc --- -#pragma mark - - -void OSystem_SDL::handleScalerHotkeys(const SDL_KeyboardEvent &key) { - // Ctrl-Alt-a toggles aspect ratio correction - if (key.keysym.sym == 'a') { - setFeatureState(kFeatureAspectRatioCorrection, !_adjustAspectRatio); -#ifdef USE_OSD - 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); -#endif - - 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); -#ifdef USE_OSD - 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); - } - } -#endif - - } - -} diff --git a/backends/sdl/module.mk b/backends/sdl/module.mk deleted file mode 100644 index fd9e314076..0000000000 --- a/backends/sdl/module.mk +++ /dev/null @@ -1,12 +0,0 @@ -MODULE := backends/sdl - -MODULE_OBJS := \ - events.o \ - graphics.o \ - sdl.o - -MODULE_DIRS += \ - backends/sdl/ - -# We don't use the rules.mk here on purpose -OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) diff --git a/backends/sdl/sdl-common.h b/backends/sdl/sdl-common.h deleted file mode 100644 index f4c9383c63..0000000000 --- a/backends/sdl/sdl-common.h +++ /dev/null @@ -1,392 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * 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 SDL_COMMON_H -#define SDL_COMMON_H - -#include - -#include "common/stdafx.h" -#include "common/scummsys.h" -#include "common/system.h" -#include "graphics/scaler.h" -#include "backends/intern.h" - - -#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) -// Uncomment this to enable the 'on screen display' code. -#define USE_OSD 1 -#endif - - -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_SDL : public OSystem { -public: - OSystem_SDL(); - virtual ~OSystem_SDL(); - - virtual void initBackend(); - - void beginGFXTransaction(void); - void endGFXTransaction(void); - - // Set the size of the video bitmap. - // Typically, 320x200 - virtual void initSize(uint w, uint h); // overloaded by CE backend - - // 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 - virtual void copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h); // overloaded by CE backend (FIXME) - - // 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. - virtual void warpMouse(int x, int y); // overloaded by CE backend (FIXME) - - // Set the bitmap that's used when drawing the cursor. - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale); // overloaded by CE backend (FIXME) - - // 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 - virtual void showOverlay(); // WinCE FIXME - virtual void hideOverlay(); // WinCE FIXME - virtual void clearOverlay(); - virtual void grabOverlay(OverlayColor *buf, int pitch); - virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); // WinCE FIXME - virtual int16 getHeight(); - virtual int16 getWidth(); - virtual int16 getOverlayHeight() { return _overlayHeight; } - virtual int16 getOverlayWidth() { return _overlayWidth; } - - // Methods that convert RGB to/from colors suitable for the overlay. - virtual OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b); - virtual 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); - -#ifdef USE_OSD - void displayMessageOnOSD(const char *msg); -#endif - -protected: - bool _inited; - -#ifdef USE_OSD - 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 - }; -#endif - - // 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; - - /** True if aspect ratio correction is enabled. */ - bool _adjustAspectRatio; - - 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; - byte _mouseKeyColor; - int _cursorTargetScale; - bool _cursorPaletteDisabled; - SDL_Surface *_mouseOrigSurface; - SDL_Surface *_mouseSurface; - enum { - kMouseColorKey = 1 - }; - - // joystick - SDL_Joystick *_joystick; - - // 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); // overloaded by CE backend - - virtual void drawMouse(); // overloaded by CE backend - virtual void undrawMouse(); // overloaded by CE backend (FIXME) - virtual void blitCursor(); // overloaded by CE backend (FIXME) - - /** Set the position of the virtual mouse cursor. */ - void setMousePos(int x, int y); - virtual void fillMouseEvent(Event &event, int x, int y); // overloaded by CE backend - void toggleMouseGrab(); - - virtual void internUpdateScreen(); // overloaded by CE backend - - virtual void loadGFXMode(); // overloaded by CE backend - virtual void unloadGFXMode(); // overloaded by CE backend - virtual void hotswapGFXMode(); // overloaded by CE backend - - void setFullscreenMode(bool enable); - void setAspectRatioCorrection(bool enable); - - virtual bool saveScreenshot(const char *filename); // overloaded by CE backend - - 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); -}; - -#endif diff --git a/backends/sdl/sdl.cpp b/backends/sdl/sdl.cpp deleted file mode 100644 index dce70bc780..0000000000 --- a/backends/sdl/sdl.cpp +++ /dev/null @@ -1,488 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "backends/sdl/sdl-common.h" -#include "common/config-manager.h" -#include "common/util.h" -#include "base/main.h" - -#include "icons/scummvm.xpm" - -#if defined(__SYMBIAN32__) -#include "SymbianOs.h" -#endif - -#if !defined(_WIN32_WCE) && !defined(__MAEMO__) - -#if defined (WIN32) -int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpCmdLine*/, int /*iShowCmd*/) { - SDL_SetModuleHandle(GetModuleHandle(NULL)); - return main(__argc, __argv); -} -#endif - -int main(int argc, char *argv[]) { - -#if defined(__SYMBIAN32__) - // - // Set up redirects for stdout/stderr under Windows and Symbian. - // Code copied from SDL_main. - // - - // Symbian does not like any output to the console through any *print* function - char STDOUT_FILE[256], STDERR_FILE[256]; // shhh, don't tell anybody :) - strcpy(STDOUT_FILE, Symbian::GetExecutablePath()); - strcpy(STDERR_FILE, Symbian::GetExecutablePath()); - strcat(STDOUT_FILE, "scummvm.stdout.txt"); - strcat(STDERR_FILE, "scummvm.stderr.txt"); - - /* Flush the output in case anything is queued */ - fclose(stdout); - fclose(stderr); - - /* Redirect standard input and standard output */ - FILE *newfp = freopen(STDOUT_FILE, "w", stdout); - if (newfp == NULL) { /* This happens on NT */ -#if !defined(stdout) - stdout = fopen(STDOUT_FILE, "w"); -#else - newfp = fopen(STDOUT_FILE, "w"); - if (newfp) { - *stdout = *newfp; - } -#endif - } - newfp = freopen(STDERR_FILE, "w", stderr); - if (newfp == NULL) { /* This happens on NT */ -#if !defined(stderr) - stderr = fopen(STDERR_FILE, "w"); -#else - newfp = fopen(STDERR_FILE, "w"); - if (newfp) { - *stderr = *newfp; - } -#endif - } - setbuf(stderr, NULL); /* No buffering */ - -#endif // defined(__SYMBIAN32__) - - // Create our OSystem instance -#if defined(__SYMBIAN32__) - g_system = new OSystem_SDL_Symbian(); -#else - g_system = new OSystem_SDL(); -#endif - assert(g_system); - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - g_system->quit(); // TODO: Consider removing / replacing this! - return res; -} -#endif - -void OSystem_SDL::initBackend() { - assert(!_inited); - - 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; - -#ifdef _WIN32_WCE - if (ConfMan.hasKey("use_GDI") && ConfMan.getBool("use_GDI")) { - SDL_VideoInit("windib", 0); - sdlFlags ^= SDL_INIT_VIDEO; - } -#endif - - if (joystick_num > -1) - sdlFlags |= SDL_INIT_JOYSTICK; - - if (SDL_Init(sdlFlags) == -1) { - error("Could not initialize SDL: %s", SDL_GetError()); - } - - _graphicsMutex = createMutex(); - - SDL_ShowCursor(SDL_DISABLE); - - // Enable unicode support if possible - SDL_EnableUNICODE(1); - - _cksumValid = false; -#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) && !defined(DISABLE_SCALERS) - _mode = GFX_DOUBLESIZE; - _scaleFactor = 2; - _scalerProc = Normal2x; - _fullscreen = ConfMan.getBool("fullscreen"); - _adjustAspectRatio = ConfMan.getBool("aspect_ratio"); -#else // for small screen platforms - _mode = GFX_NORMAL; - _scaleFactor = 1; - _scalerProc = Normal1x; - -#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) - _fullscreen = ConfMan.getBool("fullscreen"); -#else - _fullscreen = true; -#endif - - _adjustAspectRatio = false; -#endif - _scalerType = 0; - _modeFlags = 0; - -#if !defined(MACOSX) && !defined(__SYMBIAN32__) // Don't set icon on OS X, as we use a nicer external icon there - setupIcon(); // Don't for Symbian: it uses the EScummVM.aif file for the icon -#endif - - // enable joystick - if (joystick_num > -1 && SDL_NumJoysticks() > 0) { - printf("Using joystick: %s\n", SDL_JoystickName(0)); - _joystick = SDL_JoystickOpen(joystick_num); - } - - _inited = true; -} - -OSystem_SDL::OSystem_SDL() - : -#ifdef USE_OSD - _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0), -#endif - _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), _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_SDL::~OSystem_SDL() { - free(_dirtyChecksums); - free(_currentPalette); - free(_cursorPalette); - free(_mouseData); -} - -uint32 OSystem_SDL::getMillis() { - return SDL_GetTicks(); -} - -void OSystem_SDL::delayMillis(uint msecs) { - SDL_Delay(msecs); -} - -void OSystem_SDL::setTimerCallback(TimerProc callback, int timer) { - SDL_SetTimer(timer, (SDL_TimerCallback) callback); -} - -void OSystem_SDL::setWindowCaption(const char *caption) { - SDL_WM_SetCaption(caption, caption); -} - -bool OSystem_SDL::hasFeature(Feature f) { - return - (f == kFeatureFullscreenMode) || - (f == kFeatureAspectRatioCorrection) || - (f == kFeatureAutoComputeDirtyRects) || - (f == kFeatureCursorHasPalette); -} - -void OSystem_SDL::setFeatureState(Feature f, bool enable) { - switch (f) { - case kFeatureFullscreenMode: - setFullscreenMode(enable); - break; - 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_SDL::getFeatureState(Feature f) { - assert (_transactionMode == kTransactionNone); - - switch (f) { - case kFeatureFullscreenMode: - return _fullscreen; - case kFeatureAspectRatioCorrection: - return _adjustAspectRatio; - case kFeatureAutoComputeDirtyRects: - return _modeFlags & DF_WANT_RECT_OPTIM; - default: - return false; - } -} - -void OSystem_SDL::quit() { - if (_cdrom) { - SDL_CDStop(_cdrom); - SDL_CDClose(_cdrom); - } - unloadGFXMode(); - deleteMutex(_graphicsMutex); - - if (_joystick) - SDL_JoystickClose(_joystick); - SDL_ShowCursor(SDL_ENABLE); - SDL_Quit(); - - exit(0); -} - -void OSystem_SDL::setupIcon() { - int w, h, ncols, nbytes, i; - unsigned int rgba[256], icon[32 * 32]; - unsigned char mask[32][4]; - - sscanf(scummvm_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes); - if ((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1)) { - warning("Could not load the icon (%d %d %d %d)", w, h, ncols, nbytes); - return; - } - for (i = 0; i < ncols; i++) { - unsigned char code; - char color[32]; - unsigned int col; - sscanf(scummvm_icon[1 + i], "%c c %s", &code, color); - if (!strcmp(color, "None")) - col = 0x00000000; - else if (!strcmp(color, "black")) - col = 0xFF000000; - else if (color[0] == '#') { - sscanf(color + 1, "%06x", &col); - col |= 0xFF000000; - } else { - warning("Could not load the icon (%d %s - %s) ", code, color, scummvm_icon[1 + i]); - return; - } - - rgba[code] = col; - } - memset(mask, 0, sizeof(mask)); - for (h = 0; h < 32; h++) { - const char *line = scummvm_icon[1 + ncols + h]; - for (w = 0; w < 32; w++) { - icon[w + 32 * h] = rgba[(int)line[w]]; - if (rgba[(int)line[w]] & 0xFF000000) { - mask[h][w >> 3] |= 1 << (7 - (w & 0x07)); - } - } - } - - SDL_Surface *sdl_surf = SDL_CreateRGBSurfaceFrom(icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); - SDL_WM_SetIcon(sdl_surf, (unsigned char *) mask); - SDL_FreeSurface(sdl_surf); -} - -OSystem::MutexRef OSystem_SDL::createMutex(void) { - return (MutexRef) SDL_CreateMutex(); -} - -void OSystem_SDL::lockMutex(MutexRef mutex) { - SDL_mutexP((SDL_mutex *) mutex); -} - -void OSystem_SDL::unlockMutex(MutexRef mutex) { - SDL_mutexV((SDL_mutex *) mutex); -} - -void OSystem_SDL::deleteMutex(MutexRef mutex) { - SDL_DestroyMutex((SDL_mutex *) mutex); -} - -#pragma mark - -#pragma mark --- Audio --- -#pragma mark - - -bool OSystem_SDL::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; - - // Originally, we always used 2048 samples. This loop will produce the - // same result at 22050 Hz, and should hopefully produce something - // sensible for other frequencies. Note that it must be a power of two. - - uint32 samples = 0x8000; - - for (;;) { - if ((1000 * samples) / _samplesPerSec < 100) - break; - samples >>= 1; - } - - desired.freq = _samplesPerSec; - desired.format = AUDIO_S16SYS; - desired.channels = 2; - desired.samples = (uint16)samples; - desired.callback = proc; - desired.userdata = param; - if (SDL_OpenAudio(&desired, &obtained) != 0) { - warning("Could not open audio device: %s", SDL_GetError()); - return false; - } - // Note: This should be the obtained output rate, but it seems that at - // least on some platforms SDL will lie and claim it did get the rate - // even if it didn't. Probably only happens for "weird" rates, though. - _samplesPerSec = obtained.freq; - SDL_PauseAudio(0); - return true; -} - -void OSystem_SDL::clearSoundCallback() { - SDL_CloseAudio(); -} - -int OSystem_SDL::getOutputSampleRate() const { - return _samplesPerSec; -} - -#pragma mark - -#pragma mark --- CD Audio --- -#pragma mark - - -bool OSystem_SDL::openCD(int drive) { - if (SDL_InitSubSystem(SDL_INIT_CDROM) == -1) - _cdrom = NULL; - else { - _cdrom = SDL_CDOpen(drive); - // Did it open? Check if _cdrom is NULL - if (!_cdrom) { - warning("Couldn't open drive: %s", SDL_GetError()); - } else { - _cdNumLoops = 0; - _cdStopTime = 0; - _cdEndTime = 0; - } - } - - return (_cdrom != NULL); -} - -void OSystem_SDL::stopCD() { /* Stop CD Audio in 1/10th of a second */ - _cdStopTime = SDL_GetTicks() + 100; - _cdNumLoops = 0; -} - -void OSystem_SDL::playCD(int track, int num_loops, int start_frame, int duration) { - if (!num_loops && !start_frame) - return; - - if (!_cdrom) - return; - - if (duration > 0) - duration += 5; - - _cdTrack = track; - _cdNumLoops = num_loops; - _cdStartFrame = start_frame; - - SDL_CDStatus(_cdrom); - if (start_frame == 0 && duration == 0) - SDL_CDPlayTracks(_cdrom, track, 0, 1, 0); - else - SDL_CDPlayTracks(_cdrom, track, start_frame, 0, duration); - _cdDuration = duration; - _cdStopTime = 0; - _cdEndTime = SDL_GetTicks() + _cdrom->track[track].length * 1000 / CD_FPS; -} - -bool OSystem_SDL::pollCD() { - if (!_cdrom) - return false; - - return (_cdNumLoops != 0 && (SDL_GetTicks() < _cdEndTime || SDL_CDStatus(_cdrom) != CD_STOPPED)); -} - -void OSystem_SDL::updateCD() { - if (!_cdrom) - return; - - if (_cdStopTime != 0 && SDL_GetTicks() >= _cdStopTime) { - SDL_CDStop(_cdrom); - _cdNumLoops = 0; - _cdStopTime = 0; - return; - } - - if (_cdNumLoops == 0 || SDL_GetTicks() < _cdEndTime) - return; - - if (_cdNumLoops != 1 && SDL_CDStatus(_cdrom) != CD_STOPPED) { - // Wait another second for it to be done - _cdEndTime += 1000; - return; - } - - if (_cdNumLoops > 0) - _cdNumLoops--; - - if (_cdNumLoops != 0) { - if (_cdStartFrame == 0 && _cdDuration == 0) - SDL_CDPlayTracks(_cdrom, _cdTrack, 0, 1, 0); - else - SDL_CDPlayTracks(_cdrom, _cdTrack, _cdStartFrame, 0, _cdDuration); - _cdEndTime = SDL_GetTicks() + _cdrom->track[_cdTrack].length * 1000 / CD_FPS; - } -} diff --git a/backends/symbian/src/SymbianOS.h b/backends/symbian/src/SymbianOS.h index 4e8dbeb983..955f59c59c 100644 --- a/backends/symbian/src/SymbianOS.h +++ b/backends/symbian/src/SymbianOS.h @@ -25,7 +25,7 @@ #ifndef SDLSYMBIANH #define SDLSYMBIANH -#include "backends/sdl/sdl-common.h" +#include "backends/platform/sdl/sdl-common.h" /** Vibration support */ #ifdef USE_VIBRA_SE_PXXX diff --git a/backends/wince/wince-sdl.h b/backends/wince/wince-sdl.h index f9715272a5..ae1d252f2d 100644 --- a/backends/wince/wince-sdl.h +++ b/backends/wince/wince-sdl.h @@ -28,7 +28,7 @@ #include "common/system.h" #include "graphics/scaler.h" #include "backends/intern.h" -#include "backends/sdl/sdl-common.h" +#include "backends/platform/sdl/sdl-common.h" #include "CEgui.h" #include "CEkeys.h" diff --git a/backends/x11/build.rules b/backends/x11/build.rules deleted file mode 100644 index 1540d452d6..0000000000 --- a/backends/x11/build.rules +++ /dev/null @@ -1,7 +0,0 @@ -# Build settings for the X11 backend -MODULES += backends/x11 -OBJS += backends/x11/x11.o -DEFINES += -DUNIX -DX11_BACKEND -LDFLAGS += -L/usr/X11R6/lib -L/usr/local/lib -INCLUDES+= -I/usr/X11R6/include -LIBS += -lpthread -lXext -lX11 diff --git a/backends/x11/module.mk b/backends/x11/module.mk deleted file mode 100644 index 7350708299..0000000000 --- a/backends/x11/module.mk +++ /dev/null @@ -1,10 +0,0 @@ -MODULE := backends/x11 - -MODULE_OBJS := \ - x11.o - -MODULE_DIRS += \ - backends/x11/ - -# We don't use the rules.mk here on purpose -OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS) diff --git a/backends/x11/x11.cpp b/backends/x11/x11.cpp deleted file mode 100644 index 8039bd8c26..0000000000 --- a/backends/x11/x11.cpp +++ /dev/null @@ -1,1037 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * 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$ - * - */ - -/* The bare pure X11 port done by Lionel 'BBrox' Ulmer */ - -#include "common/stdafx.h" -#include "common/scummsys.h" -#include "common/system.h" -#include "common/util.h" -#include "base/main.h" -#include "backends/intern.h" - -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include - -#ifdef __linux__ -#include -#else -#include -#endif - -#include -#include - -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) { - g_system = OSystem_X11::create(0, 0); - assert(g_system); - - // Invoke the actual ScummVM main entry point: - int res = scummvm_main(argc, argv); - g_system->quit(); // TODO: Consider removing / replacing this! - return res; -} - -OSystem *OSystem_X11::create(int gfx_mode, bool full_screen) { - OSystem_X11 *syst = new OSystem_X11(); - return syst; -} - -OSystem_X11::OSystem_X11() { - /* Some members initialization */ - _fake_right_mouse = 0; - _report_presses = 1; - _current_shake_pos = 0; - _new_shake_pos = 0; - _palette_changed = false; - _num_of_dirty_rects = 0; - _overlay_visible = false; - _mouse_state_changed = true; - _mouse_visible = true; - _ms_buf = NULL; - _curMouseState.x = 0; - _curMouseState.y = 0; - _curMouseState.hot_x = 0; - _curMouseState.hot_y = 0; - _curMouseState.w = 0; - _curMouseState.h = 0; - _palette16 = 0; - _palette32 = 0; - _bytesPerPixel = 0; - _image = 0; - _local_fb = 0; - _local_fb_overlay = 0; -} - -OSystem_X11::~OSystem_X11() { - XFree(_image); - if (_palette16) - free(_palette16); - - if (_palette32) - free(_palette32); - - if (_ms_buf) - free(_ms_buf); - - free(_local_fb_overlay); - free(_local_fb); -} - -void OSystem_X11::initBackend() { - char buf[512]; - XWMHints *wm_hints; - XGCValues values; - XTextProperty window_name; - char *name = (char *)&buf; - /* For the_window title */ - sprintf(buf, "ScummVM"); - - _display = XOpenDisplay(NULL); - if (_display == NULL) { - error("Could not open display !\n"); - exit(1); - } - - if (XShmQueryExtension(_display)!=True) - error("No Shared Memory Extension present"); - - _screen = DefaultScreen(_display); - _depth = DefaultDepth(_display, _screen); - switch (_depth) { - case 16 : - _bytesPerPixel = 2; - break; - case 24 : - case 32 : - _bytesPerPixel = 4; - break; - } - - if (!_bytesPerPixel) - error("Your screen depth is %ibit. Values other than 16, 24 and 32bit are currently not supported", _depth); - - _window_width = 320; - _window_height = 200; - _scumm_x = 0; - _scumm_y = 0; - _window = XCreateSimpleWindow(_display, XRootWindow(_display, _screen), 0, 0, 320, 200, 0, 0, 0); - wm_hints = XAllocWMHints(); - if (wm_hints == NULL) { - error("Not enough memory to allocate Hints !\n"); - exit(1); - } - wm_hints->flags = InputHint | StateHint; - wm_hints->input = True; - wm_hints->initial_state = NormalState; - XStringListToTextProperty(&name, 1, &window_name); - XSetWMProperties(_display, _window, &window_name, &window_name, - NULL /* argv */ , 0 /* argc */ , NULL /* size hints */ , - wm_hints, NULL /* class hints */ ); - XFree(wm_hints); - - XSelectInput(_display, _window, - ExposureMask | KeyPressMask | KeyReleaseMask | - PointerMotionMask | ButtonPressMask | ButtonReleaseMask | StructureNotifyMask); - - values.foreground = BlackPixel(_display, _screen); - _black_gc = XCreateGC(_display, _window, GCForeground, &values); - - XMapWindow(_display, _window); - XFlush(_display); - - _fb_width = 0; - _fb_height = 0; - - if (!_palette16) - _palette16 = (uint16 *)calloc(256, sizeof(uint16)); - if (!_palette32 && _bytesPerPixel == 4) - _palette32 = (uint32 *)calloc(256, sizeof(uint32)); - - while (1) { - XEvent event; - XNextEvent(_display, &event); - switch (event.type) { - case Expose: - goto out_of_loop; - } - } -out_of_loop: - create_empty_cursor(); - - /* Initialize the timer routines */ - _timer_active = false; - - /* And finally start the local timer */ - gettimeofday(&_start_time, NULL); - -} - -#undef CAPTURE_SOUND -#define FRAG_SIZE 4096 - -static void *sound_and_music_thread(void *params) { - /* Init sound */ - int sound_fd, param, frag_size; - uint8 sound_buffer[FRAG_SIZE]; - OSystem::SoundProc sound_proc = ((THREAD_PARAM *)params)->sound_proc; - void *proc_param = ((THREAD_PARAM *)params)->param; - -#ifdef CAPTURE_SOUND - FILE *f = fopen("sound.raw", "wb"); -#endif - - sound_fd = open("/dev/dsp", O_WRONLY); - audio_buf_info info; - if (sound_fd < 0) { - warning("Error opening sound device!\n"); - return NULL; - } - param = 0; - frag_size = FRAG_SIZE /* audio fragment size */ ; - while (frag_size) { - frag_size >>= 1; - param++; - } - param--; - param |= /* audio_fragment_num */ 3 << 16; - if (ioctl(sound_fd, SNDCTL_DSP_SETFRAGMENT, ¶m) != 0) { - warning("Error in the SNDCTL_DSP_SETFRAGMENT ioctl!\n"); - return NULL; - } - param = AFMT_S16_LE; - if (ioctl(sound_fd, SNDCTL_DSP_SETFMT, ¶m) == -1) { - warning("Error in the SNDCTL_DSP_SETFMT ioctl!\n"); - return NULL;; - } - if (param != AFMT_S16_LE) { - warning("AFMT_S16_LE not supported!\n"); - return NULL; - } - param = 2; - if (ioctl(sound_fd, SNDCTL_DSP_CHANNELS, ¶m) == -1) { - warning("Error in the SNDCTL_DSP_CHANNELS ioctl!\n"); - return NULL; - } - if (param != 2) { - warning("Stereo mode not supported!\n"); - return NULL; - } - param = SAMPLES_PER_SEC; - if (ioctl(sound_fd, SNDCTL_DSP_SPEED, ¶m) == -1) { - warning("Error in the SNDCTL_DSP_SPEED ioctl!\n"); - return NULL; - } - if (param != SAMPLES_PER_SEC) { - warning("%d kHz not supported!\n", SAMPLES_PER_SEC); - return NULL; - } - if (ioctl(sound_fd, SNDCTL_DSP_GETOSPACE, &info) != 0) { - warning("SNDCTL_DSP_GETOSPACE"); - return NULL; - } - - sched_yield(); - while (1) { - uint8 *buf = (uint8 *)sound_buffer; - int size, written; - - sound_proc(proc_param, (byte *)sound_buffer, FRAG_SIZE); -#ifdef CAPTURE_SOUND - fwrite(buf, 2, FRAG_SIZE >> 1, f); - fflush(f); -#endif - size = FRAG_SIZE; - while (size > 0) { - written = write(sound_fd, buf, size); - buf += written; - size -= written; - } - } - - return NULL; -} - -/* Function used to hide the mouse cursor */ -void OSystem_X11::create_empty_cursor() { - XColor bg; - Pixmap pixmapBits; - Cursor cursor = None; - static const char data[] = { 0 }; - - bg.red = bg.green = bg.blue = 0x0000; - pixmapBits = XCreateBitmapFromData(_display, XRootWindow(_display, _screen), data, 1, 1); - if (pixmapBits) { - cursor = XCreatePixmapCursor(_display, pixmapBits, pixmapBits, &bg, &bg, 0, 0); - XFreePixmap(_display, pixmapBits); - } - XDefineCursor(_display, _window, cursor); -} - -bool OSystem_X11::hasFeature(Feature f) { - return false; -} - -void OSystem_X11::setFeatureState(Feature f, bool enable) { -} - -bool OSystem_X11::getFeatureState(Feature f) { - return false; -} - -const OSystem::GraphicsMode *OSystem_X11::getSupportedGraphicsModes() const { - static const OSystem::GraphicsMode mode = {"1x", "Normal mode", 0}; - return &mode; -} - -int OSystem_X11::getDefaultGraphicsMode() const { - return 0; -} - -bool OSystem_X11::setGraphicsMode(int mode) { - return (mode == 0); -} - -int OSystem_X11::getGraphicsMode() const { - return 0; -} - - -uint32 OSystem_X11::getMillis() { - struct timeval current_time; - gettimeofday(¤t_time, NULL); - return (uint32)(((current_time.tv_sec - _start_time.tv_sec) * 1000) + - ((current_time.tv_usec - _start_time.tv_usec) / 1000)); -} - -void OSystem_X11::initSize(uint w, uint h) { - //debug("initSize(%i, %i)", w, h); - static XShmSegmentInfo shminfo; - - if (((uint)_fb_width != w) || ((uint)_fb_height != w)) { - _fb_width = w; - _fb_height = h; - - /* We need to change the size of the X11_window */ - XWindowChanges new_values; - - new_values.width = _fb_width; - new_values.height = _fb_height; - - XConfigureWindow(_display,_window, CWWidth | CWHeight, &new_values); - - if (_image) - XFree(_image); - _image = XShmCreateImage(_display, DefaultVisual(_display, _screen), _depth, ZPixmap, NULL, &shminfo,_fb_width,_fb_height); - if (!_image) - error("Couldn't get image by XShmCreateImage()"); - - shminfo.shmid = shmget(IPC_PRIVATE, _image->bytes_per_line * _image->height, IPC_CREAT | 0700); - if (shminfo.shmid < 0) - error("Couldn't allocate image data by shmget()"); - - _image->data = shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0); - shminfo.readOnly = False; - if (XShmAttach(_display, &shminfo) == 0) { - error("Could not attach shared memory segment !\n"); - exit(1); - } - shmctl(shminfo.shmid, IPC_RMID, 0); - - if (_local_fb) - free(_local_fb); - if (_local_fb_overlay) - free(_local_fb_overlay); - /* Initialize the 'local' frame buffer and the palette */ - _local_fb = (uint8 *)calloc(_fb_width * _fb_height, sizeof(uint8)); - _local_fb_overlay = (uint16 *)calloc(_fb_width * _fb_height, sizeof(uint16)); - - } -} - -bool OSystem_X11::setSoundCallback(SoundProc proc, void *param) { - static THREAD_PARAM thread_param; - - /* And finally start the music thread */ - thread_param.param = param; - thread_param.sound_proc = proc; - - pthread_create(&_sound_thread, NULL, sound_and_music_thread, (void *)&thread_param); - - return true; -} - -void OSystem_X11::clearSoundCallback() { - // TODO implement this... - // The sound_thread has to be stopped in a nice way. In particular, - // using pthread_kill would be a bad idea. Rather, use pthread_cancel, - // or maybe a global variable, to achieve this. - // This method shouldn't return until the sound thread really has stopped. -} - - -void OSystem_X11::setPalette(const byte *colors, uint start, uint num) { - uint16 *pal = &(_palette16[start]); - const byte *data = colors; - - if (_bytesPerPixel == 4) { - for (uint i = start; i < start+num; i++) { - //_palette32[i] = ((uint32 *)colors)[i]; - _palette32[i] = (colors[i * 4 + 0] << 16) | (colors[i * 4 + 1] << 8) | (colors[i * 4 + 2] << 0); - } - } - - do { - *pal++ = ((data[0] & 0xF8) << 8) | ((data[1] & 0xFC) << 3) | (data[2] >> 3); - data += 4; - num--; - } while (num > 0); - - _palette_changed = true; -} - -#define AddDirtyRec(xi,yi,wi,hi) \ - if (_num_of_dirty_rects < MAX_NUMBER_OF_DIRTY_RECTS) { \ - _ds[_num_of_dirty_rects].x = xi; \ - _ds[_num_of_dirty_rects].y = yi; \ - _ds[_num_of_dirty_rects].w = wi; \ - _ds[_num_of_dirty_rects].h = hi; \ - _num_of_dirty_rects++; \ - } - -void OSystem_X11::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { - uint8 *dst; - - if (y < 0) { - h += y; - buf -= y * pitch; - y = 0; - } - if (h > (_fb_height - y)) { - h = _fb_height - y; - } - - dst = _local_fb + _fb_width * y + x; - - if (h <= 0) - return; - - AddDirtyRec(x, y, w, h); - while (h-- > 0) { - memcpy(dst, buf, w); - dst +=_fb_width; - buf += pitch; - } -} - -void OSystem_X11::blit(const DirtyRect *d, uint16 *dst, int pitch) { - uint8 *ptr_src = _local_fb + (_fb_width * d->y) + d->x; - uint16 *ptr_dst = dst + ((_fb_width * d->y) + d->x); - int x, y; - - for (y = 0; y < d->h; y++) { - for (x = 0; x < d->w; x++) { - *ptr_dst++ = _palette16[*ptr_src++]; - } - ptr_dst += pitch - d->w; - ptr_src +=_fb_width - d->w; - } -} - -void OSystem_X11::blit_convert(const DirtyRect *d, uint8 *dst, int pitch) { - uint8 *ptr_src = _local_fb + (_fb_width * d->y) + d->x; - uint8 *ptr_dst = dst + ((_fb_width * d->y) + d->x) * _bytesPerPixel; - int x, y; - - switch (_bytesPerPixel) { - case 2: - for (y = 0; y < d->h; y++) { - for (x = 0; x < d->w; x++) { - *ptr_dst = _palette16[*ptr_src++]; - ptr_dst += _bytesPerPixel; - } - ptr_dst += (pitch - d->w) * _bytesPerPixel; - ptr_src +=_fb_width - d->w; - } - break; - case 4: - for (y = 0; y < d->h; y++) { - for (x = 0; x < d->w; x++) { - *(uint32 *)ptr_dst = _palette32[*ptr_src]; - ptr_dst += _bytesPerPixel; - ptr_src++; - } - ptr_dst += (pitch - d->w) * _bytesPerPixel; - ptr_src += _fb_width - d->w; - } - } -} - -void OSystem_X11::updateScreen_helper(const DirtyRect *d, DirtyRect *dout) { - - if (_overlay_visible == false) { - blit_convert(d, (uint8 *)_image->data, _fb_width); - } else { - uint16 *ptr_src = _local_fb_overlay + (_fb_width * d->y) + d->x; - uint8 *ptr_dst = (uint8 *)_image->data + ((_fb_width * d->y) + d->x) * _bytesPerPixel; - - int y; - - switch (_bytesPerPixel) { - case 2: - for (y = 0; y < d->h; y++) { - memcpy(ptr_dst, ptr_src, d->w * sizeof(uint16)); - ptr_dst += _fb_width * sizeof(uint16); - ptr_src += _fb_width; - } - break; - case 4: - uint16 currLine, x; - register uint16 currPixel; - for (y = d->y; y < d->y + d->h; y++) { - currLine = y * _fb_width; - for (x = d->x; x < d->x + d->w; x++) { - currPixel = _local_fb_overlay[(currLine + x)]; - *(uint32 *)ptr_dst = ((currPixel & 0xF800) << 8) + ((currPixel & 0x07E0) << 5) + - ((currPixel & 0x001F) << 3); - ptr_dst += sizeof(uint32); - } - ptr_dst += (_fb_width - d->w) * _bytesPerPixel; - } - - } - } - if (d->x < dout->x) - dout->x = d->x; - if (d->y < dout->y) - dout->y = d->y; - if ((d->x + d->w) > dout->w) - dout->w = d->x + d->w; - if ((d->y + d->h) > dout->h) - dout->h = d->y + d->h; -} - -void OSystem_X11::updateScreen() { - bool full_redraw = false; - bool need_redraw = false; - static const DirtyRect ds_full = { 0, 0, _fb_width, _fb_height }; - DirtyRect dout = {_fb_width, _fb_height, 0, 0 }; - - if (_palette_changed) { - full_redraw = true; - _num_of_dirty_rects = 0; - _palette_changed = false; - } else if (_num_of_dirty_rects >= MAX_NUMBER_OF_DIRTY_RECTS) { - full_redraw = true; - _num_of_dirty_rects = 0; - } - - if (full_redraw) { - updateScreen_helper(&ds_full, &dout); - need_redraw = true; - } else if ((_num_of_dirty_rects > 0) || (_mouse_state_changed == true)) { - need_redraw = true; - while (_num_of_dirty_rects > 0) { - _num_of_dirty_rects--; - updateScreen_helper(&(_ds[_num_of_dirty_rects]), &dout); - } - } - - /* Then 'overlay' the mouse on the image */ - draw_mouse(&dout); - - if (_current_shake_pos != _new_shake_pos) { - /* Redraw first the 'black borders' in case of resize */ - if (_current_shake_pos < _new_shake_pos) - XFillRectangle(_display,_window, _black_gc, 0, _current_shake_pos, _window_width, _new_shake_pos); - else - XFillRectangle(_display,_window, _black_gc, 0, _window_height - _current_shake_pos, - _window_width,_window_height - _new_shake_pos); - XShmPutImage(_display, _window, DefaultGC(_display, _screen), _image, - 0, 0, _scumm_x, _scumm_y + _new_shake_pos, _fb_width, _fb_height, 0); - _current_shake_pos = _new_shake_pos; - } else if (need_redraw == true) { - XShmPutImage(_display, _window, DefaultGC(_display, _screen), _image, - dout.x, dout.y, _scumm_x + dout.x, _scumm_y + dout.y + _current_shake_pos, - dout.w - dout.x, dout.h - dout.y, 0); - XFlush(_display); - } -} - -bool OSystem_X11::showMouse(bool visible) -{ - if (_mouse_visible == visible) - return visible; - - bool last = _mouse_visible; - _mouse_visible = visible; - - if ((visible == false) && (_mouse_state_changed == false)) { - undraw_mouse(); - } - _mouse_state_changed = true; - - return last; -} - -void OSystem_X11::quit() { - exit(0); -} - -void OSystem_X11::setWindowCaption(const char *caption) { - //debug("setWindowCaption('%s')", caption); -} - -void OSystem_X11::undraw_mouse() { - AddDirtyRec(_oldMouseState.x, _oldMouseState.y, _oldMouseState.w, _oldMouseState.h); -} - -void OSystem_X11::draw_mouse(DirtyRect *dout) { - //debug("draw_mouse()"); - _mouse_state_changed = false; - - if (_mouse_visible == false) - return; - - int xdraw = _curMouseState.x - _curMouseState.hot_x; - int ydraw = _curMouseState.y - _curMouseState.hot_y; - int w = _curMouseState.w; - int h = _curMouseState.h; - int real_w; - int real_h; - - uint8 *dst; - const byte *buf = _ms_buf; - - if (ydraw < 0) { - real_h = h + ydraw; - buf += (-ydraw) * w; - ydraw = 0; - } else { - real_h = (ydraw + h) > _fb_height ? (_fb_height - ydraw) : h; - } - if (xdraw < 0) { - real_w = w + xdraw; - buf += (-xdraw); - xdraw = 0; - } else { - real_w = (xdraw + w) > _fb_width ? (_fb_width - xdraw) : w; - } - - dst = (uint8 *)_image->data + ((ydraw *_fb_width) + xdraw) * _bytesPerPixel; - - if ((real_h == 0) || (real_w == 0)) { - return; - } - - - if (xdraw < dout->x) - dout->x = xdraw; - if (ydraw < dout->y) - dout->y = ydraw; - if ((xdraw + real_w) > dout->w) - dout->w = xdraw + real_w; - if ((ydraw + real_h) > dout->h) - dout->h = ydraw + real_h; - - _oldMouseState.x = xdraw; - _oldMouseState.y = ydraw; - _oldMouseState.w = real_w; - _oldMouseState.h = real_h; - - while (real_h > 0) { - int width = real_w; - while (width > 0) { - byte color = *buf; - if (color != _mouseKeycolor) { - if (_depth == 16) - *(uint16 *)dst = _palette16[color]; - else { - *(uint32 *)dst = _palette32[color]; - } - } - buf++; - dst += _bytesPerPixel; - width--; - } - buf += w - real_w; - dst += (_fb_width - real_w) * _bytesPerPixel; - real_h--; - } -} - -void OSystem_X11::set_mouse_pos(int x, int y) { - if ((x != _curMouseState.x) || (y != _curMouseState.y)) { - _curMouseState.x = x; - _curMouseState.y = y; - if (_mouse_state_changed == false) { - undraw_mouse(); - } - _mouse_state_changed = true; - } -} - -void OSystem_X11::warpMouse(int x, int y) { - set_mouse_pos(x, y); -} - -void OSystem_X11::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, byte keycolor, int cursorTargetScale) { - _curMouseState.w = w; - _curMouseState.h = h; - _curMouseState.hot_x = hotspot_x; - _curMouseState.hot_y = hotspot_y; - - if (_ms_buf) - free(_ms_buf); - _ms_buf = (byte *) malloc(w * h); - memcpy(_ms_buf, buf, w * h); - - if (_mouse_state_changed == false) { - undraw_mouse(); - } - _mouseKeycolor = keycolor; - _mouse_state_changed = true; -} - -void OSystem_X11::setShakePos(int shake_pos) { - if (_new_shake_pos != shake_pos) { - if (_mouse_state_changed == false) { - undraw_mouse(); - } - _mouse_state_changed = true; - } - _new_shake_pos = shake_pos; -} - -int OSystem_X11::getOutputSampleRate() const { - return SAMPLES_PER_SEC; -} - -void OSystem_X11::delayMillis(uint msecs) { - usleep(msecs * 1000); -} - -bool OSystem_X11::pollEvent(Event &scumm_event) { - /* First, handle timers */ - uint32 current_msecs = getMillis(); - - if (_timer_active && (current_msecs >= _timer_next_expiry)) { - _timer_duration = _timer_callback(_timer_duration); - _timer_next_expiry = current_msecs + _timer_duration; - } - - while (XPending(_display)) { - XEvent event; - - XNextEvent(_display, &event); - switch (event.type) { - case Expose:{ - int real_w, real_h; - int real_x, real_y; - real_x = event.xexpose.x; - real_y = event.xexpose.y; - real_w = event.xexpose.width; - real_h = event.xexpose.height; - if (real_x < _scumm_x) { - real_w -= _scumm_x - real_x; - real_x = 0; - } else { - real_x -= _scumm_x; - } - if (real_y < _scumm_y) { - real_h -= _scumm_y - real_y; - real_y = 0; - } else { - real_y -= _scumm_y; - } - if ((real_h <= 0) || (real_w <= 0)) - break; - if ((real_x >=_fb_width) || (real_y >=_fb_height)) - break; - - if ((real_x + real_w) >=_fb_width) { - real_w =_fb_width - real_x; - } - if ((real_y + real_h) >=_fb_height) { - real_h =_fb_height - real_y; - } - - /* Compute the intersection of the expose event with the real ScummVM display zone */ - AddDirtyRec(real_x, real_y, real_w, real_h); - } - break; - - case KeyPress:{ - /* I am using keycodes here and NOT keysyms to be sure that even if the user - remaps his iPAQ's keyboard, it will still work. - */ - int keycode = -1; - int ascii = -1; - byte mode = 0; - - if (event.xkey.state & 0x01) - mode |= KBD_SHIFT; - if (event.xkey.state & 0x04) - mode |= KBD_CTRL; - if (event.xkey.state & 0x08) - mode |= KBD_ALT; - switch (event.xkey.keycode) { - - case 9: /* Escape on my PC */ - case 130: /* Calendar on the iPAQ */ - keycode = 27; - break; - - case 71: /* F5 on my PC */ - case 128: /* Record on the iPAQ */ - keycode = 319; - break; - - case 65: /* Space on my PC */ - case 131: /* Schedule on the iPAQ */ - keycode = 32; - break; - - case 132: - _report_presses = 0; - break; - - case 133: - _fake_right_mouse = 1; - break; - - default:{ - KeySym xsym; - xsym = XKeycodeToKeysym(_display, event.xkey.keycode, 0); - keycode = xsym; - if ((xsym >= 'a') && (xsym <= 'z') && (event.xkey.state & 0x01)) - xsym &= ~0x20; /* Handle shifted keys */ - ascii = xsym; - } - } - if (keycode != -1) { - scumm_event.type = EVENT_KEYDOWN; - scumm_event.kbd.keycode = keycode; - scumm_event.kbd.ascii = (ascii != -1 ? ascii : keycode); - scumm_event.kbd.flags = mode; - return true; - } - } - break; - - case KeyRelease:{ - /* I am using keycodes here and NOT keysyms to be sure that even if the user - remaps his iPAQ's keyboard, it will still work. - */ - int keycode = -1; - int ascii = -1; - byte mode = 0; - - if (event.xkey.state & 0x01) - mode |= KBD_SHIFT; - if (event.xkey.state & 0x04) - mode |= KBD_CTRL; - if (event.xkey.state & 0x08) - mode |= KBD_ALT; - switch (event.xkey.keycode) { - case 132: /* 'Q' on the iPAQ */ - _report_presses = 1; - break; - - case 133: /* Arrow on the iPAQ */ - _fake_right_mouse = 0; - break; - - default:{ - KeySym xsym; - xsym = XKeycodeToKeysym(_display, event.xkey.keycode, 0); - keycode = xsym; - if ((xsym >= 'a') && (xsym <= 'z') && (event.xkey.state & 0x01)) - xsym &= ~0x20; /* Handle shifted keys */ - ascii = xsym; - } - } - if (keycode != -1) { - scumm_event.type = EVENT_KEYUP; - scumm_event.kbd.keycode = keycode; - scumm_event.kbd.ascii = (ascii != -1 ? ascii : keycode); - scumm_event.kbd.flags = mode; - return true; - } - } - break; - - case ButtonPress: - if (_report_presses != 0) { - if (event.xbutton.button == 1) { - if (_fake_right_mouse == 0) { - scumm_event.type = EVENT_LBUTTONDOWN; - } else { - scumm_event.type = EVENT_RBUTTONDOWN; - } - } else if (event.xbutton.button == 3) - scumm_event.type = EVENT_RBUTTONDOWN; - scumm_event.mouse.x = event.xbutton.x - _scumm_x; - scumm_event.mouse.y = event.xbutton.y - _scumm_y; - return true; - } - break; - - case ButtonRelease: - if (_report_presses != 0) { - if (event.xbutton.button == 1) { - if (_fake_right_mouse == 0) { - scumm_event.type = EVENT_LBUTTONUP; - } else { - scumm_event.type = EVENT_RBUTTONUP; - } - } else if (event.xbutton.button == 3) - scumm_event.type = EVENT_RBUTTONUP; - scumm_event.mouse.x = event.xbutton.x - _scumm_x; - scumm_event.mouse.y = event.xbutton.y - _scumm_y; - return true; - } - break; - - case MotionNotify: - scumm_event.type = EVENT_MOUSEMOVE; - scumm_event.mouse.x = event.xmotion.x - _scumm_x; - scumm_event.mouse.y = event.xmotion.y - _scumm_y; - set_mouse_pos(scumm_event.mouse.x, scumm_event.mouse.y); - return true; - - case ConfigureNotify:{ - if ((_window_width != event.xconfigure.width) || (_window_height != event.xconfigure.height)) { - _window_width = event.xconfigure.width; - _window_height = event.xconfigure.height; - _scumm_x = (_window_width -_fb_width) / 2; - _scumm_y = (_window_height -_fb_height) / 2; - XFillRectangle(_display, _window, _black_gc, 0, 0, _window_width, _window_height); - } - } - break; - - default: - printf("Unhandled event : %d\n", event.type); - break; - } - } - - return false; -} - -void OSystem_X11::setTimerCallback(TimerProc callback, int interval) { - if (callback != NULL) { - _timer_duration = interval; - _timer_next_expiry = getMillis() + interval; - _timer_callback = callback; - _timer_active = true; - } else { - _timer_active = false; - } -} - -OSystem::MutexRef OSystem_X11::createMutex(void) { - pthread_mutex_t *mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(mutex, NULL); - return (MutexRef)mutex; -} - -void OSystem_X11::lockMutex(MutexRef mutex) { - pthread_mutex_lock((pthread_mutex_t *) mutex); -} - -void OSystem_X11::unlockMutex(MutexRef mutex) { - pthread_mutex_unlock((pthread_mutex_t *) mutex); -} - -void OSystem_X11::deleteMutex(MutexRef mutex) { - pthread_mutex_destroy((pthread_mutex_t *) mutex); - free(mutex); -} - -void OSystem_X11::showOverlay() { - _overlay_visible = true; -} - -void OSystem_X11::hideOverlay() { - _overlay_visible = false; - _palette_changed = true; // This is to force a full redraw to hide the overlay -} - -void OSystem_X11::clearOverlay() { - if (_overlay_visible == false) - return; - DirtyRect d = { 0, 0, _fb_width, _fb_height }; - AddDirtyRec(0, 0, _fb_width, _fb_height); - blit(&d, _local_fb_overlay, _fb_width); -} - -void OSystem_X11::grabOverlay(int16 *dest, int pitch) { - if (_overlay_visible == false) - return; - - DirtyRect d = { 0, 0, _fb_width, _fb_height }; - blit(&d, (uint16 *)dest, pitch); -} - -void OSystem_X11::copyRectToOverlay(const int16 *src, int pitch, int x, int y, int w, int h) { - if (_overlay_visible == false) - return; - uint16 *dst = _local_fb_overlay + x + (y * _fb_width); - AddDirtyRec(x, y, w, h); - while (h > 0) { - memcpy(dst, src, w * sizeof(*dst)); - dst +=_fb_width; - src += pitch; - h--; - } -} - -int16 OSystem_X11::getHeight() { - return _fb_height; -} - -int16 OSystem_X11::getWidth() { - return _fb_width; -} - -void OSystem_X11::grabPalette(byte *colors, uint start, uint num) { - warning("Dummy: grabPalette()"); -} diff --git a/backends/x11/x11.h b/backends/x11/x11.h deleted file mode 100644 index ba29bc7eab..0000000000 --- a/backends/x11/x11.h +++ /dev/null @@ -1,195 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2006 The ScummVM project - * - * 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$ - * - */ - -class OSystem_X11:public OSystem { -public: - OSystem_X11(); - ~OSystem_X11(); - - void initBackend(); - - // Determine whether the backend supports the specified feature. - bool hasFeature(Feature f); - - // En-/disable the specified feature. - void setFeatureState(Feature f, bool enable); - - // Query the state of the specified feature. - bool getFeatureState(Feature f); - - // Retrieve a list of all graphics modes supported by this backend. - const GraphicsMode *getSupportedGraphicsModes() const; - - // Return the ID of the 'default' graphics mode. - int getDefaultGraphicsMode() const; - - // Switch to the specified graphics mode. - bool setGraphicsMode(int mode); - - // Determine which graphics mode is currently active. - int getGraphicsMode() const; - - // Set colors of the palette - void setPalette(const byte *colors, uint start, uint num); - - // Set the size of the video bitmap. - // Typically, 320x200 - void initSize(uint w, uint h); - - // Draw a bitmap to screen. - // The screen will not be updated to reflect the new bitmap - void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); - - // Update the dirty areas of the screen - void updateScreen(); - - // Either show or hide the mouse cursor - bool showMouse(bool visible); - - // Set the position of the mouse cursor - void set_mouse_pos(int x, int y); - - // 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 hotspotX, int hotspotY, byte keycolor = 255, int cursorTargetScale = 1); - - // 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. - bool pollEvent(Event &event); - - // Set function that generates samples - bool setSoundCallback(SoundProc proc, void *param); - void clearSoundCallback(); - - // Determine the output sample rate. Audio data provided by the sound - // callback will be played using this rate. - int getOutputSampleRate() const; - - // Quit - void quit(); - - // Add a callback timer - void setTimerCallback(TimerProc callback, int interval); - - // Mutex handling - MutexRef createMutex(); - void lockMutex(MutexRef mutex); - void unlockMutex(MutexRef mutex); - void deleteMutex(MutexRef mutex); - - // Overlay handling for the new menu system - void showOverlay(); - void hideOverlay(); - void clearOverlay(); - void grabOverlay(int16 *, int); - void copyRectToOverlay(const int16 *, int, int, int, int, int); - virtual int16 getHeight(); - virtual int16 getWidth(); - - virtual void grabPalette(byte *colors, uint start, uint num); - - // Set a window caption or any other comparable status display to the - // given value. - void setWindowCaption(const char *caption); - - static OSystem *create(int gfx_mode, bool full_screen); - -private: - typedef struct { - int x, y; - int w, h; - int hot_x, hot_y; - } MouseState; - - typedef struct { - int x, y, w, h; - } DirtyRect; - - enum { - MAX_NUMBER_OF_DIRTY_RECTS = 32 - }; - - void create_empty_cursor(); - void draw_mouse(DirtyRect *dout); - void undraw_mouse(); - void updateScreen_helper(const DirtyRect *d, DirtyRect *dout); - void blit_convert(const DirtyRect *d, uint8 *dst, int pitch); - void blit(const DirtyRect *d, uint16 *dst, int pitch); - - uint8 *_local_fb; - uint16 *_local_fb_overlay; - bool _overlay_visible; - - int _window_width, _window_height; - int _fb_width, _fb_height; - int _scumm_x, _scumm_y; - - uint16 *_palette16; - uint32 *_palette32; - - bool _palette_changed; - Display *_display; - int _screen, _depth; - uint8 _bytesPerPixel; - Window _window; - GC _black_gc; - XImage *_image; - pthread_t _sound_thread; - - struct timeval _start_time; - - int _fake_right_mouse; - int _report_presses; - int _current_shake_pos; - int _new_shake_pos; - DirtyRect _ds[MAX_NUMBER_OF_DIRTY_RECTS]; - int _num_of_dirty_rects; - - MouseState _oldMouseState, _curMouseState; - byte *_ms_buf; - bool _mouse_visible; - bool _mouse_state_changed; - byte _mouseKeycolor; - - uint32 _timer_duration, _timer_next_expiry; - bool _timer_active; - int (*_timer_callback) (int); -}; - -typedef struct { - OSystem::SoundProc sound_proc; - void *param; -} THREAD_PARAM; -- cgit v1.2.3