diff options
author | cpasjuste | 2017-03-01 14:00:17 -0600 |
---|---|---|
committer | rsn8887 | 2017-03-04 15:42:19 -0600 |
commit | 70988527c64947fd7fe3c361907e9f0806b0cb5c (patch) | |
tree | 9472f2a894e65f98dcbdda60e7c46c32d28defd6 | |
parent | 3a7c0911224adc0d0d467dc530f62f97a8868bee (diff) | |
download | scummvm-rg350-70988527c64947fd7fe3c361907e9f0806b0cb5c.tar.gz scummvm-rg350-70988527c64947fd7fe3c361907e9f0806b0cb5c.tar.bz2 scummvm-rg350-70988527c64947fd7fe3c361907e9f0806b0cb5c.zip |
PSP2: Add Playstation Vita (PSP2) support
39 files changed, 2049 insertions, 15 deletions
diff --git a/.gitignore b/.gitignore index dff59d2045..53dc2b90e7 100644 --- a/.gitignore +++ b/.gitignore @@ -208,5 +208,10 @@ dists/msvc*/** out/ scummvm.xcodeproj +#Ignore PSP2 files +psp2pkg/ +*.velf +*.vpk + #Ignore gmon.out created by gprof gmon.out diff --git a/backends/events/psp2sdl/psp2sdl-events.cpp b/backends/events/psp2sdl/psp2sdl-events.cpp new file mode 100644 index 0000000000..e58e49d9a8 --- /dev/null +++ b/backends/events/psp2sdl/psp2sdl-events.cpp @@ -0,0 +1,323 @@ +/* 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(PSP2) + +#include <psp2/kernel/processmgr.h> +#include "backends/platform/sdl/psp2/psp2.h" +#include "backends/events/psp2sdl/psp2sdl-events.h" +#include "backends/platform/sdl/sdl.h" +#include "engines/engine.h" + +#include "common/util.h" +#include "common/events.h" +#include "common/config-manager.h" + +#include "math.h" + +#define JOY_DEADZONE 2000 +#define JOY_ANALOG +#define JOY_XAXIS 0 +#define JOY_YAXIS 1 +#define JOY_XAXISR 2 +#define JOY_YAXISR 3 + +enum { + BTN_LEFT = 7, + BTN_DOWN = 6, + BTN_RIGHT = 9, + BTN_UP = 8, + + BTN_START = 11, + BTN_SELECT = 10, + + BTN_SQUARE = 3, + BTN_CROSS = 2, + BTN_CIRCLE = 1, + BTN_TRIANGLE = 0, + + BTN_R1 = 5, + BTN_L1 = 4 +}; + +bool PSP2EventSource::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) { + + event.kbd.flags = 0; + + switch (ev.jbutton.button) { +// Dpad + case BTN_LEFT: // Left (+R_trigger: Up+Left) + if (!_km.modifier) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_KP4; + event.kbd.ascii = mapKey(SDLK_KP4, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_KP7; + event.kbd.ascii = mapKey(SDLK_KP7, (SDLMod) ev.key.keysym.mod, 0); + } + break; + case BTN_RIGHT: // Right (+R_trigger: Down+Right) + if (!_km.modifier) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_KP6; + event.kbd.ascii = mapKey(SDLK_KP6, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_KP3; + event.kbd.ascii = mapKey(SDLK_KP3, (SDLMod) ev.key.keysym.mod, 0); + } + break; + case BTN_UP: // Up (+R_trigger: Up+Right) + if (!_km.modifier) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_KP8; + event.kbd.ascii = mapKey(SDLK_KP8, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_KP9; + event.kbd.ascii = mapKey(SDLK_KP9, (SDLMod) ev.key.keysym.mod, 0); + } + break; + case BTN_DOWN: // Down (+R_trigger: Down+Left) + if (!_km.modifier) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_KP2; + event.kbd.ascii = mapKey(SDLK_KP2, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_KP1; + event.kbd.ascii = mapKey(SDLK_KP1, (SDLMod) ev.key.keysym.mod, 0); + } + break; +// Buttons + case BTN_CROSS: // Left mouse button + event.type = Common::EVENT_LBUTTONDOWN; + processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER); + break; + case BTN_CIRCLE: // Right mouse button + event.type = Common::EVENT_RBUTTONDOWN; + processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER); + break; + case BTN_TRIANGLE: // Escape (+R_trigger: Return) + if (!_km.modifier) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = mapKey(SDLK_ESCAPE, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_RETURN; + event.kbd.ascii = mapKey(SDLK_RETURN, (SDLMod) ev.key.keysym.mod, 0); + } + break; + case BTN_SQUARE: // Period (+R_trigger: Space) + if (!_km.modifier) { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_PERIOD; + event.kbd.ascii = mapKey(SDLK_PERIOD, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_SPACE; + event.kbd.ascii = mapKey(SDLK_SPACE, (SDLMod) ev.key.keysym.mod, 0); + } + break; + case BTN_L1: // Game menu + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = mapKey(SDLK_F5, (SDLMod) ev.key.keysym.mod, 0); + break; + case BTN_R1: // Modifier + Shift + _km.modifier=true; // slow mouse + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_INVALID; + event.kbd.ascii = 0; + event.kbd.flags = Common::KBD_SHIFT; + break; + case BTN_START: // ScummVM in game menu + event.type = Common::EVENT_MAINMENU; + break; + case BTN_SELECT: // Virtual keyboard (+R_trigger: Predictive Input Dialog) + if (!_km.modifier) { +#ifdef ENABLE_VKEYBD + event.type = Common::EVENT_VIRTUAL_KEYBOARD; +#endif + } else { + event.type = Common::EVENT_PREDICTIVE_DIALOG; + } + break; + } + return true; +} + +bool PSP2EventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) { + + event.kbd.flags = 0; + + switch (ev.jbutton.button) { +// Dpad + case BTN_LEFT: // Left (+R_trigger: Up+Left) + if (!_km.modifier) { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_KP4; + event.kbd.ascii = mapKey(SDLK_KP4, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_KP7; + event.kbd.ascii = mapKey(SDLK_KP7, (SDLMod) ev.key.keysym.mod, 0); + } + break; + case BTN_RIGHT: // Right (+R_trigger: Down+Right) + if (!_km.modifier) { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_KP6; + event.kbd.ascii = mapKey(SDLK_KP6, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_KP3; + event.kbd.ascii = mapKey(SDLK_KP3, (SDLMod) ev.key.keysym.mod, 0); + } + break; + case BTN_UP: // Up (+R_trigger: Up+Right) + if (!_km.modifier) { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_KP8; + event.kbd.ascii = mapKey(SDLK_KP8, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_KP9; + event.kbd.ascii = mapKey(SDLK_KP9, (SDLMod) ev.key.keysym.mod, 0); + } + break; + case BTN_DOWN: // Down (+R_trigger: Down+Left) + if (!_km.modifier) { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_KP2; + event.kbd.ascii = mapKey(SDLK_KP2, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_KP1; + event.kbd.ascii = mapKey(SDLK_KP1, (SDLMod) ev.key.keysym.mod, 0); + } + break; +// Buttons + case BTN_CROSS: // Left mouse button + event.type = Common::EVENT_LBUTTONUP; + processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER); + break; + case BTN_CIRCLE: // Right mouse button + event.type = Common::EVENT_RBUTTONUP; + processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER); + break; + case BTN_TRIANGLE: // Escape (+R_trigger: Return) + if (!_km.modifier) { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = mapKey(SDLK_ESCAPE, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_RETURN; + event.kbd.ascii = mapKey(SDLK_RETURN, (SDLMod) ev.key.keysym.mod, 0); + } + break; + case BTN_SQUARE: // Period (+R_trigger: Space) + if (!_km.modifier) { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_PERIOD; + event.kbd.ascii = mapKey(SDLK_PERIOD, (SDLMod) ev.key.keysym.mod, 0); + } else { + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_SPACE; + event.kbd.ascii = mapKey(SDLK_SPACE, (SDLMod) ev.key.keysym.mod, 0); + } + break; + case BTN_L1: // Game menu + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_F5; + event.kbd.ascii = mapKey(SDLK_F5, (SDLMod) ev.key.keysym.mod, 0); + break; + case BTN_R1: // Modifier + SHIFT Key + _km.modifier = false; // slow mouse + event.type = Common::EVENT_KEYUP; + event.kbd.keycode = Common::KEYCODE_INVALID; + event.kbd.ascii = 0; + event.kbd.flags = 0; + break; + case BTN_START: // ScummVM in game menu + // Handled in key down + break; + case BTN_SELECT: // Virtual keyboard (+R_trigger: Predictive Input Dialog) + // Handled in key down + break; + } + return true; +} + +bool PSP2EventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) { + + int axis = ev.jaxis.value; + + // conversion factor between keyboard mouse and joy axis value + int vel_to_axis = (1500 / MULTIPLIER); + + if (ev.jaxis.axis == JOY_XAXIS) { + _km.joy_x = axis; + } else if (ev.jaxis.axis == JOY_YAXIS) { + axis = -axis; + _km.joy_y = -axis; + } + + // radial and scaled deadzone + + float analogX = (float)_km.joy_x; + float analogY = (float)_km.joy_y; + float deadZone = (float)JOY_DEADZONE; + if (g_system->hasFeature(OSystem::kFeatureJoystickDeadzone)) + deadZone = (float)ConfMan.getInt("joystick_deadzone") * 1000.0f; + float scalingFactor = 1.0f; + float magnitude = 0.0f; + + magnitude = sqrt(analogX * analogX + analogY * analogY); + + if (magnitude >= deadZone) { + _km.x_down_count = 0; + _km.y_down_count = 0; + scalingFactor = 1.0f / magnitude * (magnitude - deadZone) / (32769.0f - deadZone); + _km.x_vel = (int16)(analogX * scalingFactor * 32768.0f / (float) vel_to_axis); + _km.y_vel = (int16)(analogY * scalingFactor * 32768.0f / (float) vel_to_axis); + } else { + _km.x_vel = 0; + _km.y_vel = 0; + } + + return false; +} + +void PSP2EventSource::preprocessEvents(SDL_Event *event) { + + // prevent suspend (scummvm games contains a lot of cutscenes..) + sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DISABLE_AUTO_SUSPEND); + sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DISABLE_OLED_OFF); +} + +#endif diff --git a/backends/events/psp2sdl/psp2sdl-events.h b/backends/events/psp2sdl/psp2sdl-events.h new file mode 100644 index 0000000000..001312e1d5 --- /dev/null +++ b/backends/events/psp2sdl/psp2sdl-events.h @@ -0,0 +1,39 @@ +/* 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_PSP2_H + +#include "backends/events/sdl/sdl-events.h" + +/** + * SDL Events manager for the PSP2. + */ +class PSP2EventSource : public SdlEventSource { +protected: + bool handleJoyButtonDown(SDL_Event &ev, Common::Event &event); + bool handleJoyButtonUp(SDL_Event &ev, Common::Event &event); + bool handleJoyAxisMotion(SDL_Event &ev, Common::Event &event); + void preprocessEvents(SDL_Event *event); +}; + +#endif /* BACKEND_EVENTS_PSP2_H */ diff --git a/backends/fs/posix/posix-fs.cpp b/backends/fs/posix/posix-fs.cpp index 4434bcba97..3f90fc1a19 100644 --- a/backends/fs/posix/posix-fs.cpp +++ b/backends/fs/posix/posix-fs.cpp @@ -20,7 +20,7 @@ * */ -#if defined(POSIX) || defined(PLAYSTATION3) +#if defined(POSIX) || defined(PLAYSTATION3) || defined(PSP2) // Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h. // Also with clock() in sys/time.h in some Mac OS X SDKs. @@ -36,7 +36,12 @@ #include <sys/param.h> #include <sys/stat.h> +#ifdef PSP2 +#include "backends/fs/psp2/psp2-dirent.h" +#define mkdir sceIoMkdir +#else #include <dirent.h> +#endif #include <stdio.h> #include <errno.h> #include <fcntl.h> diff --git a/backends/fs/psp2/psp2-dirent.cpp b/backends/fs/psp2/psp2-dirent.cpp new file mode 100644 index 0000000000..aefd1a067d --- /dev/null +++ b/backends/fs/psp2/psp2-dirent.cpp @@ -0,0 +1,241 @@ +/* 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. + * + */ + +/* + +Copyright (C) 2016, David "Davee" Morgan + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*/ + +#include "psp2-dirent.h" +#include <errno.h> +#include <malloc.h> +#include <string.h> + +#include <psp2/types.h> +#include <psp2/io/dirent.h> +#include <psp2/kernel/threadmgr.h> + +#define SCE_ERRNO_MASK 0xFF + + +struct DIR_ { + SceUID uid; + struct dirent dir; + int refcount; + char *dirname; + int index; +}; + +static inline void grab_dir(DIR *dirp) { + __sync_add_and_fetch(&dirp->refcount, 1); +} + +static inline void drop_dir(DIR *dirp) { + if (__sync_add_and_fetch(&dirp->refcount, 1) == 0) { + free(dirp->dirname); + free(dirp); + } +} + +static inline void release_drop_dir(DIR *dirp) { + if (__sync_add_and_fetch(&dirp->refcount, 2) == 0) { + free(dirp->dirname); + free(dirp); + } +} + +static inline void atomic_exchange(int *obj, int desired) { + __sync_synchronize(); + __sync_lock_test_and_set(obj, desired); +} + +#ifdef F_closedir +int closedir(DIR *dirp) { + if (!dirp) { + errno = EBADF; + return -1; + } + + grab_dir(dirp); + + int res = sceIoDclose(dirp->uid); + + if (res < 0) { + errno = res & SCE_ERRNO_MASK; + drop_dir(dirp); + return -1; + } + + release_drop_dir(dirp); + + errno = 0; + return 0; +} +#endif + +#if F_opendir +DIR *opendir(const char *dirname) { + SceUID uid = sceIoDopen(dirname); + + if (uid < 0) { + errno = uid & SCE_ERRNO_MASK; + return NULL; + } + + DIR *dirp = (DIR *)calloc(1, sizeof(DIR)); + + if (!dirp) { + sceIoDclose(uid); + errno = ENOMEM; + return NULL; + } + + dirp->refcount = 1; + dirp->uid = uid; + dirp->dirname = strdup(dirname); + dirp->index = 0; + + errno = 0; + return dirp; +} +#endif + +#ifdef F_readdir +struct dirent *readdir(DIR *dirp) { + if (!dirp) { + errno = EBADF; + return NULL; + } + + grab_dir(dirp); + + int res = sceIoDread(dirp->uid, (SceIoDirent *)&dirp->dir); + + if (res < 0) { + errno = res & SCE_ERRNO_MASK; + drop_dir(dirp); + return NULL; + } + + if (res == 0) { + errno = 0; + drop_dir(dirp); + return NULL; + } + + __sync_add_and_fetch(&dirp->index, 1); + + struct dirent *dir = &dirp->dir; + drop_dir(dirp); + return dir; +} +#endif +#ifdef F_readdir_r +int readdir_r(DIR *dirp, struct dirent *x, struct dirent **y) { + errno = ENOSYS; + return -1; +} +#endif + +#ifdef F_rewinddir +void rewinddir(DIR *dirp) { + if (!dirp) { + errno = EBADF; + return; + } + + grab_dir(dirp); + + SceUID dirfd = sceIoDopen(dirp->dirname); + + if (dirfd < 0) { + errno = dirfd & SCE_ERRNO_MASK; + drop_dir(dirp); + return; + } + + sceIoDclose(dirp->uid); + atomic_exchange(&dirp->uid, dirfd); + atomic_exchange(&dirp->index, 0); + + drop_dir(dirp); +} +#endif + +#ifdef F_seekdir +void seekdir(DIR *dirp, long int index) { + if (!dirp) { + errno = EBADF; + return; + } + + grab_dir(dirp); + + if (index < dirp->index) + rewinddir(dirp); + + if (index < dirp->index) { + drop_dir(dirp); + return; + } + + while (index != dirp->index) { + if (!readdir(dirp)) { + errno = ENOENT; + drop_dir(dirp); + return; + } + } + + drop_dir(dirp); +} +#endif + +#ifdef F_telldir +long int telldir(DIR *dirp) { + if (!dirp) { + errno = EBADF; + return -1; + } + + return dirp->index; +} +#endif diff --git a/backends/fs/psp2/psp2-dirent.h b/backends/fs/psp2/psp2-dirent.h new file mode 100644 index 0000000000..0e56976404 --- /dev/null +++ b/backends/fs/psp2/psp2-dirent.h @@ -0,0 +1,59 @@ +/* + +Copyright (C) 2016, David "Davee" Morgan + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*/ + +#ifndef _PSP2_DIRENT_H_ +#define _PSP2_DIRENT_H_ + +#include <sys/types.h> +#include <sys/time.h> + +#include <psp2/io/dirent.h> + +#define F_opendir 1 +#define F_readdir 1 +#define F_closedir 1 + +struct dirent +{ + /** File status. */ + SceIoStat d_stat; + /** File name. */ + char d_name[256]; + /** Device-specific data. */ + void *d_private; + int dummy; +}; + +struct DIR_; +typedef struct DIR_ DIR; + +int closedir(DIR *); +DIR *opendir(const char *); +struct dirent *readdir(DIR *); +int readdir_r(DIR *, struct dirent *, struct dirent **); +void rewinddir(DIR *); +void seekdir(DIR *, long int); +long int telldir(DIR *); + +#endif /* _PSP2_DIRENT_H_ */ diff --git a/backends/fs/psp2/psp2-fs-factory.cpp b/backends/fs/psp2/psp2-fs-factory.cpp new file mode 100644 index 0000000000..68d91122b8 --- /dev/null +++ b/backends/fs/psp2/psp2-fs-factory.cpp @@ -0,0 +1,45 @@ +/* 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. + * + */ + +// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h. +// Also with clock() in sys/time.h in some Mac OS X SDKs. +#define FORBIDDEN_SYMBOL_EXCEPTION_time_h +#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h +#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir +#define FORBIDDEN_SYMBOL_EXCEPTION_exit //Needed for IRIX's unistd.h + +#include "backends/fs/posix/posix-fs-factory.h" +#include "backends/fs/posix/posix-fs.h" +#include "backends/fs/psp2/psp2-fs-factory.h" + +AbstractFSNode *PSP2FilesystemFactory::makeRootFileNode() const { + return new POSIXFilesystemNode("ux0:"); +} + +AbstractFSNode *PSP2FilesystemFactory::makeCurrentDirectoryFileNode() const { + return makeRootFileNode(); +} + +AbstractFSNode *PSP2FilesystemFactory::makeFileNodePath(const Common::String &path) const { + assert(!path.empty()); + return new POSIXFilesystemNode(path); +} diff --git a/backends/fs/psp2/psp2-fs-factory.h b/backends/fs/psp2/psp2-fs-factory.h new file mode 100644 index 0000000000..3429b815ae --- /dev/null +++ b/backends/fs/psp2/psp2-fs-factory.h @@ -0,0 +1,41 @@ +/* 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 PSP2_FILESYSTEM_FACTORY_H +#define PSP2_FILESYSTEM_FACTORY_H + +#include "backends/fs/posix/posix-fs-factory.h" + +/** + * Creates PSP2FilesystemFactory objects. + * + * Parts of this class are documented in the base interface class, FilesystemFactory. + */ + +class PSP2FilesystemFactory : public FilesystemFactory { +protected: + virtual AbstractFSNode *makeRootFileNode() const; + virtual AbstractFSNode *makeCurrentDirectoryFileNode() const; + virtual AbstractFSNode *makeFileNodePath(const Common::String &path) const; +}; + +#endif /*PSP2_FILESYSTEM_FACTORY_H*/ diff --git a/backends/graphics/graphics.h b/backends/graphics/graphics.h index db8b6a920b..f6b0058fac 100644 --- a/backends/graphics/graphics.h +++ b/backends/graphics/graphics.h @@ -46,6 +46,13 @@ public: virtual bool setGraphicsMode(int mode) = 0; virtual void resetGraphicsScale() = 0; virtual int getGraphicsMode() const = 0; + virtual const OSystem::GraphicsMode *getSupportedShaders() const { + static const OSystem::GraphicsMode no_shader[2] = {{"NONE", "Normal (no shader)", 0}, {0, 0, 0}}; + return no_shader; + }; + virtual bool setShader(int id) { return false; } + virtual int getShader() { return 0; } + #ifdef USE_RGB_COLOR virtual Graphics::PixelFormat getScreenFormat() const = 0; virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const = 0; diff --git a/backends/graphics/psp2sdl/psp2sdl-graphics.cpp b/backends/graphics/psp2sdl/psp2sdl-graphics.cpp new file mode 100644 index 0000000000..fa2adc85e4 --- /dev/null +++ b/backends/graphics/psp2sdl/psp2sdl-graphics.cpp @@ -0,0 +1,522 @@ +/* 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(SDL_BACKEND) + +#include "backends/graphics/psp2sdl/psp2sdl-graphics.h" +#include "backends/events/sdl/sdl-events.h" +#include "backends/platform/sdl/sdl.h" +#include "common/config-manager.h" +#include "common/mutex.h" +#include "common/textconsole.h" +#include "common/translation.h" +#include "common/util.h" +#include "common/frac.h" +#ifdef USE_RGB_COLOR +#include "common/list.h" +#endif +#include "graphics/font.h" +#include "graphics/fontman.h" +#include "graphics/scaler.h" +#include "graphics/scaler/aspect.h" +#include "graphics/surface.h" +#include "gui/EventRecorder.h" + +#include <vita2d_fbo.h> +#include <lcd3x_v.h> +#include <lcd3x_f.h> +#include <texture_v.h> +#include <texture_f.h> +#include <advanced_aa_v.h> +#include <advanced_aa_f.h> +#include <scale2x_f.h> +#include <scale2x_v.h> +#include <sharp_bilinear_f.h> +#include <sharp_bilinear_v.h> +#include <sharp_bilinear_simple_f.h> +#include <sharp_bilinear_simple_v.h> + +#define GFX_SHADER_NONE 0 +#define GFX_SHADER_LCD3X 1 +#define GFX_SHADER_SHARP 2 +#define GFX_SHADER_SHARP_SCAN 3 +#define GFX_SHADER_AAA 4 +#define GFX_SHADER_SCALE2X 5 + +static const OSystem::GraphicsMode s_supportedShadersPSP2[] = { + {"NONE", "Normal (no shader)", GFX_SHADER_NONE}, + {"LCD", "LCD", GFX_SHADER_LCD3X}, + {"Sharp", "Sharp", GFX_SHADER_SHARP}, + {"Scan", "Scan", GFX_SHADER_SHARP_SCAN}, + {"AAA", "Super2xSAI", GFX_SHADER_AAA}, + {"Scale", "Scale", GFX_SHADER_SCALE2X}, + {0, 0, 0} +}; + +PSP2SdlGraphicsManager::PSP2SdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window) + : + SurfaceSdlGraphicsManager(sdlEventSource, window), + _vitatex_hwscreen(nullptr), + _sdlpixels_hwscreen(nullptr) { + + // do aspect ratio correction in hardware on the Vita + if (_videoMode.aspectRatioCorrection == true) { + _hardwareAspectRatioCorrection = true; + } else { + _hardwareAspectRatioCorrection = false; + } + _videoMode.aspectRatioCorrection = false; + + if (g_system->hasFeature(OSystem::kFeatureShader)) { + // shader number 0 is the entry NONE (no shader) + const OSystem::GraphicsMode *p = s_supportedShadersPSP2; + _numShaders = 0; + while (p->name) { + _numShaders++; + p++; + } + _currentShader = ConfMan.getInt("shader"); + if (_currentShader < 0 || _currentShader >= _numShaders) { + _currentShader = 0; + } + } else { + _numShaders = 1; + _currentShader = 0; + } + + _shaders[0] = NULL; +} + +PSP2SdlGraphicsManager::~PSP2SdlGraphicsManager() { + if (_vitatex_hwscreen) { + vita2d_free_texture(_vitatex_hwscreen); + for (int i = 0; i < 6; i++) { + vita2d_free_shader(_shaders[i]); + _shaders[i] = NULL; + } + _vitatex_hwscreen = NULL; + } + if (_hwscreen) { + _hwscreen->pixels = _sdlpixels_hwscreen; + } + _sdlpixels_hwscreen = nullptr; +} + +OSystem::TransactionError PSP2SdlGraphicsManager::endGFXTransaction() { + OSystem::TransactionError returnValue = SurfaceSdlGraphicsManager::endGFXTransaction(); + + // force update of filtering on Vita + PSP2_UpdateFiltering(); + + return returnValue; +} + +void PSP2SdlGraphicsManager::setGraphicsModeIntern() { + SurfaceSdlGraphicsManager::setGraphicsModeIntern(); + PSP2_UpdateFiltering(); +} + +void PSP2SdlGraphicsManager::PSP2_UpdateFiltering() { + if (_vitatex_hwscreen) { + if (_videoMode.filtering) { + vita2d_texture_set_filters(_vitatex_hwscreen, SCE_GXM_TEXTURE_FILTER_LINEAR, SCE_GXM_TEXTURE_FILTER_LINEAR); + } else { + vita2d_texture_set_filters(_vitatex_hwscreen, SCE_GXM_TEXTURE_FILTER_POINT, SCE_GXM_TEXTURE_FILTER_POINT); + } + } +} + +const OSystem::GraphicsMode *PSP2SdlGraphicsManager::getSupportedShaders() const { + return s_supportedShadersPSP2; +} + +void PSP2SdlGraphicsManager::unloadGFXMode() { + if (_screen) { + SDL_FreeSurface(_screen); + _screen = NULL; + } + + deinitializeRenderer(); + + if (_hwscreen) { + if (_vitatex_hwscreen) { + vita2d_free_texture(_vitatex_hwscreen); + for (int i = 0; i < 6; i++) { + vita2d_free_shader(_shaders[i]); + _shaders[i] = NULL; + } + _vitatex_hwscreen = NULL; + } + _hwscreen->pixels = _sdlpixels_hwscreen; + } + SurfaceSdlGraphicsManager::unloadGFXMode(); +} + +bool PSP2SdlGraphicsManager::hotswapGFXMode() { + if (!_screen) + return false; + + // Release the HW screen surface + if (_hwscreen) { + if (_vitatex_hwscreen) { + vita2d_free_texture(_vitatex_hwscreen); + for (int i = 0; i < 6; i++) { + vita2d_free_shader(_shaders[i]); + _shaders[i] = NULL; + } + _vitatex_hwscreen = NULL; + } + _hwscreen->pixels = _sdlpixels_hwscreen; + } + return SurfaceSdlGraphicsManager::hotswapGFXMode(); +} + +void PSP2SdlGraphicsManager::updateShader() { +// shader init code goes here +// currently only used on Vita port +// the user-selected shaderID should be obtained via ConfMan.getInt("shader") +// and the corresponding shader should then be activated here +// this way the user can combine any software scaling (scalers) +// with any hardware shading (shaders). The shaders could provide +// scanline masks, overlays, but could also serve for +// hardware-based up-scaling (sharp-bilinear-simple, etc.) + if (_vitatex_hwscreen) { + if (_shaders[0] == NULL) { + // load shaders + _shaders[GFX_SHADER_NONE] = vita2d_create_shader((const SceGxmProgram *)texture_v, (const SceGxmProgram *)texture_f); + _shaders[GFX_SHADER_LCD3X] = vita2d_create_shader((const SceGxmProgram *)lcd3x_v, (const SceGxmProgram *)lcd3x_f); + _shaders[GFX_SHADER_SHARP] = vita2d_create_shader((const SceGxmProgram *)sharp_bilinear_simple_v, (const SceGxmProgram *)sharp_bilinear_simple_f); + _shaders[GFX_SHADER_SHARP_SCAN] = vita2d_create_shader((const SceGxmProgram *)sharp_bilinear_v, (const SceGxmProgram *)sharp_bilinear_f); + _shaders[GFX_SHADER_AAA] = vita2d_create_shader((const SceGxmProgram *)advanced_aa_v, (const SceGxmProgram *)advanced_aa_f); + _shaders[GFX_SHADER_SCALE2X] = vita2d_create_shader((const SceGxmProgram *)scale2x_v, (const SceGxmProgram *)scale2x_f); + } + if (_currentShader >= 0 && _currentShader < _numShaders) { + vita2d_texture_set_program(_shaders[_currentShader]->vertexProgram, _shaders[_currentShader]->fragmentProgram); + vita2d_texture_set_wvp(_shaders[_currentShader]->wvpParam); + vita2d_texture_set_vertexInput(&_shaders[_currentShader]->vertexInput); + vita2d_texture_set_fragmentInput(&_shaders[_currentShader]->fragmentInput); + } + } +} + +void PSP2SdlGraphicsManager::internUpdateScreen() { + SDL_Surface *srcSurf, *origSurf; + int height, width; + ScalerProc *scalerProc; + int scale1; + + // definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?) +#if defined(DEBUG) + assert(_hwscreen != NULL); + assert(_hwscreen->map->sw_data != NULL); +#endif + + // If the shake position changed, fill the dirty area with blackness + if (_currentShakePos != _newShakePos || + (_mouseNeedsRedraw && _mouseBackup.y <= _currentShakePos)) { + SDL_Rect blackrect = {0, 0, (Uint16)(_videoMode.screenWidth * _videoMode.scaleFactor), (Uint16)(_newShakePos * _videoMode.scaleFactor)}; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + blackrect.h = real2Aspect(blackrect.h - 1) + 1; + + SDL_FillRect(_hwscreen, &blackrect, 0); + + _currentShakePos = _newShakePos; + + _forceFull = true; + } + + // Check whether the palette was changed in the meantime and update the + // screen surface accordingly. + if (_screen && _paletteDirtyEnd != 0) { + SDL_SetColors(_screen, _currentPalette + _paletteDirtyStart, + _paletteDirtyStart, + _paletteDirtyEnd - _paletteDirtyStart); + + _paletteDirtyEnd = 0; + + _forceFull = true; + } + + if (!_overlayVisible) { + origSurf = _screen; + srcSurf = _tmpscreen; + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; + scalerProc = _scalerProc; + scale1 = _videoMode.scaleFactor; + } else { + origSurf = _overlayscreen; + srcSurf = _tmpscreen2; + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; + scalerProc = Normal1x; + + scale1 = 1; + } + + // Add the area covered by the mouse cursor to the list of dirty rects if + // we have to redraw the mouse. + if (_mouseNeedsRedraw) + undrawMouse(); + +#ifdef USE_OSD + updateOSD(); +#endif + + // 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; + } + + // Only draw anything if necessary + if (_numDirtyRects > 0 || _mouseNeedsRedraw) { + SDL_Rect *r; + SDL_Rect dst; + uint32 srcPitch, dstPitch; + SDL_Rect *lastRect = _dirtyRectList + _numDirtyRects; + + for (r = _dirtyRectList; r != lastRect; ++r) { + dst = *r; + dst.x++; // Shift rect by one since 2xSai needs to access 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); + srcPitch = srcSurf->pitch; + dstPitch = _hwscreen->pitch; + + for (r = _dirtyRectList; r != lastRect; ++r) { + register int dst_y = r->y + _currentShakePos; + register int dst_h = 0; +#ifdef USE_SCALERS + register int orig_dst_y = 0; +#endif + 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; + +#ifdef USE_SCALERS + orig_dst_y = dst_y; +#endif + dst_y = dst_y * scale1; + + if (_videoMode.aspectRatioCorrection && !_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; + +#ifdef USE_SCALERS + if (_videoMode.aspectRatioCorrection && 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); + // 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 + drawOSD(); +#endif + +#ifdef USE_SDL_DEBUG_FOCUSRECT + // We draw the focus rectangle on top of everything, to assure it's easily visible. + // Of course when the overlay is visible we do not show it, since it is only for game + // specific focus. + if (_enableFocusRect && !_overlayVisible) { + int y = _focusRect.top + _currentShakePos; + int h = 0; + int x = _focusRect.left * scale1; + int w = _focusRect.width() * scale1; + + if (y < height) { + h = _focusRect.height(); + if (h > height - y) + h = height - y; + + y *= scale1; + + if (_videoMode.aspectRatioCorrection && !_overlayVisible) + y = real2Aspect(y); + + if (h > 0 && w > 0) { + // Use white as color for now. + Uint32 rectColor = SDL_MapRGB(_hwscreen->format, 0xFF, 0xFF, 0xFF); + + // First draw the top and bottom lines + // then draw the left and right lines + if (_hwscreen->format->BytesPerPixel == 2) { + uint16 *top = (uint16 *)((byte *)_hwscreen->pixels + y * _hwscreen->pitch + x * 2); + uint16 *bottom = (uint16 *)((byte *)_hwscreen->pixels + (y + h) * _hwscreen->pitch + x * 2); + byte *left = ((byte *)_hwscreen->pixels + y * _hwscreen->pitch + x * 2); + byte *right = ((byte *)_hwscreen->pixels + y * _hwscreen->pitch + (x + w - 1) * 2); + + while (w--) { + *top++ = rectColor; + *bottom++ = rectColor; + } + + while (h--) { + *(uint16 *)left = rectColor; + *(uint16 *)right = rectColor; + + left += _hwscreen->pitch; + right += _hwscreen->pitch; + } + } else if (_hwscreen->format->BytesPerPixel == 4) { + uint32 *top = (uint32 *)((byte *)_hwscreen->pixels + y * _hwscreen->pitch + x * 4); + uint32 *bottom = (uint32 *)((byte *)_hwscreen->pixels + (y + h) * _hwscreen->pitch + x * 4); + byte *left = ((byte *)_hwscreen->pixels + y * _hwscreen->pitch + x * 4); + byte *right = ((byte *)_hwscreen->pixels + y * _hwscreen->pitch + (x + w - 1) * 4); + + while (w--) { + *top++ = rectColor; + *bottom++ = rectColor; + } + + while (h--) { + *(uint32 *)left = rectColor; + *(uint32 *)right = rectColor; + + left += _hwscreen->pitch; + right += _hwscreen->pitch; + } + } + } + } + } +#endif + + // Finally, blit all our changes to the screen + if (!_displayDisabled) { + PSP2_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); + } + } + + _numDirtyRects = 0; + _forceFull = false; + _mouseNeedsRedraw = false; +} + +void PSP2SdlGraphicsManager::setAspectRatioCorrection(bool enable) { + Common::StackLock lock(_graphicsMutex); + + if (_oldVideoMode.setup && _hardwareAspectRatioCorrection == enable) + return; + + if (_transactionMode == kTransactionActive) { + _videoMode.aspectRatioCorrection = false; + _hardwareAspectRatioCorrection = enable; + // erase the screen for both buffers + if (_vitatex_hwscreen) { + for (int i = 0; i <= 10; i++) { + vita2d_start_drawing(); + vita2d_clear_screen(); + vita2d_end_drawing(); + vita2d_swap_buffers(); + } + } + } +} + +SDL_Surface *PSP2SdlGraphicsManager::SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) { + SDL_Surface *screen = SurfaceSdlGraphicsManager::SDL_SetVideoMode(width, height, bpp, flags); + + if (screen != nullptr) { + vita2d_set_vblank_wait(true); + _vitatex_hwscreen = vita2d_create_empty_texture_format(width, height, SCE_GXM_TEXTURE_FORMAT_R5G6B5); + _sdlpixels_hwscreen = screen->pixels; // for SDL_FreeSurface... + screen->pixels = vita2d_texture_get_datap(_vitatex_hwscreen); + updateShader(); + } + return screen; +} + +void PSP2SdlGraphicsManager::PSP2_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects) { + int x, y, w, h; + float sx, sy; + float ratio = (float)screen->w / (float)screen->h; + + if ((_videoMode.screenHeight == 200 || _videoMode.screenHeight == 400) && _hardwareAspectRatioCorrection) { + ratio = ratio * (200.0f / 240.0f); + } + + if (_videoMode.fullscreen || screen->h >= 544) { + h = 544; + w = h * ratio; + } else { + if (screen->h <= 277 && screen->w <= 480) { + // Use Vita hardware 2x scaling if the picture is really small + // this uses the current shader and filtering mode + h = screen->h * 2; + w = screen->w * 2; + } else { + h = screen->h; + w = screen->w; + } + if ((_videoMode.screenHeight == 200 || _videoMode.screenHeight == 400) && _hardwareAspectRatioCorrection) { + // stretch the height only if it fits, otherwise make the width smaller + if (((float)w * (1.0f / ratio)) <= 544.0f) { + h = w * (1.0f / ratio); + } else { + w = h * ratio; + } + } + } + + x = (960 - w) / 2; y = (544 - h) / 2; + sx = (float)w / (float)screen->w; + sy = (float)h / (float)screen->h; + if (_vitatex_hwscreen) { + vita2d_start_drawing(); + vita2d_draw_texture_scale(_vitatex_hwscreen, x, y, sx, sy); + vita2d_end_drawing(); + vita2d_swap_buffers(); + } +} + +#endif diff --git a/backends/graphics/psp2sdl/psp2sdl-graphics.h b/backends/graphics/psp2sdl/psp2sdl-graphics.h new file mode 100644 index 0000000000..638437c9a6 --- /dev/null +++ b/backends/graphics/psp2sdl/psp2sdl-graphics.h @@ -0,0 +1,55 @@ +/* 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 BACKENDS_GRAPHICS_PSP2SDL_GRAPHICS_H +#define BACKENDS_GRAPHICS_PSP2SDL_GRAPHICS_H + +#include "backends/graphics/surfacesdl/surfacesdl-graphics.h" +#include <vita2d_fbo.h> + +class PSP2SdlGraphicsManager : public SurfaceSdlGraphicsManager { +public: + PSP2SdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window); + virtual ~PSP2SdlGraphicsManager(); + + virtual OSystem::TransactionError endGFXTransaction(); + virtual const OSystem::GraphicsMode *getSupportedShaders() const; + +protected: + virtual void setGraphicsModeIntern(); + virtual void unloadGFXMode(); + virtual bool hotswapGFXMode(); + + virtual void internUpdateScreen(); + virtual void updateShader(); + virtual void setAspectRatioCorrection(bool enable); + virtual SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); + void PSP2_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects); + void PSP2_UpdateFiltering(); + + bool _hardwareAspectRatioCorrection; + vita2d_texture *_vitatex_hwscreen; + void *_sdlpixels_hwscreen; + vita2d_shader *_shaders[6]; +}; + +#endif diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index 6cd5a47e1c..4eb63fd303 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -43,6 +43,11 @@ #include "graphics/surface.h" #include "gui/EventRecorder.h" +static const OSystem::GraphicsMode s_supportedShaders[] = { + {"NONE", "Normal (no shader)", 0}, + {0, 0, 0} +}; + static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { {"1x", _s("Normal (no scaling)"), GFX_NORMAL}, #ifdef USE_SCALERS @@ -194,6 +199,23 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou #if SDL_VERSION_ATLEAST(2, 0, 0) _videoMode.filtering = ConfMan.getBool("filtering"); #endif + + if (g_system->hasFeature(OSystem::kFeatureShader)) { + // shader number 0 is the entry NONE (no shader) + const OSystem::GraphicsMode *p = s_supportedShaders; + _numShaders = 0; + while (p->name) { + _numShaders++; + p++; + } + _currentShader = ConfMan.getInt("shader"); + if (_currentShader < 0 || _currentShader >= _numShaders) { + _currentShader = 0; + } + } else { + _numShaders = 1; + _currentShader = 0; + } } SurfaceSdlGraphicsManager::~SurfaceSdlGraphicsManager() { @@ -602,6 +624,8 @@ void SurfaceSdlGraphicsManager::setGraphicsModeIntern() { Common::StackLock lock(_graphicsMutex); ScalerProc *newScalerProc = 0; + updateShader(); + switch (_videoMode.mode) { case GFX_NORMAL: newScalerProc = Normal1x; @@ -676,6 +700,21 @@ int SurfaceSdlGraphicsManager::getGraphicsMode() const { return _videoMode.mode; } +const OSystem::GraphicsMode *SurfaceSdlGraphicsManager::getSupportedShaders() const { + return s_supportedShaders; +} + +int SurfaceSdlGraphicsManager::getShader() { + return _currentShader; +} + +bool SurfaceSdlGraphicsManager::setShader(int id) { + assert(id >= 0 && id < _numShaders); + _currentShader = id; + updateShader(); + return true; +} + void SurfaceSdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFormat *format) { assert(_transactionMode == kTransactionActive); @@ -996,10 +1035,18 @@ bool SurfaceSdlGraphicsManager::hotswapGFXMode() { _overlayscreen = NULL; // Release the HW screen surface - SDL_FreeSurface(_hwscreen); _hwscreen = NULL; - - SDL_FreeSurface(_tmpscreen); _tmpscreen = NULL; - SDL_FreeSurface(_tmpscreen2); _tmpscreen2 = NULL; + if (_hwscreen) { + SDL_FreeSurface(_hwscreen); + _hwscreen = NULL; + } + if (_tmpscreen) { + SDL_FreeSurface(_tmpscreen); + _tmpscreen = NULL; + } + if (_tmpscreen2) { + SDL_FreeSurface(_tmpscreen2); + _tmpscreen2 = NULL; + } // Setup the new GFX mode if (!loadGFXMode()) { @@ -1039,6 +1086,17 @@ void SurfaceSdlGraphicsManager::updateScreen() { internUpdateScreen(); } +void SurfaceSdlGraphicsManager::updateShader() { +// shader init code goes here +// currently only used on Vita port +// the user-selected shaderID should be obtained via ConfMan.getInt("shader") +// and the corresponding shader should then be activated here +// this way the user can combine any software scaling (scalers) +// with any hardware shading (shaders). The shaders could provide +// scanline masks, overlays, but could also serve for +// hardware-based up-scaling (sharp-bilinear-simple, etc.) +} + void SurfaceSdlGraphicsManager::internUpdateScreen() { SDL_Surface *srcSurf, *origSurf; int height, width; @@ -2554,7 +2612,8 @@ void SurfaceSdlGraphicsManager::deinitializeRenderer() { SDL_DestroyRenderer(_renderer); _renderer = nullptr; - _window->destroyWindow(); + if (_window) + _window->destroyWindow(); } void SurfaceSdlGraphicsManager::setWindowResolution(int width, int height) { diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h index 975cbfe27b..ef41b90f6c 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.h +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h @@ -105,6 +105,9 @@ public: virtual Graphics::PixelFormat getScreenFormat() const { return _screenFormat; } virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const; #endif + virtual const OSystem::GraphicsMode *getSupportedShaders() const; + virtual int getShader(); + virtual bool setShader(int id); virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL); virtual int getScreenChangeID() const { return _screenChangeCount; } @@ -200,7 +203,7 @@ protected: void setWindowResolution(int width, int height); void recreateScreenTexture(); - SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); + virtual SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects); #endif @@ -302,6 +305,9 @@ protected: int _screenChangeCount; + int _currentShader; + int _numShaders; + enum { NUM_DIRTY_RECT = 100, MAX_SCALING = 3 @@ -384,6 +390,7 @@ protected: virtual void blitCursor(); virtual void internUpdateScreen(); + virtual void updateShader(); virtual bool loadGFXMode(); virtual void unloadGFXMode(); diff --git a/backends/mixer/sdl/sdl-mixer.cpp b/backends/mixer/sdl/sdl-mixer.cpp index 0ca3231892..3e65fbae97 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) +#elif defined(PLAYSTATION3) || defined(PSP2) #define SAMPLES_PER_SEC 48000 #else #define SAMPLES_PER_SEC 44100 diff --git a/backends/modular-backend.cpp b/backends/modular-backend.cpp index 1fef5c5a48..1dab18d54e 100644 --- a/backends/modular-backend.cpp +++ b/backends/modular-backend.cpp @@ -81,6 +81,18 @@ int ModularBackend::getGraphicsMode() const { return _graphicsManager->getGraphicsMode(); } +const OSystem::GraphicsMode *ModularBackend::getSupportedShaders() const { + return _graphicsManager->getSupportedShaders(); +} + +bool ModularBackend::setShader(int id) { + return _graphicsManager->setShader(id); +} + +int ModularBackend::getShader() const { + return _graphicsManager->getShader(); +} + void ModularBackend::resetGraphicsScale() { _graphicsManager->resetGraphicsScale(); } diff --git a/backends/modular-backend.h b/backends/modular-backend.h index 23f0e2d547..d828c2dde6 100644 --- a/backends/modular-backend.h +++ b/backends/modular-backend.h @@ -66,6 +66,9 @@ public: virtual int getDefaultGraphicsMode() const; virtual bool setGraphicsMode(int mode); virtual int getGraphicsMode() const; + virtual const GraphicsMode *getSupportedShaders() const; + virtual int getShader() const; + virtual bool setShader(int id); virtual void resetGraphicsScale(); #ifdef USE_RGB_COLOR virtual Graphics::PixelFormat getScreenFormat() const; diff --git a/backends/module.mk b/backends/module.mk index 158f9a3b7c..d8b518b59a 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -290,6 +290,15 @@ MODULE_OBJS += \ timer/psp/timer.o endif +ifeq ($(BACKEND),psp2) +MODULE_OBJS += \ + fs/posix/posix-fs.o \ + fs/psp2/psp2-fs-factory.o \ + fs/psp2/psp2-dirent.o \ + events/psp2sdl/psp2sdl-events.o \ + graphics/psp2sdl/psp2sdl-graphics.o +endif + ifeq ($(BACKEND),samsungtv) MODULE_OBJS += \ events/samsungtvsdl/samsungtvsdl-events.o \ diff --git a/backends/platform/sdl/module.mk b/backends/platform/sdl/module.mk index 84ce272d3c..7fde04037f 100644 --- a/backends/platform/sdl/module.mk +++ b/backends/platform/sdl/module.mk @@ -37,6 +37,13 @@ MODULE_OBJS += \ ps3/ps3.o endif +ifdef PSP2 +CC=arm-vita-eabi-gcc +MODULE_OBJS += \ + psp2/psp2-main.o \ + psp2/psp2.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 5deebb0ae3..92354b273e 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(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) #include "backends/platform/sdl/posix/posix.h" #include "backends/plugins/sdl/sdl-provider.h" diff --git a/backends/platform/sdl/psp2/psp2-main.cpp b/backends/platform/sdl/psp2/psp2-main.cpp new file mode 100644 index 0000000000..0bdf0b34bc --- /dev/null +++ b/backends/platform/sdl/psp2/psp2-main.cpp @@ -0,0 +1,66 @@ +/* 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 <psp2/kernel/processmgr.h> +#include <psp2/power.h> + +#include "common/scummsys.h" +#include "backends/platform/sdl/psp2/psp2.h" +#include "backends/plugins/sdl/sdl-provider.h" +#include "base/main.h" + +int _newlib_heap_size_user = 192 * 1024 * 1024; + +int main(int argc, char *argv[]) { + +#ifdef __PSP2_DEBUG__ + psp2shell_init(3333, 10); +#endif + + scePowerSetArmClockFrequency(444); + scePowerSetBusClockFrequency(222); + scePowerSetGpuClockFrequency(222); + scePowerSetGpuXbarClockFrequency(166); + + // Create our OSystem instance + g_system = new OSystem_PSP2(); + assert(g_system); + + // Pre initialize the backend + ((OSystem_PSP2 *)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_PSP2 *)g_system; + +#ifdef __PSP2_DEBUG__ + psp2shell_exit(); +#endif + + return res; +} diff --git a/backends/platform/sdl/psp2/psp2.cpp b/backends/platform/sdl/psp2/psp2.cpp new file mode 100644 index 0000000000..3c0cb9106d --- /dev/null +++ b/backends/platform/sdl/psp2/psp2.cpp @@ -0,0 +1,143 @@ +/* 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_mkdir +#define FORBIDDEN_SYMBOL_EXCEPTION_time_h // sys/stat.h includes sys/time.h +#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h + +#include "common/scummsys.h" +#include "common/config-manager.h" +#include "common/debug-channels.h" +#include "backends/platform/sdl/psp2/psp2.h" +#include "backends/graphics/psp2sdl/psp2sdl-graphics.h" +#include "backends/saves/default/default-saves.h" + +#include "backends/fs/psp2/psp2-fs-factory.h" +#include "backends/events/psp2sdl/psp2sdl-events.h" +#include "backends/fs/psp2/psp2-dirent.h" +#include <sys/stat.h> + +#ifdef __PSP2_DEBUG__ +#include <psp2shell.h> +#endif + +int access(const char *pathname, int mode) { + struct stat sb; + + if (stat(pathname, &sb) == -1) { + return -1; + } + + return 0; +} + +OSystem_PSP2::OSystem_PSP2(Common::String baseConfigName) + : _baseConfigName(baseConfigName) { +} + +void OSystem_PSP2::init() { + +#if __PSP2_DEBUG__ + gDebugLevel = 3; +#endif + + // Initialze File System Factory + sceIoMkdir("ux0:data", 0755); + sceIoMkdir("ux0:data/scummvm", 0755); + sceIoMkdir("ux0:data/scummvm/saves", 0755); + _fsFactory = new PSP2FilesystemFactory(); + + // Invoke parent implementation of this method + OSystem_SDL::init(); +} + +void OSystem_PSP2::initBackend() { + + ConfMan.set("joystick_num", 0); + ConfMan.set("vkeybdpath", PREFIX "/data"); + ConfMan.registerDefault("fullscreen", true); + ConfMan.registerDefault("aspect_ratio", false); + ConfMan.registerDefault("gfx_mode", "2x"); + ConfMan.registerDefault("filtering", true); + ConfMan.registerDefault("kbdmouse_speed", 3); + ConfMan.registerDefault("joystick_deadzone", 2); + ConfMan.registerDefault("shader", 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("filtering")) { + ConfMan.setBool("filtering", true); + } + if (!ConfMan.hasKey("kbdmouse_speed")) { + ConfMan.setInt("kbdmouse_speed", 3); + } + if (!ConfMan.hasKey("joystick_deadzone")) { + ConfMan.setInt("joystick_deadzone", 2); + } + if (!ConfMan.hasKey("shader")) { + ConfMan.setInt("shader", 0); + } + + // Create the savefile manager + if (_savefileManager == 0) + _savefileManager = new DefaultSaveFileManager("ux0:data/scummvm/saves"); + + // Event source + if (_eventSource == 0) + _eventSource = new PSP2EventSource(); + + // Graphics Manager + if (_graphicsManager == 0) + _graphicsManager = new PSP2SdlGraphicsManager(_eventSource, _window); + + // Invoke parent implementation of this method + OSystem_SDL::initBackend(); +} + +bool OSystem_PSP2::hasFeature(Feature f) { + return (f == kFeatureKbdMouseSpeed || + f == kFeatureJoystickDeadzone || + f == kFeatureShader || + OSystem_SDL::hasFeature(f)); +} + +void OSystem_PSP2::logMessage(LogMessageType::Type type, const char *message) { +#if __PSP2_DEBUG__ + psp2shell_print(message); +#endif +} + +Common::String OSystem_PSP2::getDefaultConfigFileName() { + return "ux0:data/scummvm/" + _baseConfigName; +} + +Common::WriteStream *OSystem_PSP2::createLogFile() { + Common::FSNode file("ux0:data/scummvm/scummvm.log"); + return file.createWriteStream(); +} diff --git a/backends/platform/sdl/psp2/psp2.h b/backends/platform/sdl/psp2/psp2.h new file mode 100644 index 0000000000..65d98098be --- /dev/null +++ b/backends/platform/sdl/psp2/psp2.h @@ -0,0 +1,52 @@ +/* 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_PSP2_H +#define PLATFORM_SDL_PSP2_H + +#include "backends/platform/sdl/sdl.h" +#ifdef __PSP2_DEBUG__ +#include <psp2shell.h> +#endif + +class OSystem_PSP2 : public OSystem_SDL { +public: + // Let the subclasses be able to change _baseConfigName in the constructor + OSystem_PSP2(Common::String baseConfigName = "scummvm.ini"); + virtual ~OSystem_PSP2() {} + + virtual void init(); + virtual void initBackend(); + virtual bool hasFeature(Feature f); + virtual void logMessage(LogMessageType::Type type, const char *message); + +protected: + // Base string for creating the default path and filename + // for the configuration file + Common::String _baseConfigName; + + virtual Common::String getDefaultConfigFileName(); + + virtual Common::WriteStream *createLogFile(); +}; + +#endif diff --git a/backends/platform/sdl/psp2/psp2.mk b/backends/platform/sdl/psp2/psp2.mk new file mode 100644 index 0000000000..b719ed7acf --- /dev/null +++ b/backends/platform/sdl/psp2/psp2.mk @@ -0,0 +1,26 @@ +DATE := $(shell date +%y-%m-%d) + +psp2vpk: $(EXECUTABLE) + rm -rf psp2pkg + rm -f $(EXECUTABLE)-$(DATE).vpk + mkdir -p psp2pkg/sce_sys/livearea/contents + mkdir -p psp2pkg/data/ + mkdir -p psp2pkg/doc/ + vita-elf-create $(EXECUTABLE) $(EXECUTABLE).velf + vita-make-fself -s -c $(EXECUTABLE).velf psp2pkg/eboot.bin + vita-mksfoex -s TITLE_ID=VSCU00001 "$(EXECUTABLE)" psp2pkg/sce_sys/param.sfo + cp $(srcdir)/dists/psp2/icon0.png psp2pkg/sce_sys/ + cp $(srcdir)/dists/psp2/template.xml psp2pkg/sce_sys/livearea/contents/ + cp $(srcdir)/dists/psp2/bg.png psp2pkg/sce_sys/livearea/contents/ + cp $(srcdir)/dists/psp2/startup.png psp2pkg/sce_sys/livearea/contents/ + cp $(srcdir)/backends/vkeybd/packs/vkeybd_default.zip psp2pkg/data/ + cp $(srcdir)/backends/vkeybd/packs/vkeybd_small.zip psp2pkg/data/ + cp $(DIST_FILES_THEMES) psp2pkg/data/ +ifdef DIST_FILES_ENGINEDATA + cp $(DIST_FILES_ENGINEDATA) psp2pkg/data/ +endif + cp $(DIST_FILES_DOCS) psp2pkg/doc/ + cp $(srcdir)/dists/psp2/readme-psp2.md psp2pkg/doc/ + cd psp2pkg && zip -r ../$(EXECUTABLE)-$(DATE).vpk . && cd .. + +.PHONY: psp2vpk diff --git a/common/system.h b/common/system.h index 83bc457707..68d33b78be 100644 --- a/common/system.h +++ b/common/system.h @@ -361,7 +361,12 @@ public: /** * change analog joystick deadzone */ - kFeatureJoystickDeadzone + kFeatureJoystickDeadzone, + + /** + * shaders + */ + kFeatureShader }; @@ -573,6 +578,34 @@ public: #endif /** + * Retrieve a list of all hardware shaders supported by this backend. + * This can be only hardware shaders. + * it is completely up to the backend maintainer to decide what is + * appropriate here and what not. + * The list is terminated by an all-zero entry. + * @return a list of supported shaders + */ + virtual const GraphicsMode *getSupportedShaders() const { + static const OSystem::GraphicsMode no_shader[2] = {{"NONE", "Normal (no shader)", 0}, {0, 0, 0}}; + return no_shader; + } + + /** + * Switch to the specified shader mode. If switching to the new mode + * failed, this method returns false. + * + * @param mode the ID of the new shader mode + * @return true if the switch was successful, false otherwise + */ + virtual bool setShader(int id) { return false; } + + /** + * Determine which shader is currently active. + * @return the ID of the active shader + */ + virtual int getShader() { return 0; } + + /** * Set the size and color format of the virtual screen. Typical sizes include: * - 320x200 (e.g. for most SCUMM games, and Simon) * - 320x240 (e.g. for FM-TOWN SCUMM games) @@ -883,7 +883,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, samsungtv, sdl, tizen, webos, wii, wince) [sdl] + ps2, psp, psp2, samsungtv, sdl, tizen, webos, wii, wince) [sdl] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX @@ -934,6 +934,7 @@ Special configuration feature: ouya for OUYA ps2 for PlayStation 2 ps3 for PlayStation 3 + psp2 for PlayStation Vita psp for PlayStation Portable samsungtv for Samsung TV tizen for Samsung Tizen @@ -1559,6 +1560,22 @@ ps3) datadir='${datarootdir}' docdir='${prefix}/doc' ;; +psp2) + _host_os=psp2 + _host_cpu=arm + _host_alias=arm-vita-eabi + + # The prefix is always the same on PSP2 so we hardcode the default + # here. It is still possible to define a custom prefix which is + # needed when packaging the app with a user-specific app ID. + test "x$prefix" = xNONE && prefix=app0: + # PSP2 apps are installed into app-specific directories. The + # default directory structure of ScummVM makes no sense here so we + # hardcode PSP2 specific directories here. + datarootdir='${prefix}/data' + datadir='${datarootdir}' + docdir='${prefix}/doc' + ;; psp) _host_os=psp _host_cpu=mipsallegrexel @@ -1625,7 +1642,7 @@ fi # case $_host in -caanoo | gp2x | gp2xwiz | openpandora | ps2) +caanoo | gp2x | gp2xwiz | openpandora | ps2 | psp2) if test "$_debug_build" = auto; then # If you want to debug one of these platforms, use '--disable-optimizations --enable-debug' _debug_build=no @@ -1719,6 +1736,12 @@ ps3) exit 1 fi ;; +psp2) + if test -z "$VITASDK"; then + echo "Please set VITASDK in your environment. export VITASDK=<path to psp2 toolchain>" + exit 1 + fi + ;; psp) if test -z "$PSPDEV"; then PSPDEV=`psp-config --pspdev-path` @@ -1947,7 +1970,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* | n64 | psp | ps2 | ps3 | tizen | wii | wince ) + 3ds | amigaos* | android | androidsdl | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | psp2 | tizen | wii | wince ) ;; *) append_var CXXFLAGS "-ansi" @@ -2200,6 +2223,9 @@ case $_host_cpu in ;; arm-apple-darwin11) ;; + # psvita does not like the asm code... + arm-vita-eabi) + ;; *) define_in_config_if_yes yes 'USE_ARM_SCALER_ASM' @@ -2627,6 +2653,27 @@ case $_host_os in add_line_to_config_mk 'PLAYSTATION3 = 1' add_line_to_config_h "#define PREFIX \"${prefix}\"" ;; + psp2) + _freetypepath="$VITASDK/arm-vita-eabi/bin" + _freetype2=yes + _libcurlpath="$VITASDK/arm-vita-eabi/bin" + append_var CXXFLAGS "--sysroot=$VITASDK/arm-vita-eabi" + append_var LDFLAGS "--sysroot=$VITASDK/arm-vita-eabi" + append_var DEFINES "-DPSP2 -DSYSTEM_NOT_SUPPORTING_D_TYPE" + append_var CXXFLAGS "-Wl,-q -I$VITASDK/arm-vita-eabi/include" + append_var CXXFLAGS "-march=armv7-a -mtune=cortex-a9 -mfpu=neon -mfloat-abi=hard" + append_var LDFLAGS "-Wl,-q -L$VITASDK/arm-vita-eabi/lib" + if test "$_debug_build" = no; then + _optimization_level=-O1 + fi + if test "$_debug_build" = yes; then + _optimization_level=-O0 + append_var DEFINES "-D__PSP2_DEBUG__" + append_var LIBS "-lpsp2shell" + fi + add_line_to_config_mk 'PSP2 = 1' + add_line_to_config_h "#define PREFIX \"${prefix}\"" + ;; psp) if test -d "$PSPDEV/psp/lib"; then append_var LDFLAGS "-L$PSPDEV/psp/lib" @@ -3121,6 +3168,16 @@ if test -n "$_host"; then _eventrec=no _port_mk="backends/platform/sdl/ps3/ps3.mk" ;; + psp2) + _backend="psp2" + _vkeybd=yes + _build_scalers=yes + _build_hq_scalers=no + _mt32emu=no + _timidity=no + _eventrec=no + _port_mk="backends/platform/sdl/psp2/psp2.mk" + ;; psp) _backend="psp" _build_scalers=no @@ -3294,6 +3351,17 @@ case $_backend in append_var LIBS "-lpng" append_var LIBS "-Wl,-Map,mapfile.txt" ;; + psp2) + append_var LIBS "-lvitashaders -lSDL2 -lvita2d_fbo -lSceCommonDialog_stub" + append_var LIBS "-lSceSysmodule_stub -lSceDisplay_stub -lSceGxm_stub" + append_var LIBS "-lSceAudio_stub -lSceCtrl_stub -lScePower_stub" + append_var LIBS "-lSceNet_stub -lSceNetCtl_stub -lSceAppMgr_stub -lScePgf_stub" + append_var DEFINES "-DSDL_BACKEND" + add_line_to_config_mk "SDL_BACKEND = 1" + add_line_to_config_mk "USE_SDL2 = 1" + append_var MODULES "backends/platform/sdl" + append_var INCLUDES "-I$VITASDK/arm-vita-eabi/include/SDL2" + ;; samsungtv) append_var DEFINES "-DSAMSUNGTV" append_var LDFLAGS "-shared" @@ -3404,7 +3472,7 @@ esac # Enable 16bit support only for backends which support it # case $_backend in - 3ds | android | androidsdl | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii) + 3ds | android | androidsdl | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | psp2 | samsungtv | sdl | tizen | webos | wii) if test "$_16bit" = auto ; then _16bit=yes else @@ -3480,7 +3548,7 @@ esac # echo_n "Checking if host is POSIX compliant... " case $_host_os in - amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp | wii | wince) + amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp2 | psp | 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) @@ -4189,6 +4257,9 @@ if test "$_libcurl" != "no"; then amigaos*) append_var LIBCURL_LIBS "-lpthread" ;; + psp2*) + append_var LIBCURL_LIBS "-lssl -lcrypto" + ;; esac if test "$_libcurl" = "auto"; then diff --git a/dists/psp2/bg.png b/dists/psp2/bg.png Binary files differnew file mode 100644 index 0000000000..a6fa8bdc81 --- /dev/null +++ b/dists/psp2/bg.png diff --git a/dists/psp2/icon0.png b/dists/psp2/icon0.png Binary files differnew file mode 100644 index 0000000000..65696f6f55 --- /dev/null +++ b/dists/psp2/icon0.png diff --git a/dists/psp2/readme-psp2.md b/dists/psp2/readme-psp2.md new file mode 100644 index 0000000000..559c2fbd60 --- /dev/null +++ b/dists/psp2/readme-psp2.md @@ -0,0 +1,64 @@ +Prerequisites +============= +- A homebrew enabled PlayStation Vita console. +- At least one ScummVM supported game. The list of compatible games can be seen here: http://www.scummvm.org/compatibility/ +The page http://wiki.scummvm.org/index.php/Where_to_get_the_games references some places where those games can be bought. Demonstration versions for most of the supported games are downloadable on http://scummvm.org/demos/ + +Installing +========== +From a computer, download the installable package. Unzip and copy the .vpk file it to the PlayStation Vita and install it. + +Configuring and playing games +============================= +The user manual describes how to add games to ScummVM and launch them : http://wiki.scummvm.org/index.php/User_Manual + +PlayStation Vita Specifics +========================== +Saves are wrote in the ux0:/data/scummvm/saves folder. + +Joypad button mapping +===================== +- Left stick => Mouse +- R + Left stick => Slow Mouse +- Cross => Left mouse button +- Circle => Right mouse button +- DPad => Cursor Keys (useful for character motion) +- R + DPad => Diagonal Cursor Keys +- L Trigger => Game menu (F5) +- R Trigger => Shift (used to enable Mass Add in menu) +- Square => Period '.' (used to skip dialog lines) +- R + Square => Space ' ' +- Triangle => Escape (used to skip cutscenes) +- R + Triangle => Return +- Start => ScummVM's global in-game menu +- Select => Toggle virtual keyboard +- R + Select => AGI predictive input dialog + +Disclaimer +========== +Unauthorized distribution of an installable package with non freeware games included is a violation of the copyright law and is as such forbidden. + +Building from source +==================== +This port of ScummVM to the PSP2 is based on SDL2. It uses the open source SDK VITASDK. + +The dependencies needed to build it are : + +- The toolchain from https://github.com/vitadev/vdpm +- zlib, libpng, libjpeg-turbo, libogg, libvorbis, flac, curl, openssl, freetype, from https://github.com/vitadev/vdpm +- libmad from https://github.com/Cpasjuste/libmad-psp2 +- SDL2 from https://github.com/Cpasjuste/SDL-Vita +- ScummVM from https://github.com/Cpasjuste/scummvm +- The fbo branch of libvita2d from https://github.com/frangarcj/vita2dlib/tree/fbo/libvita2d +copied under new names libvita2d_fbo.a in $VITASDK/arm-vita-eabi-gcc/lib and vita2d_fbo.h in $VITASDK/arm-vita-eabi-gcc/include. The renaming is necessary to prevent conflict with the official vita2d lib that comes with the VitaSDK. +- The pre-compiled gtu release of vita-shader-collection from https://github.com/frangarcj/vita-shader-collection/releases, copy all headers to $VITASDK/arm-vita-eabi-gcc/include and the library libvitashaders.a to $VITASDK/arm-vita-eabi-gcc/lib + +Once all the dependencies are correctly setup, an installable package can be obtained from source by issuing the following command : + +./configure --host=psp2 && make psp2vpk + +Thanks +====== +Xavier from consoleX for donating a ps vita device +xerpi for initial SDL2 port +VITASDK and henkaku developers diff --git a/dists/psp2/startup.png b/dists/psp2/startup.png Binary files differnew file mode 100644 index 0000000000..4f50ea395f --- /dev/null +++ b/dists/psp2/startup.png diff --git a/dists/psp2/template.xml b/dists/psp2/template.xml new file mode 100644 index 0000000000..a4d43f0130 --- /dev/null +++ b/dists/psp2/template.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> + +<livearea style="a1" format-ver="01.00" content-rev="1"> + <livearea-background> + <image>bg.png</image> + </livearea-background> + + <gate> + <startup-image>startup.png</startup-image> + </gate> +</livearea> diff --git a/gui/options.cpp b/gui/options.cpp index eb25f3bbb2..08b5538a1f 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -159,6 +159,9 @@ void OptionsDialog::init() { _fullscreenCheckbox = 0; _filteringCheckbox = 0; _aspectCheckbox = 0; + _enableShaderSettings = false; + _shaderPopUpDesc = 0; + _shaderPopUp = 0; _enableAudioSettings = false; _midiPopUp = 0; _midiPopUpDesc = 0; @@ -315,6 +318,14 @@ void OptionsDialog::build() { } + // Shader options + if (g_system->hasFeature(OSystem::kFeatureShader)) { + if (_shaderPopUp) { + int value = ConfMan.getInt("shader", _domain); + _shaderPopUp->setSelected(value); + } + } + // Audio options if (!loadMusicDeviceSetting(_midiPopUp, "music_driver")) _midiPopUp->setSelected(0); @@ -549,6 +560,18 @@ void OptionsDialog::apply() { } } + // Shader options + if (_enableShaderSettings) { + if (g_system->hasFeature(OSystem::kFeatureShader)) { + if (_shaderPopUp) { + if (ConfMan.getInt("shader", _domain) != _shaderPopUp->getSelectedTag()) { + ConfMan.setInt("shader", _shaderPopUp->getSelectedTag(), _domain); + g_system->setShader(_shaderPopUp->getSelectedTag()); + } + } + } + } + // Control options if (_enableControlSettings) { if (g_system->hasFeature(OSystem::kFeatureOnScreenControl)) { @@ -967,6 +990,23 @@ void OptionsDialog::addControlControls(GuiObject *boss, const Common::String &pr _enableControlSettings = true; } +void OptionsDialog::addShaderControls(GuiObject *boss, const Common::String &prefix) { + // Shader selector + if (g_system->hasFeature(OSystem::kFeatureShader)) { + if (g_system->getOverlayWidth() > 320) + _shaderPopUpDesc = new StaticTextWidget(boss, prefix + "grShaderPopUpDesc", _("HW Shader:"), _("Different hardware shaders give different visual effects")); + else + _shaderPopUpDesc = new StaticTextWidget(boss, prefix + "grShaderPopUpDesc", _c("HW Shader:", "lowres"), _("Different hardware shaders give different visual effects")); + _shaderPopUp = new PopUpWidget(boss, prefix + "grShaderPopUp", _("Different shaders give different visual effects")); + const OSystem::GraphicsMode *p = g_system->getSupportedShaders(); + while (p->name) { + _shaderPopUp->appendEntry(p->name, p->id); + p++; + } + } + _enableShaderSettings = true; +} + void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &prefix) { const OSystem::GraphicsMode *gm = g_system->getSupportedGraphicsModes(); Common::String context; @@ -1422,6 +1462,15 @@ void GlobalOptionsDialog::build() { addGraphicControls(tab, "GlobalOptions_Graphics."); // + // The shader tab (currently visible only for Vita platform), visibility checking by features + // + + if (g_system->hasFeature(OSystem::kFeatureShader)) { + tab->addTab(_("Shader")); + addShaderControls(tab, "GlobalOptions_Shader."); + } + + // // The control tab (currently visible only for AndroidSDL, SDL, and Vita platform, visibility checking by features // if (g_system->hasFeature(OSystem::kFeatureTouchpadMode) || diff --git a/gui/options.h b/gui/options.h index 2f628315e4..ed07307f80 100644 --- a/gui/options.h +++ b/gui/options.h @@ -89,6 +89,7 @@ protected: void addControlControls(GuiObject *boss, const Common::String &prefix); void addGraphicControls(GuiObject *boss, const Common::String &prefix); + void addShaderControls(GuiObject *boss, const Common::String &prefix); void addAudioControls(GuiObject *boss, const Common::String &prefix); void addMIDIControls(GuiObject *boss, const Common::String &prefix); void addMT32Controls(GuiObject *boss, const Common::String &prefix); @@ -142,6 +143,13 @@ private: CheckboxWidget *_aspectCheckbox; StaticTextWidget *_renderModePopUpDesc; PopUpWidget *_renderModePopUp; + + // + // Shader controls + // + bool _enableShaderSettings; + StaticTextWidget *_shaderPopUpDesc; + PopUpWidget *_shaderPopUp; // // Audio controls diff --git a/gui/themes/default.inc b/gui/themes/default.inc index f967067adc..6e79450e23 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -877,6 +877,16 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "</layout>" "</dialog>" +"<dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'>" +"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>" +"<widget name = 'grShaderPopUpDesc' " +"type = 'OptionsLabel' " +"/>" +"<widget name = 'grShaderPopUp' " +"type = 'PopUp' " +"/>" +"</layout>" +"</dialog>" "<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>" "<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" @@ -2454,6 +2464,16 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "/>" "</layout>" "</dialog>" +"<dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'>" +"<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>" +"<widget name = 'grShaderPopUpDesc' " +"type = 'OptionsLabel' " +"/>" +"<widget name = 'grShaderPopUp' " +"type = 'PopUp' " +"/>" +"</layout>" +"</dialog>" "<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>" "<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip Binary files differindex 8024437f6b..bff0388d3e 100644 --- a/gui/themes/scummclassic.zip +++ b/gui/themes/scummclassic.zip diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx index 35f4a03e6d..9d9fe28a16 100644 --- a/gui/themes/scummclassic/classic_layout.stx +++ b/gui/themes/scummclassic/classic_layout.stx @@ -304,6 +304,19 @@ </layout> </dialog> + <dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'> + <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'> + <widget name = 'grShaderPopUpDesc' + type = 'OptionsLabel' + /> + <widget name = 'grShaderPopUp' + type = 'PopUp' + /> + </layout> + </layout> + </dialog> + <dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'> <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'> diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx index 1085c5fc6f..d0c3170d8e 100644 --- a/gui/themes/scummclassic/classic_layout_lowres.stx +++ b/gui/themes/scummclassic/classic_layout_lowres.stx @@ -301,6 +301,19 @@ </layout> </dialog> + <dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'> + <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'> + <widget name = 'grShaderPopUpDesc' + type = 'OptionsLabel' + /> + <widget name = 'grShaderPopUp' + type = 'PopUp' + /> + </layout> + </layout> + </dialog> + <dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'> <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'> diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip Binary files differindex 73aee35f61..983f727f6a 100644 --- a/gui/themes/scummmodern.zip +++ b/gui/themes/scummmodern.zip diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx index 9633cb4e50..25a95845aa 100644 --- a/gui/themes/scummmodern/scummmodern_layout.stx +++ b/gui/themes/scummmodern/scummmodern_layout.stx @@ -318,6 +318,19 @@ </layout> </dialog> + <dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'> + <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'> + <widget name = 'grShaderPopUpDesc' + type = 'OptionsLabel' + /> + <widget name = 'grShaderPopUp' + type = 'PopUp' + /> + </layout> + </layout> + </dialog> + <dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'> <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'> diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx index be8ce0c17e..3da8a6c6a3 100644 --- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx +++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx @@ -299,6 +299,19 @@ </layout> </dialog> + <dialog name = 'GlobalOptions_Shader' overlays = 'Dialog.GlobalOptions.TabWidget'> + <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> + <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'> + <widget name = 'grShaderPopUpDesc' + type = 'OptionsLabel' + /> + <widget name = 'grShaderPopUp' + type = 'PopUp' + /> + </layout> + </layout> + </dialog> + <dialog name = 'GlobalOptions_Audio' overlays = 'Dialog.GlobalOptions.TabWidget'> <layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'> <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'> |