diff options
Diffstat (limited to 'backends')
22 files changed, 1730 insertions, 9 deletions
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 |