From 488bbb267a4a96db51794d424131817a8afc50c6 Mon Sep 17 00:00:00 2001 From: Cpasjuste Date: Thu, 20 Sep 2018 16:33:08 +0200 Subject: SWITCH: add nintendo switch support --- .gitignore | 6 + backends/events/switchsdl/switchsdl-events.cpp | 432 +++++++++++++++++++++++++ backends/events/switchsdl/switchsdl-events.h | 78 +++++ backends/mixer/sdl/sdl-mixer.cpp | 2 +- backends/module.mk | 5 + backends/platform/sdl/module.mk | 6 + backends/platform/sdl/posix/posix-main.cpp | 2 +- backends/platform/sdl/switch/switch-main.cpp | 62 ++++ backends/platform/sdl/switch/switch.cpp | 111 +++++++ backends/platform/sdl/switch/switch.h | 50 +++ backends/platform/sdl/switch/switch.mk | 19 ++ backends/saves/posix/posix-saves.cpp | 3 + configure | 58 +++- dists/switch/icon.jpg | Bin 0 -> 39008 bytes 14 files changed, 825 insertions(+), 9 deletions(-) create mode 100644 backends/events/switchsdl/switchsdl-events.cpp create mode 100644 backends/events/switchsdl/switchsdl-events.h create mode 100644 backends/platform/sdl/switch/switch-main.cpp create mode 100644 backends/platform/sdl/switch/switch.cpp create mode 100644 backends/platform/sdl/switch/switch.h create mode 100644 backends/platform/sdl/switch/switch.mk create mode 100644 dists/switch/icon.jpg diff --git a/.gitignore b/.gitignore index 2708700d6a..49ca3b7819 100644 --- a/.gitignore +++ b/.gitignore @@ -248,6 +248,12 @@ psp2pkg/ *.velf *.vpk +#Ignore Switch files +switch_release/ +scummvm.elf +scummvm.nro +scummvm_switch.zip + #Ignore gmon.out created by gprof gmon.out /scummvm_libs_2015 diff --git a/backends/events/switchsdl/switchsdl-events.cpp b/backends/events/switchsdl/switchsdl-events.cpp new file mode 100644 index 0000000000..64c2b42dfd --- /dev/null +++ b/backends/events/switchsdl/switchsdl-events.cpp @@ -0,0 +1,432 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#if defined(NINTENDO_SWITCH) + +#include + +#include "backends/platform/sdl/switch/switch.h" +#include "backends/events/switchsdl/switchsdl-events.h" +#include "backends/timer/sdl/sdl-timer.h" +#include "backends/platform/sdl/sdl.h" +#include "engines/engine.h" + +#include "common/util.h" +#include "common/events.h" +#include "common/config-manager.h" + +SwitchEventSource::SwitchEventSource() { + for (int port = 0; port < SCE_TOUCH_PORT_MAX_NUM; port++) { + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + _finger[port][i].id = -1; + } + _multiFingerDragging[port] = DRAG_NONE; + } + + for (int port = 0; port < SCE_TOUCH_PORT_MAX_NUM; port++) { + for (int i = 0; i < 2; i++) { + _simulatedClickStartTime[port][i] = 0; + } + } +} + +bool SwitchEventSource::pollEvent(Common::Event &event) { + ((DefaultTimerManager *) g_system->getTimerManager())->handler(); + finishSimulatedMouseClicks(); + return SdlEventSource::pollEvent(event); +} + +void SwitchEventSource::preprocessEvents(SDL_Event *event) { + + // Supported touch gestures: + // left mouse click: single finger short tap + // right mouse click: second finger short tap while first finger is still down + // pointer motion: single finger drag + if (event->type == SDL_FINGERDOWN || event->type == SDL_FINGERUP || event->type == SDL_FINGERMOTION) { + // front (0) or back (1) panel + SDL_TouchID port = event->tfinger.touchId; + //debug(0, "touch: %li\n", port); + if (port < SCE_TOUCH_PORT_MAX_NUM && port >= 0) { + // touchpad_mouse_mode off: use only front panel for direct touch control of pointer + // touchpad_mouse_mode on: also enable rear touch with indirect touch control + // where the finger can be somewhere else than the pointer and still move it + if (port == 0 || ConfMan.getBool("touchpad_mouse_mode")) { + switch (event->type) { + case SDL_FINGERDOWN: + //debug(0, "down[%li]: %i %i", event->tfinger.fingerId, (int) event->tfinger.x, (int) event->tfinger.y); + preprocessFingerDown(event); + break; + case SDL_FINGERUP: + //debug(0, "up[%li]: %i %i", event->tfinger.fingerId, (int) event->tfinger.x, (int) event->tfinger.y); + preprocessFingerUp(event); + break; + case SDL_FINGERMOTION: + //debug(0, "mov[%li]: %i %i", event->tfinger.fingerId, (int) event->tfinger.x, (int) event->tfinger.y); + preprocessFingerMotion(event); + break; + } + } + } + } +} + +void SwitchEventSource::preprocessFingerDown(SDL_Event *event) { + // front (0) or back (1) panel + SDL_TouchID port = event->tfinger.touchId; + // id (for multitouch) + SDL_FingerID id = event->tfinger.fingerId; + + int x = _km.x / MULTIPLIER; + int y = _km.y / MULTIPLIER; + + if (port == 0 && !ConfMan.getBool("touchpad_mouse_mode")) { + convertTouchXYToGameXY(event->tfinger.x, event->tfinger.y, &x, &y); + } + + // make sure each finger is not reported down multiple times + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id == id) { + _finger[port][i].id = -1; + } + } + + // we need the timestamps to decide later if the user performed a short tap (click) + // or a long tap (drag) + // we also need the last coordinates for each finger to keep track of dragging + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id == -1) { + _finger[port][i].id = id; + _finger[port][i].timeLastDown = event->tfinger.timestamp; + _finger[port][i].lastDownX = event->tfinger.x; + _finger[port][i].lastDownY = event->tfinger.y; + _finger[port][i].lastX = x; + _finger[port][i].lastY = y; + break; + } + } +} + +void SwitchEventSource::preprocessFingerUp(SDL_Event *event) { + // front (0) or back (1) panel + SDL_TouchID port = event->tfinger.touchId; + // id (for multitouch) + SDL_FingerID id = event->tfinger.fingerId; + + // find out how many fingers were down before this event + int numFingersDown = 0; + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id >= 0) { + numFingersDown++; + } + } + + int x = _km.x / MULTIPLIER; + int y = _km.y / MULTIPLIER; + + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id == id) { + _finger[port][i].id = -1; + if (!_multiFingerDragging[port]) { + if ((event->tfinger.timestamp - _finger[port][i].timeLastDown) <= MAX_TAP_TIME) { + // short (tfinger.x * (float) TOUCHSCREEN_WIDTH) - (_finger[port][i].lastDownX * (float) TOUCHSCREEN_WIDTH)); + float yrel = ((event->tfinger.y * (float) TOUCHSCREEN_HEIGHT) - (_finger[port][i].lastDownY * (float) TOUCHSCREEN_HEIGHT)); + float maxRSquared = (float) (MAX_TAP_MOTION_DISTANCE * MAX_TAP_MOTION_DISTANCE); + if ((xrel * xrel + yrel * yrel) < maxRSquared) { + if (numFingersDown == 2 || numFingersDown == 1) { + uint8 simulatedButton = 0; + if (numFingersDown == 2) { + simulatedButton = SDL_BUTTON_RIGHT; + // need to raise the button later + _simulatedClickStartTime[port][1] = event->tfinger.timestamp; + } else if (numFingersDown == 1) { + simulatedButton = SDL_BUTTON_LEFT; + // need to raise the button later + _simulatedClickStartTime[port][0] = event->tfinger.timestamp; + if (port == 0 && !ConfMan.getBool("touchpad_mouse_mode")) { + convertTouchXYToGameXY(event->tfinger.x, event->tfinger.y, &x, &y); + } + } + + event->type = SDL_MOUSEBUTTONDOWN; + event->button.button = simulatedButton; + event->button.x = x; + event->button.y = y; + } + } + } + } else if (numFingersDown == 1) { + // when dragging, and the last finger is lifted, the drag is over + if (port == 0 && !ConfMan.getBool("touchpad_mouse_mode")) { + convertTouchXYToGameXY(event->tfinger.x, event->tfinger.y, &x, &y); + } + uint8 simulatedButton = 0; + if (_multiFingerDragging[port] == DRAG_THREE_FINGER) + simulatedButton = SDL_BUTTON_RIGHT; + else { + simulatedButton = SDL_BUTTON_LEFT; + } + event->type = SDL_MOUSEBUTTONUP; + event->button.button = simulatedButton; + event->button.x = x; + event->button.y = y; + _multiFingerDragging[port] = DRAG_NONE; + } + } + } +} + +void SwitchEventSource::preprocessFingerMotion(SDL_Event *event) { + // front (0) or back (1) panel + SDL_TouchID port = event->tfinger.touchId; + // id (for multitouch) + SDL_FingerID id = event->tfinger.fingerId; + + // find out how many fingers were down before this event + int numFingersDown = 0; + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id >= 0) { + numFingersDown++; + } + } + + if (numFingersDown >= 1) { + int x = _km.x / MULTIPLIER; + int y = _km.y / MULTIPLIER; + + if (port == 0 && !ConfMan.getBool("touchpad_mouse_mode")) { + convertTouchXYToGameXY(event->tfinger.x, event->tfinger.y, &x, &y); + } else { + // for relative mode, use the pointer speed setting + float speedFactor = 1.0; + + switch (ConfMan.getInt("kbdmouse_speed")) { + case 0: + speedFactor = 0.25; + break; + case 1: + speedFactor = 0.5; + break; + case 2: + speedFactor = 0.75; + break; + case 3: + speedFactor = 1.0; + break; + case 4: + speedFactor = 1.25; + break; + case 5: + speedFactor = 1.5; + break; + case 6: + speedFactor = 1.75; + break; + case 7: + speedFactor = 2.0; + break; + default: + speedFactor = 1.0; + } + + // convert touch events to relative mouse pointer events + // Whenever an SDL_event involving the mouse is processed, + // _km.x/y are truncated from subpixel precision to regular pixel precision. + // Therefore, there's no need here to deal with subpixel precision in _km.x/y. + x = (_km.x / MULTIPLIER + (event->tfinger.dx * 1.25 * speedFactor * _km.x_max)); + y = (_km.y / MULTIPLIER + (event->tfinger.dy * 1.25 * speedFactor * _km.y_max)); + } + + x = CLIP(x, 0, (int)_km.x_max); + y = CLIP(y, 0, (int)_km.y_max); + + // update the current finger's coordinates so we can track it later + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id == id) { + _finger[port][i].lastX = x; + _finger[port][i].lastY = y; + } + } + + // If we are starting a multi-finger drag, start holding down the mouse button + if (numFingersDown >= 2) { + if (!_multiFingerDragging[port]) { + // only start a multi-finger drag if at least two fingers have been down long enough + int numFingersDownLong = 0; + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id >= 0) { + if (event->tfinger.timestamp - _finger[port][i].timeLastDown > MAX_TAP_TIME) { + numFingersDownLong++; + } + } + } + if (numFingersDownLong >= 2) { + // starting drag, so push mouse down at current location (back) + // or location of "oldest" finger (front) + int mouseDownX = _km.x / MULTIPLIER; + int mouseDownY = _km.y / MULTIPLIER; + if (port == 0 && !ConfMan.getBool("touchpad_mouse_mode")) { + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id == id) { + uint32 earliestTime = _finger[port][i].timeLastDown; + for (int j = 0; j < MAX_NUM_FINGERS; j++) { + if (_finger[port][j].id >= 0 && (i != j) ) { + if (_finger[port][j].timeLastDown < earliestTime) { + mouseDownX = _finger[port][j].lastX; + mouseDownY = _finger[port][j].lastY; + earliestTime = _finger[port][j].timeLastDown; + } + } + } + break; + } + } + } + uint8 simulatedButton = 0; + if (numFingersDownLong == 2) { + simulatedButton = SDL_BUTTON_LEFT; + _multiFingerDragging[port] = DRAG_TWO_FINGER; + } else { + simulatedButton = SDL_BUTTON_RIGHT; + _multiFingerDragging[port] = DRAG_THREE_FINGER; + } + SDL_Event ev; + ev.type = SDL_MOUSEBUTTONDOWN; + ev.button.button = simulatedButton; + ev.button.x = mouseDownX; + ev.button.y = mouseDownY; + SDL_PushEvent(&ev); + } + } + } + + //check if this is the "oldest" finger down (or the only finger down), otherwise it will not affect mouse motion + bool updatePointer = true; + if (numFingersDown > 1) { + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id == id) { + for (int j = 0; j < MAX_NUM_FINGERS; j++) { + if (_finger[port][j].id >= 0 && (i != j) ) { + if (_finger[port][j].timeLastDown < _finger[port][i].timeLastDown) { + updatePointer = false; + } + } + } + } + } + } + if (updatePointer) { + event->type = SDL_MOUSEMOTION; + event->motion.x = x; + event->motion.y = y; + } + } +} + +void SwitchEventSource::convertTouchXYToGameXY(float touchX, float touchY, int *gameX, int *gameY) { + int screenH = _km.y_max; + int screenW = _km.x_max; + + int windowH = g_system->getHeight(); + //int windowW = g_system->getWidth(); + + bool fullscreen = ConfMan.getBool("fullscreen"); + bool aspectRatioCorrection = ConfMan.getBool("aspect_ratio"); + + const int dispW = TOUCHSCREEN_WIDTH; + const int dispH = TOUCHSCREEN_HEIGHT; + + int x, y, w, h; + float sx, sy; + float ratio = (float)screenW / (float)screenH; + + if (aspectRatioCorrection && (windowH == 200 || windowH == 400)) { + ratio = 4.0f / 3.0f; + } + + if (fullscreen || screenH >= dispH) { + h = dispH; + if (aspectRatioCorrection && (windowH == 200 || windowH == 400)) { + ratio = ratio * 1.1f; + } + w = h * ratio; + } else { + if (screenH <= dispH / 2 && screenW <= dispW / 2) { + h = screenH * 2; + w = screenW * 2; + } else { + h = screenH; + w = screenW; + } + if (aspectRatioCorrection && (windowH == 200 || windowH == 400)) { + // stretch the height only if it fits, otherwise make the width smaller + if (((float)w * (1.0f / ratio)) <= (float)dispH) { + h = w * (1.0f / ratio); + } else { + w = h * ratio; + } + } + } + + x = (dispW - w) / 2; + y = (dispH - h) / 2; + + sy = (float)h / (float)screenH; + sx = (float)w / (float)screenW; + + // Find touch coordinates in terms of screen pixels + float dispTouchX = (touchX * (float)dispW); + float dispTouchY = (touchY * (float)dispH); + + *gameX = CLIP((int)((dispTouchX - x) / sx), 0, (int)_km.x_max); + *gameY = CLIP((int)((dispTouchY - y) / sy), 0, (int)_km.y_max); +} + +void SwitchEventSource::finishSimulatedMouseClicks() { + for (int port = 0; port < SCE_TOUCH_PORT_MAX_NUM; port++) { + for (int i = 0; i < 2; i++) { + if (_simulatedClickStartTime[port][i] != 0) { + uint32 currentTime = SDL_GetTicks(); + if (currentTime - _simulatedClickStartTime[port][i] >= SIMULATED_CLICK_DURATION) { + int simulatedButton; + if (i == 0) { + simulatedButton = SDL_BUTTON_LEFT; + } else { + simulatedButton = SDL_BUTTON_RIGHT; + } + SDL_Event ev; + ev.type = SDL_MOUSEBUTTONUP; + ev.button.button = simulatedButton; + ev.button.x = _km.x / MULTIPLIER; + ev.button.y = _km.y / MULTIPLIER; + SDL_PushEvent(&ev); + + _simulatedClickStartTime[port][i] = 0; + } + } + } + } +} +#endif diff --git a/backends/events/switchsdl/switchsdl-events.h b/backends/events/switchsdl/switchsdl-events.h new file mode 100644 index 0000000000..6a5076bac3 --- /dev/null +++ b/backends/events/switchsdl/switchsdl-events.h @@ -0,0 +1,78 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#if !defined(DISABLE_DEFAULT_EVENTMANAGER) +#define BACKEND_EVENTS_SWITCH_H + +#include "backends/events/sdl/sdl-events.h" + +#define SCE_TOUCH_PORT_MAX_NUM 1 +#define TOUCHSCREEN_WIDTH 1280 +#define TOUCHSCREEN_HEIGHT 720 + +/** + * SDL Events manager for the SWITCH. + */ +class SwitchEventSource : public SdlEventSource { +public: + SwitchEventSource(); + bool pollEvent(Common::Event &event) override; +protected: + void preprocessEvents(SDL_Event *event) override; +private: + + enum { + MAX_NUM_FINGERS = 3, // number of fingers to track per panel + MAX_TAP_TIME = 250, // taps longer than this will not result in mouse click events + MAX_TAP_MOTION_DISTANCE = 10, // max distance finger motion in Vita screen pixels to be considered a tap + SIMULATED_CLICK_DURATION = 50, // time in ms how long simulated mouse clicks should be + }; // track three fingers per panel + + typedef struct { + int id; // -1: no touch + uint32 timeLastDown; + int lastX; // last known screen coordinates + int lastY; // last known screen coordinates + float lastDownX; // SDL touch coordinates when last pressed down + float lastDownY; // SDL touch coordinates when last pressed down + } Touch; + + Touch _finger[SCE_TOUCH_PORT_MAX_NUM][MAX_NUM_FINGERS]; // keep track of finger status + + typedef enum DraggingType { + DRAG_NONE = 0, + DRAG_TWO_FINGER, + DRAG_THREE_FINGER, + } DraggingType; + + DraggingType _multiFingerDragging[SCE_TOUCH_PORT_MAX_NUM]; // keep track whether we are currently drag-and-dropping + + unsigned int _simulatedClickStartTime[SCE_TOUCH_PORT_MAX_NUM][2]; // initiation time of last simulated left or right click (zero if no click) + + void preprocessFingerDown(SDL_Event *event); + void preprocessFingerUp(SDL_Event *event); + void preprocessFingerMotion(SDL_Event *event); + void convertTouchXYToGameXY(float touchX, float touchY, int *gameX, int *gameY); + void finishSimulatedMouseClicks(void); +}; + +#endif /* BACKEND_EVENTS_SWITCH_H */ diff --git a/backends/mixer/sdl/sdl-mixer.cpp b/backends/mixer/sdl/sdl-mixer.cpp index 11a45ebcb2..0af0748a2a 100644 --- a/backends/mixer/sdl/sdl-mixer.cpp +++ b/backends/mixer/sdl/sdl-mixer.cpp @@ -32,7 +32,7 @@ #if defined(GP2X) #define SAMPLES_PER_SEC 11025 -#elif defined(PLAYSTATION3) || defined(PSP2) +#elif defined(PLAYSTATION3) || defined(PSP2) || defined(NINTENDO_SWITCH) #define SAMPLES_PER_SEC 48000 #else #define SAMPLES_PER_SEC 44100 diff --git a/backends/module.mk b/backends/module.mk index f19b9ed6e7..e85e9d1901 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -341,6 +341,11 @@ MODULE_OBJS += \ plugins/wii/wii-provider.o endif +ifeq ($(BACKEND),switch) +MODULE_OBJS += \ + events/switchsdl/switchsdl-events.o +endif + ifdef ENABLE_EVENTRECORDER MODULE_OBJS += \ mixer/nullmixer/nullsdl-mixer.o \ diff --git a/backends/platform/sdl/module.mk b/backends/platform/sdl/module.mk index e9533ab711..62ef94f19a 100644 --- a/backends/platform/sdl/module.mk +++ b/backends/platform/sdl/module.mk @@ -52,6 +52,12 @@ MODULE_OBJS += \ psp2/psp2.o endif +ifdef SWITCH +MODULE_OBJS += \ + switch/switch-main.o \ + switch/switch.o +endif + # We don't use rules.mk but rather manually update OBJS and MODULE_DIRS. MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) OBJS := $(MODULE_OBJS) $(OBJS) diff --git a/backends/platform/sdl/posix/posix-main.cpp b/backends/platform/sdl/posix/posix-main.cpp index 7105ac69c3..72b1a66443 100644 --- a/backends/platform/sdl/posix/posix-main.cpp +++ b/backends/platform/sdl/posix/posix-main.cpp @@ -22,7 +22,7 @@ #include "common/scummsys.h" -#if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(MAEMO) && !defined(WEBOS) && !defined(LINUXMOTO) && !defined(GPH_DEVICE) && !defined(GP2X) && !defined(DINGUX) && !defined(OPENPANDORA) && !defined(PLAYSTATION3) && !defined(PSP2) && !defined(ANDROIDSDL) +#if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(MAEMO) && !defined(WEBOS) && !defined(LINUXMOTO) && !defined(GPH_DEVICE) && !defined(GP2X) && !defined(DINGUX) && !defined(OPENPANDORA) && !defined(PLAYSTATION3) && !defined(PSP2) && !defined(ANDROIDSDL) && !defined(NINTENDO_SWITCH) #include "backends/platform/sdl/posix/posix.h" #include "backends/plugins/sdl/sdl-provider.h" diff --git a/backends/platform/sdl/switch/switch-main.cpp b/backends/platform/sdl/switch/switch-main.cpp new file mode 100644 index 0000000000..411d5608be --- /dev/null +++ b/backends/platform/sdl/switch/switch-main.cpp @@ -0,0 +1,62 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include + +#define FORBIDDEN_SYMBOL_EXCEPTION_stdout +#define FORBIDDEN_SYMBOL_EXCEPTION_stderr + +#include "common/scummsys.h" +#include "backends/platform/sdl/switch/switch.h" +#include "backends/plugins/sdl/sdl-provider.h" +#include "base/main.h" + +int main(int argc, char *argv[]) { + +#ifdef __SWITCH_DEBUG__ + socketInitializeDefault(); + nxlinkStdio(); +#endif + + // Create our OSystem instance + g_system = new OSystem_Switch(); + assert(g_system); + + // Pre initialize the backend + ((OSystem_Switch *)g_system)->init(); + +#ifdef DYNAMIC_MODULES + PluginManager::instance().addPluginProvider(new SDLPluginProvider()); +#endif + + // Invoke the actual ScummVM main entry point: + int res = scummvm_main(argc, argv); + + // Free OSystem + delete (OSystem_Switch *)g_system; + +#ifdef __SWITCH_DEBUG__ + socketExit(); +#endif + + return res; +} diff --git a/backends/platform/sdl/switch/switch.cpp b/backends/platform/sdl/switch/switch.cpp new file mode 100644 index 0000000000..7ce3372d8d --- /dev/null +++ b/backends/platform/sdl/switch/switch.cpp @@ -0,0 +1,111 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#define FORBIDDEN_SYMBOL_EXCEPTION_printf +#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h + +#include +#include "common/scummsys.h" +#include "common/config-manager.h" +#include "backends/platform/sdl/switch/switch.h" +#include "backends/events/switchsdl/switchsdl-events.h" +#include "backends/saves/posix/posix-saves.h" +#include "backends/fs/posix/posix-fs-factory.h" +#include "backends/fs/posix/posix-fs.h" + +OSystem_Switch::OSystem_Switch(Common::String baseConfigName) + : _baseConfigName(baseConfigName) { +} + +void OSystem_Switch::init() { + + // Initialze File System Factory + _fsFactory = new POSIXFilesystemFactory(); + + // Invoke parent implementation of this method + OSystem_SDL::init(); +} + +void OSystem_Switch::initBackend() { + + ConfMan.registerDefault("joystick_num", 0); + ConfMan.registerDefault("fullscreen", true); + ConfMan.registerDefault("aspect_ratio", false); + ConfMan.registerDefault("gfx_mode", "2x"); + ConfMan.registerDefault("output_rate", 48000); + ConfMan.registerDefault("touchpad_mouse_mode", true); + + if (!ConfMan.hasKey("joystick_num")) { + ConfMan.setInt("joystick_num", 0); + } + if (!ConfMan.hasKey("fullscreen")) { + ConfMan.setBool("fullscreen", true); + } + if (!ConfMan.hasKey("aspect_ratio")) { + ConfMan.setBool("aspect_ratio", false); + } + if (!ConfMan.hasKey("gfx_mode")) { + ConfMan.set("gfx_mode", "2x"); + } + if (!ConfMan.hasKey("output_rate")) { + ConfMan.setInt("output_rate", 48000); + } + if (!ConfMan.hasKey("touchpad_mouse_mode")) { + ConfMan.setBool("touchpad_mouse_mode", true); + } + + // Create the savefile manager + if (_savefileManager == 0) { + _savefileManager = new POSIXSaveFileManager(); + } + + // Event source + if (_eventSource == 0) { + _eventSource = new SwitchEventSource(); + } + + // Invoke parent implementation of this method + OSystem_SDL::initBackend(); +} + +bool OSystem_Switch::hasFeature(Feature f) { + + if (f == kFeatureDisplayLogFile) + return false; + if (f == kFeatureOpenUrl) + return false; + + return OSystem_SDL::hasFeature(f); +} + +void OSystem_Switch::logMessage(LogMessageType::Type type, const char *message) { + printf("%s\n", message); +} + +Common::String OSystem_Switch::getDefaultConfigFileName() { + return _baseConfigName; +} + +Common::WriteStream *OSystem_Switch::createLogFile() { + Common::FSNode file("scummvm.log"); + return file.createWriteStream(); +} diff --git a/backends/platform/sdl/switch/switch.h b/backends/platform/sdl/switch/switch.h new file mode 100644 index 0000000000..6578463897 --- /dev/null +++ b/backends/platform/sdl/switch/switch.h @@ -0,0 +1,50 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef PLATFORM_SDL_SWITCH_H +#define PLATFORM_SDL_SWITCH_H + +#include "backends/platform/sdl/sdl.h" + +class OSystem_Switch : public OSystem_SDL { +public: + // Let the subclasses be able to change _baseConfigName in the constructor + OSystem_Switch(Common::String baseConfigName = "scummvm.ini"); + virtual ~OSystem_Switch() {} + + virtual void init() override; + virtual void initBackend() override; + virtual bool hasFeature(Feature f) override; + virtual void logMessage(LogMessageType::Type type, const char *message) override; + +protected: + // Base string for creating the default path and filename + // for the configuration file + Common::String _baseConfigName; + + virtual Common::String getDefaultConfigFileName() override; + + virtual Common::WriteStream *createLogFile() override; +}; + +#endif + diff --git a/backends/platform/sdl/switch/switch.mk b/backends/platform/sdl/switch/switch.mk new file mode 100644 index 0000000000..9c978a7917 --- /dev/null +++ b/backends/platform/sdl/switch/switch.mk @@ -0,0 +1,19 @@ +scummvm.nro: $(EXECUTABLE) + mkdir -p $(srcdir)/switch_release/scummvm/data + mkdir -p $(srcdir)/switch_release/scummvm/doc + nacptool --create "ScummVM" "Cpasjuste" "2.12" $(srcdir)/switch_release/scummvm.nacp + elf2nro $(EXECUTABLE) $(srcdir)/switch_release/scummvm/scummvm.nro --icon=$(srcdir)/dists/switch/icon.jpg --nacp=$(srcdir)/switch_release/scummvm.nacp + +scummvm_switch.zip: scummvm.nro + rm -f $(srcdir)/switch_release/scummvm.nacp + cp $(srcdir)/backends/vkeybd/packs/vkeybd_default.zip $(srcdir)/switch_release/scummvm/data + cp $(srcdir)/backends/vkeybd/packs/vkeybd_small.zip $(srcdir)/switch_release/scummvm/data + cp $(DIST_FILES_THEMES) $(srcdir)/switch_release/scummvm/data +ifdef DIST_FILES_ENGINEDATA + cp $(DIST_FILES_ENGINEDATA) $(srcdir)/switch_release/scummvm/data +endif + cp $(DIST_FILES_DOCS) $(srcdir)/switch_release/scummvm/doc/ + cd $(srcdir)/switch_release && zip -r ../scummvm_switch.zip . && cd .. + +.PHONY: scummvm.nro scummvm_switch.zip + diff --git a/backends/saves/posix/posix-saves.cpp b/backends/saves/posix/posix-saves.cpp index 444aa63f15..35f9fa2050 100644 --- a/backends/saves/posix/posix-saves.cpp +++ b/backends/saves/posix/posix-saves.cpp @@ -47,6 +47,9 @@ POSIXSaveFileManager::POSIXSaveFileManager() { // Register default savepath. #if defined(SAMSUNGTV) ConfMan.registerDefault("savepath", "/mtd_wiselink/scummvm savegames"); +#elif defined(NINTENDO_SWITCH) + Posix::assureDirectoryExists("./saves", nullptr); + ConfMan.registerDefault("savepath", "./saves"); #else Common::String savePath; diff --git a/configure b/configure index b4e8224fc5..d5883e9695 100755 --- a/configure +++ b/configure @@ -526,7 +526,7 @@ get_system_exe_extension() { riscos) _exeext=",e1f" ;; - 3ds | dreamcast | ds | gamecube | n64 | ps2 | psp | wii) + 3ds | dreamcast | ds | gamecube | n64 | ps2 | psp | switch | wii) _exeext=".elf" ;; gph-linux) @@ -919,7 +919,7 @@ Configuration: -h, --help display this help and exit --backend=BACKEND backend to build (3ds, android, dc, dingux, ds, gcw0, gph, iphone, ios7, linuxmoto, maemo, n64, null, openpandora, - ps2, psp, psp2, samsungtv, sdl, tizen, webos, wii, wince) [sdl] + ps2, psp, psp2, samsungtv, sdl, switch, tizen, webos, wii, wince) [sdl] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX @@ -972,6 +972,7 @@ Special configuration feature: psp2 for PlayStation Vita psp for PlayStation Portable samsungtv for Samsung TV + switch for Nintendo Switch tizen for Samsung Tizen webos for HP Palm WebOS wii for Nintendo Wii @@ -1685,6 +1686,16 @@ samsungtv) _host_cpu=arm _host_alias=arm-linux-gnueabi ;; +switch) + _host_os=switch + _host_cpu=arm + _host_alias=aarch64-none-elf + test "x$prefix" = xNONE && prefix=. + datarootdir='${prefix}/data' + datadir='${datarootdir}' + docdir='${prefix}/doc' + PKG_CONFIG_LIBDIR=$DEVKITPRO/portlibs/switch/lib/pkgconfig + ;; tizen) _host_os=tizen _host_cpu=arm @@ -1784,7 +1795,7 @@ android) exit 1 fi ;; -3ds | ds | gamecube | wii) +3ds | ds | gamecube | switch | wii) if test -z "$DEVKITPRO"; then echo "Please set DEVKITPRO in your environment. export DEVKITPRO=" exit 1 @@ -2101,7 +2112,7 @@ if test "$have_gcc" = yes ; then case $_host_os in # newlib-based system include files suppress non-C89 function # declarations under __STRICT_ANSI__ - 3ds | amigaos* | android | androidsdl | dreamcast | ds | gamecube | mingw* | mint* | n64 | psp | ps2 | ps3 | psp2 | tizen | wii | wince ) + 3ds | amigaos* | android | androidsdl | dreamcast | ds | gamecube | mingw* | mint* | n64 | psp | ps2 | ps3 | psp2 | switch | tizen | wii | wince ) ;; *) append_var CXXFLAGS "-ansi" @@ -2175,7 +2186,7 @@ fi # However, some platforms use GNU extensions in system header files, so # for these we must not use -pedantic. case $_host_os in -3ds | android | androidsdl | gamecube | ps2 | psp | tizen | wii | webos) +3ds | android | androidsdl | gamecube | ps2 | psp | switch | tizen | wii | webos) ;; *) # ICC does not support pedantic, while GCC and clang do. @@ -2883,6 +2894,22 @@ case $_host_os in # Needs -lbind -lsocket for the timidity MIDI driver append_var LIBS "-lnsl -lsocket" ;; + switch) + _pkgconfig="$DEVKITPRO/portlibs/switch/bin/aarch64-none-elf-pkg-config" + _sdlpath="$DEVKITPRO/portlibs/switch/bin" + append_var DEFINES "-DSWITCH -D__SWITCH__ -DNINTENDO_SWITCH" + append_var CXXFLAGS "-march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -ftls-model=local-exec" + append_var CXXFLAGS "-ffunction-sections -fdata-sections" + append_var CXXFLAGS "-I$DEVKITPRO/libnx/include -I$DEVKITPRO/portlibs/switch/include" + append_var LDFLAGS "-L$DEVKITPRO/libnx/lib -L$DEVKITPRO/portlibs/switch/lib" + append_var LDFLAGS "-specs=$DEVKITPRO/libnx/switch.specs" + add_line_to_config_mk 'SWITCH = 1' + if test "$_debug_build" = yes; then + append_var DEFINES "-D__SWITCH_DEBUG__" + else + _optimization_level=-O3 + fi + ;; tizen) add_line_to_config_mk "TIZEN_ROOTSTRAP = $TIZEN_ROOTSTRAP" append_var LDFLAGS "--sysroot=${TIZEN_ROOTSTRAP}" @@ -3374,6 +3401,19 @@ if test -n "$_host"; then _mt32emu=no _vkeybd=yes ;; + switch) + _backend="switch" + _opengl_mode=gles2 + _build_scalers=yes + _build_hq_scalers=yes + _dynamic_modules=no + _vkeybd=yes + _mt32emu=yes + _vorbis=yes + _tremor=no + _eventrec=no + _port_mk="backends/platform/sdl/switch/switch.mk" + ;; tizen) _unix=yes _backend="tizen" @@ -3566,6 +3606,10 @@ case $_backend in sdl) _sdl=auto ;; + switch) + _sdl=auto + append_var MODULES "backends/platform/sdl" + ;; tizen) # dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included append_var DEFINES "-DTIZEN -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT" @@ -3686,7 +3730,7 @@ fi # Enable 16bit support only for backends which support it # case $_backend in - 3ds | android | androidsdl | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | psp2 | samsungtv | sdl | tizen | webos | wii) + 3ds | android | androidsdl | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | psp2 | samsungtv | sdl | switch | tizen | webos | wii) if test "$_16bit" = auto ; then _16bit=yes else @@ -3765,7 +3809,7 @@ case $_host_os in amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp2 | psp | riscos | wii | wince) _posix=no ;; - 3ds | android | androidsdl | beos* | bsd* | darwin* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | ios7 | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos) + 3ds | android | androidsdl | beos* | bsd* | darwin* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | ios7 | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | solaris* | sunos* | switch | uclinux* | webos) _posix=yes ;; os2-emx*) diff --git a/dists/switch/icon.jpg b/dists/switch/icon.jpg new file mode 100644 index 0000000000..a4df2811ef Binary files /dev/null and b/dists/switch/icon.jpg differ -- cgit v1.2.3