diff --git a/CMakeLists.txt b/CMakeLists.txt index d0207912..3e4fe7ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,15 +4,19 @@ project(game.libretro) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) find_package(Kodi REQUIRED) -find_package(p8-platform REQUIRED) find_package(TinyXML REQUIRED) include_directories(${KODI_INCLUDE_DIR} - ${p8-platform_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src ${TINYXML_INCLUDE_DIRS}) -list(APPEND DEPLIBS ${p8-platform_LIBRARIES} ${TINYXML_LIBRARIES}) +list(APPEND DEPLIBS ${TINYXML_LIBRARIES}) + +if(WIN32) + find_package(dlfcn-win32 REQUIRED) + list(APPEND DEPLIBS ${dlfcn-win32_LIBRARIES}) + include_directories(${dlfcn-win32_INCLUDE_DIRS}) +endif() set(LIBRETRO_SOURCES src/client.cpp src/audio/AudioStream.cpp @@ -41,7 +45,6 @@ set(LIBRETRO_SOURCES src/client.cpp src/settings/LibretroSettings.cpp src/settings/Settings.cpp src/settings/SettingsGenerator.cpp - src/utils/PathUtils.cpp src/utils/Timer.cpp src/video/VideoGeometry.cpp src/video/VideoStream.cpp) @@ -80,7 +83,6 @@ set(LIBRETRO_HEADERS src/GameInfoLoader.h src/settings/SettingsGenerator.h src/settings/Settings.h src/settings/SettingsTypes.h - src/utils/PathUtils.h src/utils/Timer.h src/video/VideoGeometry.h src/video/VideoStream.h) diff --git a/Readme.md b/Readme.md index 0aa7fa95..5b493b2f 100644 --- a/Readme.md +++ b/Readme.md @@ -80,29 +80,7 @@ When developing, compiling from a git repo is more convenient than repeatedly pu ### Developing on Linux -The add-on requires several dependencies to build properly. Like Kodi's build system, you can perform a system install or a local one (demonstrated here). - -First, clone p8-platform and build per standard CMake: - -```shell -git clone https://github.com/Pulse-Eight/platform.git -cd platform -mkdir build -cd build -cmake -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_INSTALL_PREFIX=$HOME/kodi \ - .. -make -make install -``` - -The kodi-platform library was split from p8-platform. Do the same as above for this library: - -``` -git clone https://github.com/xbmc/kodi-platform.git -cd kodi-platform -... -``` +The add-on requires several dependencies to build properly. Like Kodi's build system, you can perform a system install or a local one. With these dependencies in place, the add-on can be built: diff --git a/depends/windows/dlfcn-win32/0001-dlopen_with_widechar.patch b/depends/windows/dlfcn-win32/0001-dlopen_with_widechar.patch new file mode 100644 index 00000000..d292e187 --- /dev/null +++ b/depends/windows/dlfcn-win32/0001-dlopen_with_widechar.patch @@ -0,0 +1,26 @@ +diff --git a/dlfcn.c b/dlfcn.c +index 69670d1..8d2dbc0 100644 +--- a/dlfcn.c ++++ b/dlfcn.c +@@ -264,8 +264,19 @@ void *dlopen( const char *file, int mode ) + * to UNIX's search paths (start with system folders instead of current + * folder). + */ +- hModule = LoadLibraryExA(lpFileName, NULL, +- LOAD_WITH_ALTERED_SEARCH_PATH ); ++ int wide_len = MultiByteToWideChar(CP_UTF8, 0, lpFileName, -1, 0, 0); ++ if (wide_len > 0) ++ { ++ wchar_t* lpFileNameW = (wchar_t*)malloc(wide_len * sizeof(wchar_t)); ++ MultiByteToWideChar(CP_UTF8, 0, lpFileName, -1, lpFileNameW, wide_len); ++ ++ hModule = LoadLibraryExW(lpFileNameW, NULL, ++ LOAD_WITH_ALTERED_SEARCH_PATH ); ++ ++ free(lpFileNameW); ++ } ++ else ++ hModule = 0; + + if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 ) + dwProcModsAfter = 0; diff --git a/depends/windows/dlfcn-win32/dlfcn-win32.sha256 b/depends/windows/dlfcn-win32/dlfcn-win32.sha256 new file mode 100644 index 00000000..d906474c --- /dev/null +++ b/depends/windows/dlfcn-win32/dlfcn-win32.sha256 @@ -0,0 +1 @@ +f18a412e84d8b701e61a78252411fe8c72587f52417c1ef21ca93604de1b9c55 diff --git a/depends/windows/dlfcn-win32/dlfcn-win32.txt b/depends/windows/dlfcn-win32/dlfcn-win32.txt new file mode 100644 index 00000000..6ef69af4 --- /dev/null +++ b/depends/windows/dlfcn-win32/dlfcn-win32.txt @@ -0,0 +1 @@ +dlfcn-win32 https://github.com/dlfcn-win32/dlfcn-win32/archive/v1.2.0.tar.gz diff --git a/depends/windows/dlfcn-win32/flags.txt b/depends/windows/dlfcn-win32/flags.txt new file mode 100644 index 00000000..3cb0a00e --- /dev/null +++ b/depends/windows/dlfcn-win32/flags.txt @@ -0,0 +1 @@ +-DBUILD_SHARED_LIBS=OFF diff --git a/depends/windowsstore/dlfcn-win32/0001-win10-fixed-uwp-build.patch b/depends/windowsstore/dlfcn-win32/0001-win10-fixed-uwp-build.patch new file mode 100644 index 00000000..c8ac8dc6 --- /dev/null +++ b/depends/windowsstore/dlfcn-win32/0001-win10-fixed-uwp-build.patch @@ -0,0 +1,151 @@ +From f85366b1044fff7b4ea9162c3edcd8278c3e06ff Mon Sep 17 00:00:00 2001 +From: Alwin Esch <alwin.esch@web.de> +Date: Thu, 22 Aug 2019 19:30:12 +0100 +Subject: [PATCH] [win10] fixed uwp build + +--- + dlfcn.c | 43 ++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 38 insertions(+), 5 deletions(-) + +diff --git a/dlfcn.c b/dlfcn.c +index 69670d1..2d77ca8 100644 +--- a/dlfcn.c ++++ b/dlfcn.c +@@ -19,6 +19,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#define _CRT_SECURE_NO_WARNINGS + #ifdef _DEBUG + #define _CRTDBG_MAP_ALLOC + #include <stdlib.h> +@@ -193,6 +194,7 @@ static void save_err_ptr_str( const void *ptr ) + /* Load Psapi.dll at runtime, this avoids linking caveat */ + static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ) + { ++#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) + static BOOL (WINAPI *EnumProcessModulesPtr)(HANDLE, HMODULE *, DWORD, LPDWORD); + HMODULE psapi; + +@@ -206,20 +208,26 @@ static BOOL MyEnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, + } + + return EnumProcessModulesPtr( hProcess, lphModule, cb, lpcbNeeded ); ++#else ++ return 0; ++#endif + } + + void *dlopen( const char *file, int mode ) + { +- HMODULE hModule; +- UINT uMode; ++ HMODULE hModule = NULL; ++ UINT uMode = 0; + + current_error = NULL; + + /* Do not let Windows display the critical-error-handler message box */ ++#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) + uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); ++#endif + + if( file == 0 ) + { ++#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) // what is replacement of GMH on UWP? + /* POSIX says that if the value of file is 0, a handle on a global + * symbol object must be provided. That object must be able to access + * all symbols from the original program file, and any objects loaded +@@ -234,6 +242,7 @@ void *dlopen( const char *file, int mode ) + + if( !hModule ) + save_err_ptr_str( file ); ++#endif + } + else + { +@@ -264,11 +273,29 @@ void *dlopen( const char *file, int mode ) + * to UNIX's search paths (start with system folders instead of current + * folder). + */ ++#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) ++ int result = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, lpFileName, strlen(lpFileName), NULL, 0); ++ if (result == 0) ++ return NULL; ++ ++ wchar_t* newStr = (wchar_t*)malloc(result*sizeof(wchar_t)); ++ result = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, lpFileName, strlen(lpFileName), newStr, result ); ++ if (result == 0) ++ { ++ free( newStr ); ++ return NULL; ++ } ++ ++ hModule = LoadPackagedLibrary( newStr, 0 ); ++ free( newStr ); ++ dwProcModsAfter = 0; ++#else // WINAPI_PARTITION_DESKTOP + hModule = LoadLibraryExA(lpFileName, NULL, + LOAD_WITH_ALTERED_SEARCH_PATH ); + + if( MyEnumProcessModules( hCurrentProc, NULL, 0, &dwProcModsAfter ) == 0 ) + dwProcModsAfter = 0; ++#endif + + /* If the object was loaded with RTLD_LOCAL, add it to list of local + * objects, so that its symbols cannot be retrieved even if the handle for +@@ -288,7 +315,9 @@ void *dlopen( const char *file, int mode ) + } + + /* Return to previous state of the error-mode bit flags. */ ++#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) + SetErrorMode( uMode ); ++#endif + + return (void *) hModule; + } +@@ -321,12 +350,14 @@ void *dlsym( void *handle, const char *name ) + { + FARPROC symbol; + HMODULE hCaller; +- HMODULE hModule; +- HANDLE hCurrentProc; ++ HMODULE hModule = 0; ++ HANDLE hCurrentProc = 0; + + current_error = NULL; + symbol = NULL; + hCaller = NULL; ++ ++#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) // what is replacement of GMH on UWP? + hModule = GetModuleHandle( NULL ); + hCurrentProc = GetCurrentProcess( ); + +@@ -358,6 +389,7 @@ void *dlsym( void *handle, const char *name ) + if(!hCaller) + goto end; + } ++#endif + + if( handle != RTLD_NEXT ) + { +@@ -370,7 +402,7 @@ void *dlsym( void *handle, const char *name ) + /* If the handle for the original program file is passed, also search + * in all globally loaded objects. + */ +- ++#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) + if( hModule == handle || handle == RTLD_NEXT ) + { + HMODULE *modules; +@@ -410,6 +442,7 @@ void *dlsym( void *handle, const char *name ) + } + } + } ++#endif + + end: + if( symbol == NULL ) +-- +2.19.2.windows.1 + diff --git a/depends/windowsstore/dlfcn-win32/dlfcn-win32.sha256 b/depends/windowsstore/dlfcn-win32/dlfcn-win32.sha256 new file mode 100644 index 00000000..d906474c --- /dev/null +++ b/depends/windowsstore/dlfcn-win32/dlfcn-win32.sha256 @@ -0,0 +1 @@ +f18a412e84d8b701e61a78252411fe8c72587f52417c1ef21ca93604de1b9c55 diff --git a/depends/windowsstore/dlfcn-win32/dlfcn-win32.txt b/depends/windowsstore/dlfcn-win32/dlfcn-win32.txt new file mode 100644 index 00000000..6ef69af4 --- /dev/null +++ b/depends/windowsstore/dlfcn-win32/dlfcn-win32.txt @@ -0,0 +1 @@ +dlfcn-win32 https://github.com/dlfcn-win32/dlfcn-win32/archive/v1.2.0.tar.gz diff --git a/depends/windowsstore/dlfcn-win32/flags.txt b/depends/windowsstore/dlfcn-win32/flags.txt new file mode 100644 index 00000000..3cb0a00e --- /dev/null +++ b/depends/windowsstore/dlfcn-win32/flags.txt @@ -0,0 +1 @@ +-DBUILD_SHARED_LIBS=OFF diff --git a/game.libretro/addon.xml.in b/game.libretro/addon.xml.in index 1a2eebf6..f71129fa 100644 --- a/game.libretro/addon.xml.in +++ b/game.libretro/addon.xml.in @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <addon id="game.libretro" name="Libretro Compatibility" - version="1.1.0" + version="2.0.0" provider-name="Team Kodi"> <backwards-compatibility abi="1.0.0"/> <requires>@ADDON_DEPENDS@</requires> diff --git a/src/GameInfoLoader.cpp b/src/GameInfoLoader.cpp index 7c56497e..45bb6e6a 100644 --- a/src/GameInfoLoader.cpp +++ b/src/GameInfoLoader.cpp @@ -21,19 +21,17 @@ #include "GameInfoLoader.h" #include "log/Log.h" -#include "libXBMC_addon.h" +#include <kodi/Filesystem.h> #include <stdint.h> -using namespace ADDON; using namespace LIBRETRO; #define READ_SIZE (100 * 1024) // Read from VFS 100KB at a time (if file size is unknown) #define MAX_READ_SIZE (100 * 1024 * 1024) // Read at most 100MB from VFS -CGameInfoLoader::CGameInfoLoader(const char* path, CHelper_libXBMC_addon* XBMC, bool bSupportsVFS) +CGameInfoLoader::CGameInfoLoader(const std::string& path, bool bSupportsVFS) : m_path(path), - m_xbmc(XBMC), m_bSupportsVfs(bSupportsVFS) { } @@ -43,14 +41,13 @@ bool CGameInfoLoader::Load(void) if (!m_bSupportsVfs) return false; - struct __stat64 statStruct = { }; - - bool bExists = (m_xbmc->StatFile(m_path.c_str(), &statStruct) == 0); + STAT_STRUCTURE statStruct = {0}; + bool bExists = kodi::vfs::StatFile(m_path, statStruct); // Not all VFS protocols necessarily support StatFile(), so also check if file exists if (!bExists) { - bExists = m_xbmc->FileExists(m_path.c_str(), true); + bExists = kodi::vfs::FileExists(m_path, true); if (bExists) { dsyslog("Failed to stat (but file exists): %s", m_path.c_str()); @@ -62,21 +59,21 @@ bool CGameInfoLoader::Load(void) } } - void* file = m_xbmc->OpenFile(m_path.c_str(), 0); - if (!file) + kodi::vfs::CFile file; + if (!file.OpenFile(m_path)) { esyslog("Failed to open file: %s", m_path.c_str()); return false; } - int64_t size = statStruct.st_size; + int64_t size = statStruct.size; if (size > 0) { // Size is known, read entire file at once (unless it is too big) if (size <= MAX_READ_SIZE) { m_dataBuffer.resize((size_t)size); - m_xbmc->ReadFile(file, m_dataBuffer.data(), size); + file.Read(m_dataBuffer.data(), size); } else { @@ -90,7 +87,7 @@ bool CGameInfoLoader::Load(void) // Read file in chunks unsigned int bytesRead; uint8_t buffer[READ_SIZE]; - while ((bytesRead = m_xbmc->ReadFile(file, buffer, sizeof(buffer))) > 0) + while ((bytesRead = file.Read(buffer, sizeof(buffer))) > 0) { m_dataBuffer.insert(m_dataBuffer.end(), buffer, buffer + bytesRead); diff --git a/src/GameInfoLoader.h b/src/GameInfoLoader.h index 41e9317b..180339bf 100644 --- a/src/GameInfoLoader.h +++ b/src/GameInfoLoader.h @@ -25,8 +25,6 @@ #include <string> #include <vector> -namespace ADDON { class CHelper_libXBMC_addon; } - namespace LIBRETRO { /*! @@ -39,7 +37,7 @@ namespace LIBRETRO class CGameInfoLoader { public: - CGameInfoLoader(const char* path, ADDON::CHelper_libXBMC_addon* XBMC, bool bSupportsVFS); + CGameInfoLoader(const std::string& path, bool bSupportsVFS); bool Load(void); @@ -58,7 +56,6 @@ namespace LIBRETRO private: const std::string m_path; - ADDON::CHelper_libXBMC_addon* const m_xbmc; const bool m_bSupportsVfs; std::vector<uint8_t> m_dataBuffer; }; diff --git a/src/audio/AudioStream.cpp b/src/audio/AudioStream.cpp index 70be2cb1..5211969b 100644 --- a/src/audio/AudioStream.cpp +++ b/src/audio/AudioStream.cpp @@ -21,35 +21,30 @@ #include "AudioStream.h" #include "libretro/LibretroEnvironment.h" -#include "libKODI_game.h" +#include "client.h" using namespace LIBRETRO; CAudioStream::CAudioStream() : - m_frontend(nullptr), + m_addon(nullptr), m_singleFrameAudio(this) { } -void CAudioStream::Initialize(CHelper_libKODI_game* frontend) +void CAudioStream::Initialize(CGameLibRetro* addon) { - m_frontend = frontend; + m_addon = addon; } void CAudioStream::Deinitialize() { - if (m_stream != nullptr) - { - m_frontend->CloseStream(m_stream); - m_stream = nullptr; - } - - m_frontend = nullptr; + m_stream.Close(); + m_addon = nullptr; } void CAudioStream::AddFrames_S16NE(const uint8_t* data, unsigned int size) { - if (m_frontend && m_stream == nullptr) + if (m_addon && !m_stream.IsOpen()) { static const GAME_AUDIO_CHANNEL channelMap[] = { GAME_CH_FL, GAME_CH_FR, GAME_CH_NULL }; @@ -59,17 +54,15 @@ void CAudioStream::AddFrames_S16NE(const uint8_t* data, unsigned int size) properties.audio.format = GAME_PCM_FORMAT_S16NE; properties.audio.channel_map = channelMap; - m_stream = m_frontend->OpenStream(properties); + if (m_stream.Open(properties)) + return; } - if (m_stream != nullptr) - { - game_stream_packet packet{}; + game_stream_packet packet{}; - packet.type = GAME_STREAM_AUDIO; - packet.audio.data = data; - packet.audio.size = size; + packet.type = GAME_STREAM_AUDIO; + packet.audio.data = data; + packet.audio.size = size; - m_frontend->AddStreamData(m_stream, packet); - } + m_stream.AddData(packet); } diff --git a/src/audio/AudioStream.h b/src/audio/AudioStream.h index dcfb7757..1bcc6970 100644 --- a/src/audio/AudioStream.h +++ b/src/audio/AudioStream.h @@ -21,11 +21,11 @@ #include "SingleFrameAudio.h" -#include "kodi_game_types.h" +#include <kodi/addon-instance/Game.h> #include <stdint.h> -class CHelper_libKODI_game; +class CGameLibRetro; namespace LIBRETRO { @@ -34,7 +34,7 @@ namespace LIBRETRO public: CAudioStream(); - void Initialize(CHelper_libKODI_game* frontend); + void Initialize(CGameLibRetro* addon); void Deinitialize(); void AddFrame_S16NE(int16_t left, int16_t right) { m_singleFrameAudio.AddFrame(left, right); } @@ -42,9 +42,9 @@ namespace LIBRETRO void AddFrames_S16NE(const uint8_t* data, unsigned int size); private: - CHelper_libKODI_game* m_frontend; + CGameLibRetro* m_addon; CSingleFrameAudio m_singleFrameAudio; - void* m_stream = nullptr; + kodi::addon::CInstanceGame::CStream m_stream; }; } diff --git a/src/client.cpp b/src/client.cpp index 669f9a06..7df91931 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -21,35 +21,24 @@ #include "input/ButtonMapper.h" #include "input/ControllerTopology.h" #include "input/InputManager.h" -#include "libretro/ClientBridge.h" #include "libretro/libretro.h" -#include "libretro/LibretroDLL.h" #include "libretro/LibretroEnvironment.h" #include "log/Log.h" #include "log/LogAddon.h" #include "settings/Settings.h" -#include "utils/Timer.h" #include "GameInfoLoader.h" -#include "libXBMC_addon.h" -#include "libKODI_game.h" -#include "xbmc_addon_dll.h" -#include "kodi_game_dll.h" +#include "client.h" #include <set> #include <string> #include <vector> -using namespace ADDON; using namespace LIBRETRO; #define GAME_CLIENT_NAME_UNKNOWN "Unknown libretro core" #define GAME_CLIENT_VERSION_UNKNOWN "0.0.0" -#ifndef SAFE_DELETE -#define SAFE_DELETE(x) do { delete x; x = nullptr; } while (0) -#endif - void SAFE_DELETE_GAME_INFO(std::vector<CGameInfoLoader*>& vec) { for (std::vector<CGameInfoLoader*>::iterator it = vec.begin(); it != vec.end(); ++it) @@ -57,51 +46,44 @@ void SAFE_DELETE_GAME_INFO(std::vector<CGameInfoLoader*>& vec) vec.clear(); } -namespace LIBRETRO +CGameLibRetro::CGameLibRetro() { - CHelper_libXBMC_addon* XBMC = nullptr; - CHelper_libKODI_game* FRONTEND = nullptr; - CLibretroDLL* CLIENT = nullptr; - CClientBridge* CLIENT_BRIDGE = nullptr; - std::vector<CGameInfoLoader*> GAME_INFO; - bool SUPPORTS_VFS = false; // TODO - int64_t FRAME_TIME_LAST = 0; - Timer timer; } -extern "C" +CGameLibRetro::~CGameLibRetro() { + /* TODO + m_clientBridge.AudioEnable(false); + */ -ADDON_STATUS ADDON_Create(void* callbacks, void* props) -{ - try - { - if (!callbacks || !props) - throw ADDON_STATUS_UNKNOWN; + CInputManager::Get().ClosePorts(); - AddonProps_Game* gameClientProps = static_cast<AddonProps_Game*>(props); + m_client.retro_deinit(); - if (gameClientProps->game_client_dll_path == nullptr) - throw ADDON_STATUS_UNKNOWN; + CControllerTopology::GetInstance().Clear(); - XBMC = new CHelper_libXBMC_addon; - if (!XBMC || !XBMC->RegisterMe(callbacks)) - throw ADDON_STATUS_PERMANENT_FAILURE; + CLibretroEnvironment::Get().Deinitialize(); - CLog::Get().SetPipe(new CLogAddon(XBMC)); + CLog::Get().SetType(SYS_LOG_TYPE_CONSOLE); - FRONTEND = new CHelper_libKODI_game; - if (!FRONTEND || !FRONTEND->RegisterMe(callbacks)) - throw ADDON_STATUS_PERMANENT_FAILURE; + SAFE_DELETE_GAME_INFO(m_gameInfo); +} - CLIENT = new CLibretroDLL(); - if (!CLIENT->Load(gameClientProps)) +ADDON_STATUS CGameLibRetro::Create() +{ + try + { + std::string dllPath = GameClientDllPath(); + if (dllPath.empty()) + throw ADDON_STATUS_UNKNOWN; + + if (!m_client.Load(dllPath)) { - esyslog("Failed to load %s", gameClientProps->game_client_dll_path); + esyslog("Failed to load %s", dllPath.c_str()); throw ADDON_STATUS_PERMANENT_FAILURE; } - unsigned int version = CLIENT->retro_api_version(); + unsigned int version = m_client.retro_api_version(); if (version != 1) { esyslog("Expected libretro api v1, found version %u", version); @@ -109,22 +91,21 @@ ADDON_STATUS ADDON_Create(void* callbacks, void* props) } // Environment must be initialized before calling retro_init() - CLIENT_BRIDGE = new CClientBridge; - CLibretroEnvironment::Get().Initialize(XBMC, FRONTEND, CLIENT, CLIENT_BRIDGE, gameClientProps); + CLibretroEnvironment::Get().Initialize(this, &m_client, &m_clientBridge); CButtonMapper::Get().LoadButtonMap(); CControllerTopology::GetInstance().LoadTopology(); - CLIENT->retro_init(); + m_client.retro_init(); // Log core info retro_system_info systemInfo = { }; - CLIENT->retro_get_system_info(&systemInfo); + m_client.retro_get_system_info(&systemInfo); // VFS support is derived from need_fullpath. This property means that the // libretro cores requires a valid pathname. Conversely, if need_fullpath // is false, the core can load from memory. - SUPPORTS_VFS = !systemInfo.need_fullpath; + m_supportsVFS = !systemInfo.need_fullpath; std::string libraryName = systemInfo.library_name ? systemInfo.library_name : ""; std::string libraryVersion = systemInfo.library_version ? systemInfo.library_version : ""; @@ -134,7 +115,7 @@ ADDON_STATUS ADDON_Create(void* callbacks, void* props) dsyslog("CORE: Library name: %s", libraryName.c_str()); dsyslog("CORE: Library version: %s", libraryVersion.c_str()); dsyslog("CORE: Extensions: %s", extensions.c_str()); - dsyslog("CORE: Supports VFS: %s", SUPPORTS_VFS ? "true" : "false"); + dsyslog("CORE: Supports VFS: %s", m_supportsVFS ? "true" : "false"); dsyslog("CORE: ----------------------------------"); // Reject invalid properties @@ -148,191 +129,135 @@ ADDON_STATUS ADDON_Create(void* callbacks, void* props) throw ADDON_STATUS_PERMANENT_FAILURE; } - if (gameClientProps->supports_vfs != SUPPORTS_VFS) + if (SupportsVFS() != m_supportsVFS) { - esyslog("CORE: VFS support doesn't match addon.xml: %s", gameClientProps->supports_vfs ? "true" : "false"); + esyslog("CORE: VFS support doesn't match addon.xml: %s", SupportsVFS() ? "true" : "false"); throw ADDON_STATUS_PERMANENT_FAILURE; } /* TODO // Initialize libretro's extended audio interface - CLIENT_BRIDGE->AudioEnable(true); + m_clientBridge.AudioEnable(true); */ } catch (const ADDON_STATUS& status) { - SAFE_DELETE(XBMC); - SAFE_DELETE(FRONTEND); - SAFE_DELETE(CLIENT); - SAFE_DELETE(CLIENT_BRIDGE); return status; } - return ADDON_GetStatus(); + return GetStatus(); } -void ADDON_Destroy(void) +ADDON_STATUS CGameLibRetro::GetStatus() { - /* TODO - if (CLIENT_BRIDGE) - CLIENT_BRIDGE->AudioEnable(false); - */ - - CInputManager::Get().ClosePorts(); - - if (CLIENT) - CLIENT->retro_deinit(); - - CControllerTopology::GetInstance().Clear(); - - CLibretroEnvironment::Get().Deinitialize(); - - CLog::Get().SetType(SYS_LOG_TYPE_CONSOLE); - - SAFE_DELETE(XBMC); - SAFE_DELETE(FRONTEND); - SAFE_DELETE(CLIENT); - SAFE_DELETE(CLIENT_BRIDGE); - SAFE_DELETE_GAME_INFO(GAME_INFO); -} - -ADDON_STATUS ADDON_GetStatus(void) -{ - if (!XBMC || !FRONTEND || !CLIENT || !CLIENT_BRIDGE) - return ADDON_STATUS_UNKNOWN; - if (!CSettings::Get().IsInitialized()) return ADDON_STATUS_NEED_SETTINGS; return ADDON_STATUS_OK; } -ADDON_STATUS ADDON_SetSetting(const char* settingName, const void* settingValue) +ADDON_STATUS CGameLibRetro::SetSetting(const std::string& settingName, const kodi::CSettingValue& settingValue) { - if (!settingName || !settingValue) + if (settingName == "" || settingValue.empty()) return ADDON_STATUS_UNKNOWN; CSettings::Get().SetSetting(settingName, settingValue); - CLibretroEnvironment::Get().SetSetting(settingName, static_cast<const char*>(settingValue)); + CLibretroEnvironment::Get().SetSetting(settingName, settingValue.GetString()); return ADDON_STATUS_OK; } -GAME_ERROR LoadGame(const char* url) +GAME_ERROR CGameLibRetro::LoadGame(const std::string& url) { - if (!CLIENT) - return GAME_ERROR_FAILED; - - if (url == nullptr) - return GAME_ERROR_INVALID_PARAMETERS; - // Build info loader vector - SAFE_DELETE_GAME_INFO(GAME_INFO); - GAME_INFO.push_back(new CGameInfoLoader(url, XBMC, SUPPORTS_VFS)); + SAFE_DELETE_GAME_INFO(m_gameInfo); + m_gameInfo.push_back(new CGameInfoLoader(url, m_supportsVFS)); bool bResult = false; // Try to load via memory retro_game_info gameInfo; - if (GAME_INFO[0]->Load()) + if (m_gameInfo[0]->Load()) { - GAME_INFO[0]->GetMemoryStruct(gameInfo); - bResult = CLIENT->retro_load_game(&gameInfo); + m_gameInfo[0]->GetMemoryStruct(gameInfo); + bResult = m_client.retro_load_game(&gameInfo); } if (!bResult) { // Fall back to loading via path - GAME_INFO[0]->GetPathStruct(gameInfo); - bResult = CLIENT->retro_load_game(&gameInfo); + m_gameInfo[0]->GetPathStruct(gameInfo); + bResult = m_client.retro_load_game(&gameInfo); } return bResult ? GAME_ERROR_NO_ERROR : GAME_ERROR_FAILED; } -GAME_ERROR LoadGameSpecial(SPECIAL_GAME_TYPE type, const char** urls, size_t urlCount) +GAME_ERROR CGameLibRetro::LoadGameSpecial(SPECIAL_GAME_TYPE type, const std::vector<std::string>& urls) { - if (!CLIENT) - return GAME_ERROR_FAILED; - - if (urls == nullptr || urlCount == 0) - return GAME_ERROR_INVALID_PARAMETERS; - // TODO return GAME_ERROR_FAILED; /* retro_system_info info = { }; - CLIENT->retro_get_system_info(&info); + m_client.retro_get_system_info(&info); const bool bSupportsVFS = !info.need_fullpath; // Build info loader vector - SAFE_DELETE_GAME_INFO(GAME_INFO); - for (unsigned int i = 0; i < urlCount; i++) - GAME_INFO.push_back(new CGameInfoLoader(urls[i], XBMC, bSupportsVFS)); + SAFE_DELETE_GAME_INFO(m_gameInfo); + for (const auto& url : urls) + m_gameInfo.push_back(new CGameInfoLoader(url, bSupportsVFS)); // Try to load via memory std::vector<retro_game_info> infoVec; - infoVec.resize(urlCount); + infoVec.resize(urls.size()); bool bLoadFromMemory = true; - for (unsigned int i = 0; bLoadFromMemory && i < urlCount; i++) - bLoadFromMemory &= GAME_INFO[i]->GetMemoryStruct(infoVec[i]); + for (unsigned int i = 0; bLoadFromMemory && i < urls.size(); i++) + bLoadFromMemory &= m_gameInfo[i]->GetMemoryStruct(infoVec[i]); if (bLoadFromMemory) { - if (CLIENT->retro_load_game_special(type, infoVec.data(), urlCount)) + if (m_client.retro_load_game_special(type, infoVec.data(), urls.size())) return GAME_ERROR_NO_ERROR; } // Fall back to loading by path - for (unsigned int i = 0; i < urlCount; i++) - GAME_INFO[i]->GetPathStruct(infoVec[i]); - bool result = CLIENT->retro_load_game_special(type, infoVec.data(), urlCount); + for (unsigned int i = 0; i < urls.size(); i++) + m_gameInfo[i]->GetPathStruct(infoVec[i]); + bool result = m_client.retro_load_game_special(type, infoVec.data(), urls.size()); return result ? GAME_ERROR_NO_ERROR : GAME_ERROR_FAILED; */ } -GAME_ERROR LoadStandalone(void) +GAME_ERROR CGameLibRetro::LoadStandalone() { - if (!CLIENT) - return GAME_ERROR_FAILED; - - if (!CLIENT->retro_load_game(nullptr)) + if (!m_client.retro_load_game(nullptr)) return GAME_ERROR_FAILED; return GAME_ERROR_NO_ERROR; } -GAME_ERROR UnloadGame(void) +GAME_ERROR CGameLibRetro::UnloadGame() { GAME_ERROR error = GAME_ERROR_FAILED; - if (CLIENT) - { - CLIENT->retro_unload_game(); + m_client.retro_unload_game(); - CLibretroEnvironment::Get().CloseStreams(); + CLibretroEnvironment::Get().CloseStreams(); - error = GAME_ERROR_NO_ERROR; - } + error = GAME_ERROR_NO_ERROR; - SAFE_DELETE_GAME_INFO(GAME_INFO); + SAFE_DELETE_GAME_INFO(m_gameInfo); return error; } -GAME_ERROR GetGameTiming(game_system_timing* timing_info) +GAME_ERROR CGameLibRetro::GetGameTiming(game_system_timing& timing_info) { - if (!CLIENT) - return GAME_ERROR_FAILED; - - if (timing_info == nullptr) - return GAME_ERROR_INVALID_PARAMETERS; - retro_system_av_info retro_info = { }; - CLIENT->retro_get_system_av_info(&retro_info); + m_client.retro_get_system_av_info(&retro_info); - timing_info->fps = retro_info.timing.fps; - timing_info->sample_rate = retro_info.timing.sample_rate; + timing_info.fps = retro_info.timing.fps; + timing_info.sample_rate = retro_info.timing.sample_rate; // Report info to CLibretroEnvironment CLibretroEnvironment::Get().UpdateVideoGeometry(retro_info.geometry); @@ -340,50 +265,33 @@ GAME_ERROR GetGameTiming(game_system_timing* timing_info) return GAME_ERROR_NO_ERROR; } -GAME_REGION GetRegion(void) -{ - if (!CLIENT) - return GAME_REGION_UNKNOWN; - - return CLIENT->retro_get_region() == RETRO_REGION_NTSC ? GAME_REGION_NTSC : GAME_REGION_PAL; -} - -bool RequiresGameLoop(void) +GAME_REGION CGameLibRetro::GetRegion() { - if (!CLIENT) - return false; - - return true; + return m_client.retro_get_region() == RETRO_REGION_NTSC ? GAME_REGION_NTSC : GAME_REGION_PAL; } -GAME_ERROR RunFrame(void) +GAME_ERROR CGameLibRetro::RunFrame() { - if (!CLIENT) - return GAME_ERROR_FAILED; - // Trigger the frame time callback before running the core. - uint64_t current = timer.microseconds(); + uint64_t current = m_timer.microseconds(); int64_t delta = 0; - if (FRAME_TIME_LAST > 0) - delta = current - FRAME_TIME_LAST; + if (m_frameTimeLast > 0) + delta = current - m_frameTimeLast; - FRAME_TIME_LAST = current; - CLIENT_BRIDGE->FrameTime(delta); + m_frameTimeLast = current; + m_clientBridge.FrameTime(delta); - CLIENT->retro_run(); + m_client.retro_run(); CLibretroEnvironment::Get().OnFrameEnd(); return GAME_ERROR_NO_ERROR; } -GAME_ERROR Reset(void) +GAME_ERROR CGameLibRetro::Reset() { - if (!CLIENT) - return GAME_ERROR_FAILED; - - CLIENT->retro_reset(); + m_client.retro_reset(); return GAME_ERROR_NO_ERROR; } @@ -404,68 +312,48 @@ GAME_ERROR Reset(void) * This function is not part of the Game API yet. It has been implemented * here in case a libretro core requires the extended audio interface. */ -GAME_ERROR AudioAvailable() +GAME_ERROR CGameLibRetro::AudioAvailable() { - if (!CLIENT_BRIDGE) - return GAME_ERROR_FAILED; - - return CLIENT_BRIDGE->AudioAvailable(); + return m_clientBridge.AudioAvailable(); } -GAME_ERROR HwContextReset() +GAME_ERROR CGameLibRetro::HwContextReset() { - if (!CLIENT_BRIDGE) - return GAME_ERROR_FAILED; - - return CLIENT_BRIDGE->HwContextReset(); + return m_clientBridge.HwContextReset(); } -GAME_ERROR HwContextDestroy() +GAME_ERROR CGameLibRetro::HwContextDestroy() { - if (!CLIENT_BRIDGE) - return GAME_ERROR_FAILED; - - return CLIENT_BRIDGE->HwContextDestroy(); + return m_clientBridge.HwContextDestroy(); } -bool HasFeature(const char* controller_id, const char* feature_name) +bool CGameLibRetro::HasFeature(const std::string& controller_id, const std::string& feature_name) { - if (controller_id == nullptr || feature_name == nullptr) - return false; - return CButtonMapper::Get().GetLibretroIndex(controller_id, feature_name) >= 0; } -game_input_topology* GetTopology() +game_input_topology* CGameLibRetro::GetTopology() { return CControllerTopology::GetInstance().GetTopology(); } -void FreeTopology(game_input_topology* topology) +void CGameLibRetro::FreeTopology(game_input_topology* topology) { CControllerTopology::FreeTopology(topology); } -void SetControllerLayouts(const game_controller_layout* controllers, unsigned int controller_count) +void CGameLibRetro::SetControllerLayouts(const std::vector<AddonGameControllerLayout>& controllers) { - if (controllers == nullptr) - return; - - std::vector<game_controller_layout> controllerStructs; - for (unsigned int i = 0; i < controller_count; i++) - controllerStructs.emplace_back(controllers[i]); - - CInputManager::Get().SetControllerLayouts(controllerStructs); + CInputManager::Get().SetControllerLayouts(controllers); } -bool EnableKeyboard(bool enable, const char* controller_id) +bool CGameLibRetro::EnableKeyboard(bool enable, const std::string& controller_id) { bool bSuccess = false; if (enable) { - if (controller_id != nullptr) - bSuccess = CInputManager::Get().EnableKeyboard(controller_id); + bSuccess = CInputManager::Get().EnableKeyboard(controller_id); } else { @@ -476,14 +364,13 @@ bool EnableKeyboard(bool enable, const char* controller_id) return bSuccess; } -bool EnableMouse(bool enable, const char* controller_id) +bool CGameLibRetro::EnableMouse(bool enable, const std::string& controller_id) { bool bSuccess = false; if (enable) { - if (controller_id != nullptr) - bSuccess = CInputManager::Get().EnableMouse(controller_id); + bSuccess = CInputManager::Get().EnableMouse(controller_id); } else { @@ -494,21 +381,13 @@ bool EnableMouse(bool enable, const char* controller_id) return bSuccess; } -bool ConnectController(bool connect, const char *port_address, const char* controller_id) +bool CGameLibRetro::ConnectController(bool connect, const std::string& port_address, const std::string& controller_id) { - if (port_address == nullptr) - return false; - std::string strPortAddress(port_address); std::string strController; if (connect) - { - if (controller_id == nullptr) - return false; - strController = controller_id; - } const int port = CInputManager::Get().GetPortIndex(strPortAddress); if (port < 0) @@ -531,8 +410,7 @@ bool ConnectController(bool connect, const char *port_address, const char* contr dsyslog("Setting port \"%s\" (libretro port %d) to controller \"%s\" (libretro device ID %u)", strPortAddress.c_str(), port, strController.c_str(), device); - if (CLIENT) - CLIENT->retro_set_controller_port_device(port, device); + m_client.retro_set_controller_port_device(port, device); return true; } @@ -540,80 +418,56 @@ bool ConnectController(bool connect, const char *port_address, const char* contr return false; } -bool InputEvent(const game_input_event* event) +bool CGameLibRetro::InputEvent(const game_input_event& event) { - if (!event) - return false; - - return CInputManager::Get().InputEvent(*event); + return CInputManager::Get().InputEvent(event); } -size_t SerializeSize(void) +size_t CGameLibRetro::SerializeSize() { - if (!CLIENT) - return 0; - - return CLIENT->retro_serialize_size(); + return m_client.retro_serialize_size(); } -GAME_ERROR Serialize(uint8_t* data, size_t size) +GAME_ERROR CGameLibRetro::Serialize(uint8_t* data, size_t size) { - if (!CLIENT) - return GAME_ERROR_FAILED; - if (data == nullptr) return GAME_ERROR_INVALID_PARAMETERS; - bool result = CLIENT->retro_serialize(data, size); + bool result = m_client.retro_serialize(data, size); return result ? GAME_ERROR_NO_ERROR : GAME_ERROR_FAILED; } -GAME_ERROR Deserialize(const uint8_t* data, size_t size) +GAME_ERROR CGameLibRetro::Deserialize(const uint8_t* data, size_t size) { - if (!CLIENT) - return GAME_ERROR_FAILED; - if (data == nullptr) return GAME_ERROR_INVALID_PARAMETERS; - bool result = CLIENT->retro_unserialize(data, size); + bool result = m_client.retro_unserialize(data, size); return result ? GAME_ERROR_NO_ERROR : GAME_ERROR_FAILED; } -GAME_ERROR CheatReset(void) +GAME_ERROR CGameLibRetro::CheatReset() { - if (!CLIENT) - return GAME_ERROR_FAILED; - - CLIENT->retro_cheat_reset(); + m_client.retro_cheat_reset(); return GAME_ERROR_NO_ERROR; } -GAME_ERROR GetMemory(GAME_MEMORY type, uint8_t** data, size_t* size) +GAME_ERROR CGameLibRetro::GetMemory(GAME_MEMORY type, uint8_t*& data, size_t& size) { - if (!CLIENT) - return GAME_ERROR_FAILED; - - if (data == nullptr || size == nullptr) - return GAME_ERROR_INVALID_PARAMETERS; - - *data = static_cast<uint8_t*>(CLIENT->retro_get_memory_data(type)); - *size = CLIENT->retro_get_memory_size(type); + data = static_cast<uint8_t*>(m_client.retro_get_memory_data(type)); + size = m_client.retro_get_memory_size(type); return GAME_ERROR_NO_ERROR; } -GAME_ERROR SetCheat(unsigned int index, bool enabled, const char* code) +GAME_ERROR CGameLibRetro::SetCheat(unsigned int index, bool enabled, const std::string& code) { - if (!CLIENT) - return GAME_ERROR_FAILED; - - CLIENT->retro_cheat_set(index, enabled, code); + m_client.retro_cheat_set(index, enabled, code.c_str()); return GAME_ERROR_NO_ERROR; } -} // extern "C" +ADDONCREATOR(CGameLibRetro) diff --git a/src/client.h b/src/client.h new file mode 100644 index 00000000..f47d3761 --- /dev/null +++ b/src/client.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014-2016 Team Kodi + * http://kodi.tv + * + * 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, 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; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "libretro/ClientBridge.h" +#include "libretro/LibretroDLL.h" +#include "utils/Timer.h" + +#include <kodi/addon-instance/Game.h> + +namespace LIBRETRO +{ + class CGameInfoLoader; +} + +class ATTRIBUTE_HIDDEN CGameLibRetro + : public kodi::addon::CAddonBase, + public kodi::addon::CInstanceGame +{ +public: + CGameLibRetro(); + ~CGameLibRetro() override; + + ADDON_STATUS Create() override; + ADDON_STATUS GetStatus() override; + ADDON_STATUS SetSetting(const std::string& settingName, const kodi::CSettingValue& settingValue) override; + + // --- Game operations --------------------------------------------------------- + + GAME_ERROR LoadGame(const std::string& url) override; + GAME_ERROR LoadGameSpecial(SPECIAL_GAME_TYPE type, const std::vector<std::string>& urls) override; + GAME_ERROR LoadStandalone() override; + GAME_ERROR UnloadGame() override; + GAME_ERROR GetGameTiming(game_system_timing& timing_info) override; + GAME_REGION GetRegion() override; + bool RequiresGameLoop() override { return true; } + GAME_ERROR RunFrame() override; + GAME_ERROR Reset() override; + + // --- Hardware rendering operations ------------------------------------------- + + GAME_ERROR HwContextReset() override; + GAME_ERROR HwContextDestroy() override; + + // --- Input operations -------------------------------------------------------- + + bool HasFeature(const std::string& controller_id, const std::string& feature_name) override; + game_input_topology* GetTopology() override; + void FreeTopology(game_input_topology* topology) override; + void SetControllerLayouts(const std::vector<AddonGameControllerLayout>& controllers) override; + bool EnableKeyboard(bool enable, const std::string& controller_id) override; + bool EnableMouse(bool enable, const std::string& controller_id) override; + bool ConnectController(bool connect, const std::string& port_address, const std::string& controller_id) override; + bool InputEvent(const game_input_event& event) override; + + // --- Serialization operations ------------------------------------------------ + + size_t SerializeSize() override; + GAME_ERROR Serialize(uint8_t* data, size_t size) override; + GAME_ERROR Deserialize(const uint8_t* data, size_t size) override; + + // --- Cheat operations -------------------------------------------------------- + + GAME_ERROR CheatReset() override; + GAME_ERROR GetMemory(GAME_MEMORY type, uint8_t*& data, size_t& size) override; + GAME_ERROR SetCheat(unsigned int index, bool enabled, const std::string& code) override; + +private: + GAME_ERROR AudioAvailable(); + + LIBRETRO::Timer m_timer; + LIBRETRO::CLibretroDLL m_client; + LIBRETRO::CClientBridge m_clientBridge; + std::vector<LIBRETRO::CGameInfoLoader*> m_gameInfo; + bool m_supportsVFS = false; // TODO + int64_t m_frameTimeLast = 0; +}; diff --git a/src/input/ControllerLayout.cpp b/src/input/ControllerLayout.cpp index a4f10b37..735ad488 100644 --- a/src/input/ControllerLayout.cpp +++ b/src/input/ControllerLayout.cpp @@ -20,59 +20,9 @@ #include "ControllerLayout.h" -#include "kodi_game_types.h" - using namespace LIBRETRO; -CControllerLayout::CControllerLayout(const game_controller_layout &controller) : - m_controllerId(controller.controller_id != nullptr ? controller.controller_id : ""), - m_bProvidesInput(controller.provides_input) +CControllerLayout::CControllerLayout(const AddonGameControllerLayout& controller) : + m_controller(controller) { - if (controller.digital_buttons != nullptr) - { - for (unsigned int i = 0; i < controller.digital_button_count; i++) - m_digitalButtons.emplace_back(controller.digital_buttons[i]); - } - - if (controller.analog_buttons != nullptr) - { - for (unsigned int i = 0; i < controller.analog_button_count; i++) - m_analogButtons.emplace_back(controller.analog_buttons[i]); - } - - if (controller.analog_sticks != nullptr) - { - for (unsigned int i = 0; i < controller.analog_stick_count; i++) - m_analogSticks.emplace_back(controller.analog_sticks[i]); - } - - if (controller.accelerometers != nullptr) - { - for (unsigned int i = 0; i < controller.accelerometer_count; i++) - m_accelerometers.emplace_back(controller.accelerometers[i]); - } - - if (controller.keys != nullptr) - { - for (unsigned int i = 0; i < controller.key_count; i++) - m_keys.emplace_back(controller.keys[i]); - } - - if (controller.rel_pointers != nullptr) - { - for (unsigned int i = 0; i < controller.rel_pointer_count; i++) - m_relPointers.emplace_back(controller.rel_pointers[i]); - } - - if (controller.abs_pointers != nullptr) - { - for (unsigned int i = 0; i < controller.abs_pointer_count; i++) - m_absPointers.emplace_back(controller.abs_pointers[i]); - } - - if (controller.motors != nullptr) - { - for (unsigned int i = 0; i < controller.motor_count; i++) - m_motors.emplace_back(controller.motors[i]); - } } diff --git a/src/input/ControllerLayout.h b/src/input/ControllerLayout.h index 0f886287..6b1b51aa 100644 --- a/src/input/ControllerLayout.h +++ b/src/input/ControllerLayout.h @@ -19,6 +19,8 @@ */ #pragma once +#include <kodi/addon-instance/Game.h> + #include <string> #include <vector> @@ -29,21 +31,12 @@ namespace LIBRETRO class CControllerLayout { public: - CControllerLayout(const game_controller_layout &controller); + CControllerLayout(const AddonGameControllerLayout& controller); - const std::string &ControllerID() const { return m_controllerId; } - bool ProvidesInput() const { return m_bProvidesInput; } + const std::string &ControllerID() const { return m_controller.controller_id; } + bool ProvidesInput() const { return m_controller.provides_input; } private: - std::string m_controllerId; - bool m_bProvidesInput; - std::vector<std::string> m_digitalButtons; - std::vector<std::string> m_analogButtons; - std::vector<std::string> m_analogSticks; - std::vector<std::string> m_accelerometers; - std::vector<std::string> m_keys; - std::vector<std::string> m_relPointers; - std::vector<std::string> m_absPointers; - std::vector<std::string> m_motors; + AddonGameControllerLayout m_controller; }; } diff --git a/src/input/ControllerTopology.cpp b/src/input/ControllerTopology.cpp index a27341e5..7c9eac55 100644 --- a/src/input/ControllerTopology.cpp +++ b/src/input/ControllerTopology.cpp @@ -24,7 +24,6 @@ #include "libretro/LibretroEnvironment.h" #include "log/Log.h" -#include "kodi_game_types.h" #include <tinyxml.h> #include <algorithm> diff --git a/src/input/ControllerTopology.h b/src/input/ControllerTopology.h index bd0542fb..c9b0249f 100644 --- a/src/input/ControllerTopology.h +++ b/src/input/ControllerTopology.h @@ -19,7 +19,7 @@ */ #pragma once -#include "kodi_game_types.h" +#include <kodi/addon-instance/Game.h> #include <memory> #include <string> diff --git a/src/input/InputManager.cpp b/src/input/InputManager.cpp index 656489ac..cce674de 100644 --- a/src/input/InputManager.cpp +++ b/src/input/InputManager.cpp @@ -28,13 +28,10 @@ #include "libretro/LibretroTranslator.h" #include "log/Log.h" -#include "libKODI_game.h" - #include <algorithm> #include <sstream> using namespace LIBRETRO; -using namespace P8PLATFORM; #define PORT_MAX_COUNT 32 // Large enough @@ -55,14 +52,13 @@ libretro_device_caps_t CInputManager::GetDeviceCaps(void) const } -void CInputManager::SetControllerLayouts(const std::vector<game_controller_layout> &controllers) +void CInputManager::SetControllerLayouts(const std::vector<AddonGameControllerLayout>& controllers) { m_controllerLayouts.clear(); for (const auto &controller : controllers) { - if (controller.controller_id != nullptr) - m_controllerLayouts[controller.controller_id].reset(new CControllerLayout(controller)); + m_controllerLayouts[controller.controller_id].reset(new CControllerLayout(controller)); } } diff --git a/src/input/InputManager.h b/src/input/InputManager.h index d2d090c9..34774b75 100644 --- a/src/input/InputManager.h +++ b/src/input/InputManager.h @@ -23,8 +23,8 @@ #include "ControllerLayout.h" #include "LibretroDevice.h" -#include "kodi_game_types.h" -#include "p8-platform/threads/mutex.h" +#include <kodi/addon-instance/Game.h> +#include <mutex> #include <map> #include <memory> @@ -57,7 +57,7 @@ namespace LIBRETRO /*! * \brief */ - void SetControllerLayouts(const std::vector<game_controller_layout> &controllers); + void SetControllerLayouts(const std::vector<AddonGameControllerLayout>& controllers); /*! * \brief Enable the keyboard diff --git a/src/input/InputTranslator.h b/src/input/InputTranslator.h index fb4bdcc6..d47afe9b 100644 --- a/src/input/InputTranslator.h +++ b/src/input/InputTranslator.h @@ -19,7 +19,7 @@ */ #pragma once -#include <kodi/kodi_game_types.h> +#include <kodi/addon-instance/Game.h> namespace LIBRETRO { diff --git a/src/input/LibretroDevice.h b/src/input/LibretroDevice.h index 2377fac2..9540baed 100644 --- a/src/input/LibretroDevice.h +++ b/src/input/LibretroDevice.h @@ -21,7 +21,7 @@ #include "InputTypes.h" -#include "kodi_game_types.h" +#include <kodi/addon-instance/Game.h> #include <map> #include <memory> diff --git a/src/input/LibretroDeviceInput.cpp b/src/input/LibretroDeviceInput.cpp index c121eb31..89ce8273 100644 --- a/src/input/LibretroDeviceInput.cpp +++ b/src/input/LibretroDeviceInput.cpp @@ -28,7 +28,6 @@ #include "log/Log.h" using namespace LIBRETRO; -using namespace P8PLATFORM; #define LIBRETRO_JOYPAD_BUTTON_COUNT 16 #define LIBRETRO_ANALOG_STICK_COUNT 2 @@ -136,7 +135,7 @@ int CLibretroDeviceInput::RelativePointerDeltaX(void) if (!m_relativePointers.empty()) { - CLockObject lock(m_relativePtrMutex); + std::unique_lock<std::mutex> lock(m_relativePtrMutex); deltaX = m_relativePointers[0].x; m_relativePointers[0].x = 0; @@ -151,7 +150,7 @@ int CLibretroDeviceInput::RelativePointerDeltaY(void) if (!m_relativePointers.empty()) { - CLockObject lock(m_relativePtrMutex); + std::unique_lock<std::mutex> lock(m_relativePtrMutex); deltaY = m_relativePointers[0].y; m_relativePointers[0].y = 0; @@ -285,7 +284,7 @@ bool CLibretroDeviceInput::InputEvent(const game_input_event& event) case GAME_INPUT_EVENT_RELATIVE_POINTER: if (index < (int)m_relativePointers.size()) { - CLockObject lock(m_relativePtrMutex); + std::unique_lock<std::mutex> lock(m_relativePtrMutex); m_relativePointers[index].x += event.rel_pointer.x; m_relativePointers[index].y += event.rel_pointer.y; diff --git a/src/input/LibretroDeviceInput.h b/src/input/LibretroDeviceInput.h index c164407a..a79a9a7c 100644 --- a/src/input/LibretroDeviceInput.h +++ b/src/input/LibretroDeviceInput.h @@ -19,8 +19,8 @@ */ #pragma once -#include "kodi_game_types.h" -#include "p8-platform/threads/mutex.h" +#include <kodi/addon-instance/Game.h> +#include <mutex> #include <string> #include <vector> @@ -59,6 +59,6 @@ namespace LIBRETRO std::vector<game_accelerometer_event> m_accelerometers; std::vector<game_rel_pointer_event> m_relativePointers; std::vector<game_abs_pointer_event> m_absolutePointers; - P8PLATFORM::CMutex m_relativePtrMutex; + std::mutex m_relativePtrMutex; }; } diff --git a/src/libretro/ClientBridge.h b/src/libretro/ClientBridge.h index 13269d38..4fd1c6a9 100644 --- a/src/libretro/ClientBridge.h +++ b/src/libretro/ClientBridge.h @@ -19,7 +19,7 @@ */ #pragma once -#include "kodi_game_types.h" +#include <kodi/addon-instance/Game.h> struct retro_game_info; diff --git a/src/libretro/FrontendBridge.cpp b/src/libretro/FrontendBridge.cpp index a2d70563..3fb1e841 100644 --- a/src/libretro/FrontendBridge.cpp +++ b/src/libretro/FrontendBridge.cpp @@ -23,14 +23,12 @@ #include "LibretroTranslator.h" #include "input/ButtonMapper.h" #include "input/InputManager.h" - -#include "libXBMC_addon.h" -#include "libKODI_game.h" +#include "client.h" #include <algorithm> #include <assert.h> +#include <kodi/General.h> -using namespace ADDON; using namespace LIBRETRO; #define S16NE_FRAMESIZE 4 // int16 L + int16 R @@ -44,17 +42,14 @@ using namespace LIBRETRO; void CFrontendBridge::LogFrontend(retro_log_level level, const char *fmt, ...) { - if (!CLibretroEnvironment::Get().GetXBMC()) - return; - - addon_log_t xbmcLevel; + AddonLog xbmcLevel; switch (level) { - case RETRO_LOG_DEBUG: xbmcLevel = LOG_DEBUG; break; - case RETRO_LOG_INFO: xbmcLevel = LOG_INFO; break; - case RETRO_LOG_WARN: xbmcLevel = LOG_ERROR; break; - case RETRO_LOG_ERROR: xbmcLevel = LOG_ERROR; break; - default: xbmcLevel = LOG_ERROR; break; + case RETRO_LOG_DEBUG: xbmcLevel = ADDON_LOG_DEBUG; break; + case RETRO_LOG_INFO: xbmcLevel = ADDON_LOG_INFO; break; + case RETRO_LOG_WARN: xbmcLevel = ADDON_LOG_ERROR; break; + case RETRO_LOG_ERROR: xbmcLevel = ADDON_LOG_ERROR; break; + default: xbmcLevel = ADDON_LOG_ERROR; break; } char buffer[16384]; @@ -63,7 +58,7 @@ void CFrontendBridge::LogFrontend(retro_log_level level, const char *fmt, ...) vsprintf(buffer, fmt, args); va_end(args); - CLibretroEnvironment::Get().GetXBMC()->Log(xbmcLevel, buffer); + kodi::Log(xbmcLevel, buffer); } void CFrontendBridge::VideoRefresh(const void* data, unsigned int width, unsigned int height, size_t pitch) @@ -201,7 +196,7 @@ int16_t CFrontendBridge::InputState(unsigned int port, unsigned int device, unsi uintptr_t CFrontendBridge::HwGetCurrentFramebuffer(void) { - if (!CLibretroEnvironment::Get().GetFrontend()) + if (!CLibretroEnvironment::Get().GetAddon()) return 0; return CLibretroEnvironment::Get().Video().GetHwFramebuffer(); @@ -209,15 +204,15 @@ uintptr_t CFrontendBridge::HwGetCurrentFramebuffer(void) retro_proc_address_t CFrontendBridge::HwGetProcAddress(const char *sym) { - if (!CLibretroEnvironment::Get().GetFrontend()) + if (!CLibretroEnvironment::Get().GetAddon()) return nullptr; - return CLibretroEnvironment::Get().GetFrontend()->HwGetProcAddress(sym); + return CLibretroEnvironment::Get().GetAddon()->HwGetProcAddress(sym); } bool CFrontendBridge::RumbleSetState(unsigned int port, retro_rumble_effect effect, uint16_t strength) { - if (!CLibretroEnvironment::Get().GetFrontend()) + if (!CLibretroEnvironment::Get().GetAddon()) return false; std::string controllerId = CInputManager::Get().ControllerID(port); @@ -237,7 +232,7 @@ bool CFrontendBridge::RumbleSetState(unsigned int port, retro_rumble_effect effe eventStruct.feature_name = featureName.c_str(); eventStruct.motor.magnitude = CONSTRAIN(magnitude, 0.0f, 1.0f); - CLibretroEnvironment::Get().GetFrontend()->InputEvent(eventStruct); + CLibretroEnvironment::Get().GetAddon()->KodiInputEvent(eventStruct); return true; } diff --git a/src/libretro/LibretroDLL.cpp b/src/libretro/LibretroDLL.cpp index 9271f8d6..76167f7d 100644 --- a/src/libretro/LibretroDLL.cpp +++ b/src/libretro/LibretroDLL.cpp @@ -21,18 +21,12 @@ #include "LibretroDLL.h" #include "log/Log.h" -#include "libKODI_game.h" -#include "kodi_game_types.h" +#include <kodi/addon-instance/Game.h> -#ifdef _WIN32 - #include "dlfcn-win32.h" // TODO: Use file from kodi-platform -#else - #include <dlfcn.h> -#endif +#include <dlfcn.h> #include <assert.h> -using namespace ADDON; using namespace LIBRETRO; CLibretroDLL::CLibretroDLL(void) : @@ -86,11 +80,12 @@ bool RegisterSymbol(void* dll, T& functionPtr, const char* strFunctionPtr) return (functionPtr = (T)dlsym(dll, strFunctionPtr)) != nullptr; } -bool CLibretroDLL::Load(const AddonProps_Game* gameClientProps) +bool CLibretroDLL::Load(const std::string& gameClientDllPath) { Unload(); - m_libretroClient = dlopen(gameClientProps->game_client_dll_path, RTLD_LAZY); + m_strPath = gameClientDllPath; + m_libretroClient = dlopen(m_strPath.c_str(), RTLD_LAZY); if (m_libretroClient == nullptr) { esyslog("Unable to load: %s", dlerror()); @@ -131,7 +126,5 @@ bool CLibretroDLL::Load(const AddonProps_Game* gameClientProps) return bSuccess; } - m_strPath = gameClientProps->game_client_dll_path; - return true; } diff --git a/src/libretro/LibretroDLL.h b/src/libretro/LibretroDLL.h index 743e5984..5b372aeb 100644 --- a/src/libretro/LibretroDLL.h +++ b/src/libretro/LibretroDLL.h @@ -36,7 +36,7 @@ namespace LIBRETRO ~CLibretroDLL(void) { Unload(); } void Unload(void); - bool Load(const AddonProps_Game* gameClientProps); + bool Load(const std::string& gameClientDllPath); const std::string& GetPath() const { return m_strPath; } diff --git a/src/libretro/LibretroEnvironment.cpp b/src/libretro/LibretroEnvironment.cpp index 9117dd41..c2c9eb7f 100644 --- a/src/libretro/LibretroEnvironment.cpp +++ b/src/libretro/LibretroEnvironment.cpp @@ -28,13 +28,11 @@ #include "log/Log.h" #include "settings/Settings.h" #include "video/VideoGeometry.h" +#include "client.h" -#include "libKODI_game.h" -#include "libXBMC_addon.h" +#include <kodi/General.h> -using namespace ADDON; using namespace LIBRETRO; -using namespace P8PLATFORM; namespace LIBRETRO { @@ -45,8 +43,7 @@ namespace LIBRETRO } CLibretroEnvironment::CLibretroEnvironment(void) : - m_xbmc(nullptr), - m_frontend(nullptr), + m_addon(nullptr), m_client(nullptr), m_clientBridge(nullptr), m_videoFormat(GAME_PIXEL_FORMAT_0RGB1555), // Default libretro format @@ -60,22 +57,19 @@ CLibretroEnvironment& CLibretroEnvironment::Get(void) return _instance; } -void CLibretroEnvironment::Initialize(ADDON::CHelper_libXBMC_addon* xbmc, - CHelper_libKODI_game* frontend, +void CLibretroEnvironment::Initialize(CGameLibRetro* addon, CLibretroDLL* client, - CClientBridge* clientBridge, - const AddonProps_Game* gameClientProps) + CClientBridge* clientBridge) { - m_xbmc = xbmc; - m_frontend = frontend; + m_addon = addon; m_client = client; m_clientBridge = clientBridge; - m_videoStream.Initialize(m_frontend); - m_audioStream.Initialize(m_frontend); + m_videoStream.Initialize(m_addon); + m_audioStream.Initialize(m_addon); - m_settings.Initialize(xbmc, gameClientProps); - m_resources.Initialize(xbmc, gameClientProps); + m_settings.Initialize(m_addon); + m_resources.Initialize(m_addon); // Install environment callback m_client->retro_set_environment(EnvCallback); @@ -125,7 +119,7 @@ void CLibretroEnvironment::OnFrameEnd() bool CLibretroEnvironment::EnvironmentCallback(unsigned int cmd, void *data) { - if (!m_frontend || !m_clientBridge) + if (!m_addon || !m_clientBridge) return false; switch (cmd) @@ -158,13 +152,13 @@ bool CLibretroEnvironment::EnvironmentCallback(unsigned int cmd, void *data) if (typedData) { const char* msg = typedData->msg; - m_xbmc->QueueNotification(QUEUE_INFO, msg); + kodi::QueueFormattedNotification(QUEUE_INFO, msg); } break; } case RETRO_ENVIRONMENT_SHUTDOWN: { - m_frontend->CloseGame(); + m_addon->CloseGame(); break; } case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL: @@ -290,7 +284,7 @@ bool CLibretroEnvironment::EnvironmentCallback(unsigned int cmd, void *data) { const bool bSupportsNoGame = *typedData; if (bSupportsNoGame) - m_xbmc->Log(LOG_DEBUG, "Libretro client supports loading with no game"); + kodi::Log(ADDON_LOG_DEBUG, "Libretro client supports loading with no game"); } break; } diff --git a/src/libretro/LibretroEnvironment.h b/src/libretro/LibretroEnvironment.h index 1e7347d4..de8f99e1 100644 --- a/src/libretro/LibretroEnvironment.h +++ b/src/libretro/LibretroEnvironment.h @@ -24,13 +24,12 @@ #include "settings/LibretroSettings.h" #include "video/VideoStream.h" -#include "kodi_game_types.h" +#include <kodi/addon-instance/Game.h> #include <memory> #include <string> -namespace ADDON { class CHelper_libXBMC_addon; } -class CHelper_libKODI_game; +class CGameLibRetro; struct retro_game_geometry; @@ -44,16 +43,13 @@ namespace LIBRETRO public: static CLibretroEnvironment& Get(void); - void Initialize(ADDON::CHelper_libXBMC_addon* xbmc, - CHelper_libKODI_game* frontend, + void Initialize(CGameLibRetro* addon, CLibretroDLL* client, - CClientBridge* clientBridge, - const AddonProps_Game* gameClientProps); + CClientBridge* clientBridge); void Deinitialize(void); - ADDON::CHelper_libXBMC_addon* GetXBMC(void) { return m_xbmc; } - CHelper_libKODI_game* GetFrontend(void) { return m_frontend; } + CGameLibRetro* GetAddon(void) { return m_addon; } CLibretroDLL* GetClient(void) { return m_client; } CClientBridge* GetClientBridge(void) { return m_clientBridge; } @@ -90,8 +86,7 @@ namespace LIBRETRO private: CLibretroEnvironment(void); - ADDON::CHelper_libXBMC_addon* m_xbmc; - CHelper_libKODI_game* m_frontend; + CGameLibRetro* m_addon; CLibretroDLL* m_client; CClientBridge* m_clientBridge; CVideoStream m_videoStream; diff --git a/src/libretro/LibretroResources.cpp b/src/libretro/LibretroResources.cpp index d852983d..430d26fe 100644 --- a/src/libretro/LibretroResources.cpp +++ b/src/libretro/LibretroResources.cpp @@ -21,11 +21,10 @@ #include "LibretroResources.h" #include "LibretroDefines.h" #include "log/Log.h" -#include "utils/PathUtils.h" -#include "kodi_game_types.h" -#include "libXBMC_addon.h" +#include "client.h" +#include <kodi/Filesystem.h> #include <assert.h> #include <utility> @@ -36,52 +35,42 @@ CLibretroResources::CLibretroResources() : { } -void CLibretroResources::Initialize(ADDON::CHelper_libXBMC_addon* addon, const AddonProps_Game* gameClientProps) +void CLibretroResources::Initialize(CGameLibRetro* addon) { m_addon = addon; assert(m_addon != nullptr); - for (unsigned int i = 0; i < gameClientProps->resource_directory_count; i++) + std::vector<std::string> dirs; + m_addon->ResourceDirectories(dirs); + for (const auto& dir : dirs) { - if (gameClientProps->resource_directories[i] == nullptr) - break; - - std::string resourcePath = gameClientProps->resource_directories[i]; - - PathUtils::RemoveSlashAtEnd(resourcePath); - - if (resourcePath.empty()) + if (dir.empty()) continue; // Set system path to first resource path discovered if (m_systemDirectory.empty()) { - m_systemDirectory = resourcePath + "/" LIBRETRO_SYSTEM_DIRECTORY_NAME; + m_systemDirectory = dir + "/" LIBRETRO_SYSTEM_DIRECTORY_NAME; // Ensure folder exists - if (!m_addon->DirectoryExists(m_systemDirectory.c_str())) + if (!kodi::vfs::DirectoryExists(m_systemDirectory)) { dsyslog("Creating system directory: %s", m_systemDirectory.c_str()); - m_addon->CreateDirectory(m_systemDirectory.c_str()); + kodi::vfs::CreateDirectory(m_systemDirectory); } } - m_resourceDirectories.push_back(std::move(resourcePath)); - } + m_resourceDirectories.push_back(std::move(dir)); +} - if (gameClientProps->profile_directory != nullptr) - { - m_saveDirectory = gameClientProps->profile_directory; - PathUtils::RemoveSlashAtEnd(m_saveDirectory); - m_saveDirectory += "/" LIBRETRO_SAVE_DIRECTORY_NAME; + m_saveDirectory = m_addon->ProfileDirectory() + "/" LIBRETRO_SAVE_DIRECTORY_NAME; - // Ensure folder exists - if (!m_addon->DirectoryExists(m_saveDirectory.c_str())) - { - dsyslog("Creating save directory: %s", m_saveDirectory.c_str()); - m_addon->CreateDirectory(m_saveDirectory.c_str()); - } + // Ensure folder exists + if (!kodi::vfs::DirectoryExists(m_saveDirectory)) + { + dsyslog("Creating save directory: %s", m_saveDirectory.c_str()); + kodi::vfs::CreateDirectory(m_saveDirectory); } } @@ -101,7 +90,7 @@ const char* CLibretroResources::GetBasePath(const std::string& relPath) std::string resourcePath = dir + "/" + relPath; // Check for path existence - if (m_addon->FileExists(resourcePath.c_str(), true)) + if (kodi::vfs::FileExists(resourcePath, true)) { m_pathMap.insert(std::make_pair(relPath, std::move(dir))); it = m_pathMap.find(relPath); diff --git a/src/libretro/LibretroResources.h b/src/libretro/LibretroResources.h index a997e625..5e897920 100644 --- a/src/libretro/LibretroResources.h +++ b/src/libretro/LibretroResources.h @@ -23,9 +23,7 @@ #include <string> #include <vector> -namespace ADDON { class CHelper_libXBMC_addon; } - -struct AddonProps_Game; +class CGameLibRetro; namespace LIBRETRO { @@ -35,7 +33,7 @@ namespace LIBRETRO CLibretroResources(); ~CLibretroResources() { Deinitialize(); } - void Initialize(ADDON::CHelper_libXBMC_addon* addon, const AddonProps_Game* gameClientProps); + void Initialize(CGameLibRetro* addon); void Deinitialize(); const char* GetSystemDir() const { return m_systemDirectory.c_str(); } @@ -50,8 +48,7 @@ namespace LIBRETRO private: const char* ApendSystemFolder(const std::string& path); - ADDON::CHelper_libXBMC_addon* m_addon; - + CGameLibRetro* m_addon; std::vector<std::string> m_resourceDirectories; std::map<std::string, std::string> m_pathMap; std::string m_systemDirectory; diff --git a/src/libretro/LibretroTranslator.h b/src/libretro/LibretroTranslator.h index 2802eca4..2ec60f52 100644 --- a/src/libretro/LibretroTranslator.h +++ b/src/libretro/LibretroTranslator.h @@ -22,7 +22,7 @@ #include "input/LibretroDevice.h" #include "libretro.h" -#include "kodi_game_types.h" +#include <kodi/addon-instance/Game.h> #include <string> diff --git a/src/log/Log.cpp b/src/log/Log.cpp index f8796415..7e790ce5 100644 --- a/src/log/Log.cpp +++ b/src/log/Log.cpp @@ -26,7 +26,6 @@ #include <stdio.h> using namespace LIBRETRO; -using namespace P8PLATFORM; #define SYS_LOG_BUFFER_SIZE 256 // bytes @@ -49,7 +48,7 @@ CLog::~CLog(void) bool CLog::SetType(SYS_LOG_TYPE type) { - P8PLATFORM::CLockObject lock(m_mutex); + std::unique_lock<std::mutex> lock(m_mutex); if (m_pipe && m_pipe->Type() == type) return true; // Already set @@ -72,7 +71,7 @@ bool CLog::SetType(SYS_LOG_TYPE type) void CLog::SetPipe(ILog* pipe) { - P8PLATFORM::CLockObject lock(m_mutex); + std::unique_lock<std::mutex> lock(m_mutex); delete m_pipe; m_pipe = pipe; @@ -80,7 +79,7 @@ void CLog::SetPipe(ILog* pipe) void CLog::SetLevel(SYS_LOG_LEVEL level) { - P8PLATFORM::CLockObject lock(m_mutex); + std::unique_lock<std::mutex> lock(m_mutex); m_level = level; } @@ -108,7 +107,7 @@ void CLog::Log(SYS_LOG_LEVEL level, const char* format, ...) vsnprintf(buf, SYS_LOG_BUFFER_SIZE - 1, fmt, ap); va_end(ap); - P8PLATFORM::CLockObject lock(m_mutex); + std::unique_lock<std::mutex> lock(m_mutex); if (level > m_level) return; diff --git a/src/log/Log.h b/src/log/Log.h index 429700fb..80060136 100644 --- a/src/log/Log.h +++ b/src/log/Log.h @@ -21,7 +21,7 @@ #include "ILog.h" -#include "p8-platform/threads/mutex.h" +#include <mutex> #include <string> @@ -69,6 +69,6 @@ namespace LIBRETRO ILog* m_pipe; SYS_LOG_LEVEL m_level; std::string m_strLogPrefix; - P8PLATFORM::CMutex m_mutex; + std::mutex m_mutex; }; } diff --git a/src/log/LogAddon.cpp b/src/log/LogAddon.cpp index 3f84f83a..03cbd008 100644 --- a/src/log/LogAddon.cpp +++ b/src/log/LogAddon.cpp @@ -20,7 +20,7 @@ #include "LogAddon.h" -#include "libXBMC_addon.h" +#include <kodi/General.h> #include <assert.h> @@ -28,29 +28,22 @@ using namespace LIBRETRO; // --- TranslateLogLevel() ----------------------------------------------------- -ADDON::addon_log_t TranslateLogLevel(SYS_LOG_LEVEL level) +AddonLog TranslateLogLevel(SYS_LOG_LEVEL level) { switch (level) { - case SYS_LOG_ERROR: return ADDON::LOG_ERROR; - case SYS_LOG_INFO: return ADDON::LOG_INFO; - case SYS_LOG_DEBUG: return ADDON::LOG_DEBUG; + case SYS_LOG_ERROR: return ADDON_LOG_ERROR; + case SYS_LOG_INFO: return ADDON_LOG_INFO; + case SYS_LOG_DEBUG: return ADDON_LOG_DEBUG; default: break; } - return ADDON::LOG_INFO; + return ADDON_LOG_INFO; } // -- CLogAddon ---------------------------------------------------------------- -CLogAddon::CLogAddon(ADDON::CHelper_libXBMC_addon* frontend) : - m_frontend(frontend) -{ - assert(m_frontend); -} - void CLogAddon::Log(SYS_LOG_LEVEL level, const char* logline) { - if (m_frontend) - m_frontend->Log(TranslateLogLevel(level), "%s", logline); + kodi::Log(TranslateLogLevel(level), "%s", logline); } diff --git a/src/log/LogAddon.h b/src/log/LogAddon.h index 22957390..d16b46bb 100644 --- a/src/log/LogAddon.h +++ b/src/log/LogAddon.h @@ -21,24 +21,16 @@ #include "ILog.h" -namespace ADDON -{ - class CHelper_libXBMC_addon; -} - namespace LIBRETRO { class CLogAddon : public ILog { public: - CLogAddon(ADDON::CHelper_libXBMC_addon* frontend); + CLogAddon() = default; virtual ~CLogAddon(void) { } // implementation of ILog virtual void Log(SYS_LOG_LEVEL level, const char* logline); virtual SYS_LOG_TYPE Type(void) const { return SYS_LOG_TYPE_ADDON; } - - private: - ADDON::CHelper_libXBMC_addon* const m_frontend; }; } diff --git a/src/log/LogConsole.cpp b/src/log/LogConsole.cpp index 8a8977d0..3e3f364b 100644 --- a/src/log/LogConsole.cpp +++ b/src/log/LogConsole.cpp @@ -23,11 +23,10 @@ #include <iostream> using namespace LIBRETRO; -using namespace P8PLATFORM; void CLogConsole::Log(SYS_LOG_LEVEL level, const char* logline) { - CLockObject lock(m_mutex); + std::unique_lock<std::mutex> lock(m_mutex); // TODO: Prepend current date std::cout << logline << std::endl; diff --git a/src/log/LogConsole.h b/src/log/LogConsole.h index e58a7d9f..d0fbbe31 100644 --- a/src/log/LogConsole.h +++ b/src/log/LogConsole.h @@ -21,7 +21,7 @@ #include "ILog.h" -#include "p8-platform/threads/mutex.h" +#include <mutex> namespace LIBRETRO { @@ -35,6 +35,6 @@ namespace LIBRETRO virtual SYS_LOG_TYPE Type(void) const { return SYS_LOG_TYPE_CONSOLE; } private: - P8PLATFORM::CMutex m_mutex; + std::mutex m_mutex; }; } diff --git a/src/settings/LibretroSettings.cpp b/src/settings/LibretroSettings.cpp index 75258d03..426a110b 100644 --- a/src/settings/LibretroSettings.cpp +++ b/src/settings/LibretroSettings.cpp @@ -23,17 +23,15 @@ #include "SettingsGenerator.h" #include "libretro/libretro.h" #include "log/Log.h" -#include "utils/PathUtils.h" +#include "client.h" -#include "kodi_game_types.h" -#include "libXBMC_addon.h" +#include <kodi/Filesystem.h> #include <algorithm> #include <assert.h> #include <utility> using namespace LIBRETRO; -using namespace P8PLATFORM; CLibretroSettings::CLibretroSettings() : m_addon(nullptr), @@ -42,14 +40,12 @@ CLibretroSettings::CLibretroSettings() : { } -void CLibretroSettings::Initialize(ADDON::CHelper_libXBMC_addon* addon, const AddonProps_Game* props) +void CLibretroSettings::Initialize(CGameLibRetro* addon) { m_addon = addon; - - if (props->profile_directory != nullptr) - m_profileDirectory = props->profile_directory; - assert(m_addon != nullptr); + + m_profileDirectory = m_addon->ProfileDirectory(); } void CLibretroSettings::Deinitialize() @@ -59,13 +55,13 @@ void CLibretroSettings::Deinitialize() bool CLibretroSettings::Changed() { - CLockObject lock(m_mutex); + std::unique_lock<std::mutex> lock(m_mutex); return m_bChanged; } void CLibretroSettings::SetUnchanged() { - CLockObject lock(m_mutex); + std::unique_lock<std::mutex> lock(m_mutex); m_bChanged = false; } @@ -74,7 +70,7 @@ void CLibretroSettings::SetAllSettings(const retro_variable* libretroVariables) // Keep track of whether Kodi has the correct settings bool bValid = true; - CLockObject lock(m_mutex); + std::unique_lock<std::mutex> lock(m_mutex); if (m_settings.empty()) { @@ -89,8 +85,8 @@ void CLibretroSettings::SetAllSettings(const retro_variable* libretroVariables) } // Query current value for setting from the frontend - char valueBuf[1024] = { }; - if (m_addon->GetSetting(variable->key, valueBuf)) + std::string valueBuf; + if (kodi::CheckSettingString(variable->key, valueBuf)) { if (std::find(setting.Values().begin(), setting.Values().end(), valueBuf) != setting.Values().end()) { @@ -121,7 +117,7 @@ void CLibretroSettings::SetAllSettings(const retro_variable* libretroVariables) const char* CLibretroSettings::GetCurrentValue(const std::string& settingName) { - CLockObject lock(m_mutex); + std::unique_lock<std::mutex> lock(m_mutex); auto it = m_settings.find(settingName); if (it == m_settings.end()) @@ -135,7 +131,7 @@ const char* CLibretroSettings::GetCurrentValue(const std::string& settingName) void CLibretroSettings::SetCurrentValue(const std::string& name, const std::string& value) { - CLockObject lock(m_mutex); + std::unique_lock<std::mutex> lock(m_mutex); if (m_settings.empty()) { @@ -173,17 +169,15 @@ void CLibretroSettings::GenerateSettings() std::string generatedPath = m_profileDirectory; - PathUtils::RemoveSlashAtEnd(generatedPath); - - std::string addonId = PathUtils::GetBasename(generatedPath); + std::string addonId = kodi::vfs::GetFileName(generatedPath); generatedPath += "/" SETTINGS_GENERATED_DIRECTORY_NAME; // Ensure folder exists - if (!m_addon->DirectoryExists(generatedPath.c_str())) + if (!kodi::vfs::DirectoryExists(generatedPath)) { dsyslog("Creating directory for settings and language files: %s", generatedPath.c_str()); - m_addon->CreateDirectory(generatedPath.c_str()); + kodi::vfs::CreateDirectory(generatedPath); } bool bSuccess = false; @@ -197,19 +191,19 @@ void CLibretroSettings::GenerateSettings() generatedPath += "/" SETTINGS_GENERATED_LANGUAGE_SUBDIR; // Ensure language folder exists - if (!m_addon->DirectoryExists(generatedPath.c_str())) + if (!kodi::vfs::DirectoryExists(generatedPath)) { dsyslog("Creating directory for settings and language files: %s", generatedPath.c_str()); - m_addon->CreateDirectory(generatedPath.c_str()); + kodi::vfs::CreateDirectory(generatedPath); } generatedPath += "/" SETTINGS_GENERATED_LANGUAGE_ENGLISH_SUBDIR; // Ensure English folder exists - if (!m_addon->DirectoryExists(generatedPath.c_str())) + if (!kodi::vfs::DirectoryExists(generatedPath)) { dsyslog("Creating directory for settings and language files: %s", generatedPath.c_str()); - m_addon->CreateDirectory(generatedPath.c_str()); + kodi::vfs::CreateDirectory(generatedPath); } CLanguageGenerator languageGen(addonId, generatedPath); diff --git a/src/settings/LibretroSettings.h b/src/settings/LibretroSettings.h index f0fdd205..c7751454 100644 --- a/src/settings/LibretroSettings.h +++ b/src/settings/LibretroSettings.h @@ -21,14 +21,12 @@ #include "SettingsTypes.h" -#include "p8-platform/threads/mutex.h" +#include <mutex> #include <map> #include <string> -namespace ADDON { class CHelper_libXBMC_addon; } - -struct AddonProps_Game; +class CGameLibRetro; struct retro_variable; namespace LIBRETRO @@ -38,7 +36,7 @@ namespace LIBRETRO public: CLibretroSettings(); - void Initialize(ADDON::CHelper_libXBMC_addon* addon, const AddonProps_Game* props); + void Initialize(CGameLibRetro* addon); void Deinitialize(); bool Changed(); @@ -57,13 +55,13 @@ namespace LIBRETRO void GenerateSettings(); // Frontend variables - ADDON::CHelper_libXBMC_addon* m_addon; + CGameLibRetro* m_addon; std::string m_profileDirectory; // Settings variables LibretroSettings m_settings; bool m_bChanged; bool m_bGenerated; // True if settings and language files have been generated - P8PLATFORM::CMutex m_mutex; + std::mutex m_mutex; }; } // namespace LIBRETRO diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index 15522f77..9793efa8 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -36,11 +36,11 @@ CSettings& CSettings::Get(void) return _instance; } -void CSettings::SetSetting(const std::string& strName, const void* value) +void CSettings::SetSetting(const std::string& strName, const kodi::CSettingValue& value) { if (strName == SETTING_CROP_OVERSCAN) { - m_bCropOverscan = *static_cast<const bool*>(value); + m_bCropOverscan = value.GetBoolean(); //dsyslog("Setting \"%s\" set to %f", SETTING_CROP_OVERSCAN, m_bCropOverscan ? "true" : "false"); } diff --git a/src/settings/Settings.h b/src/settings/Settings.h index a55e049d..0d9d4949 100644 --- a/src/settings/Settings.h +++ b/src/settings/Settings.h @@ -19,6 +19,7 @@ */ #pragma once +#include <kodi/AddonBase.h> #include <string> namespace LIBRETRO @@ -33,7 +34,7 @@ namespace LIBRETRO bool IsInitialized(void) const { return m_bInitialized; } - void SetSetting(const std::string& strName, const void* value); + void SetSetting(const std::string& strName, const kodi::CSettingValue& value); /*! * \brief True if the libretro core should crop overscan diff --git a/src/utils/PathUtils.cpp b/src/utils/PathUtils.cpp deleted file mode 100644 index cf92d805..00000000 --- a/src/utils/PathUtils.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2014-2016 Team Kodi - * http://kodi.tv - * - * 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, 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; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "PathUtils.h" - -#include <string.h> - -using namespace LIBRETRO; - -void PathUtils::RemoveSlashAtEnd(std::string& path) -{ - if (!path.empty()) - { - char last = path[path.size() - 1]; - if (last == '/' || last == '\\') - path.erase(path.size() - 1); - } -} - -std::string PathUtils::GetBasename(const std::string& path) -{ - char last = path[path.size() - 1]; - if (last == '/' || last == '\\') - return ""; - - const char* s = strrchr(const_cast<char*>(path.c_str()), '/'); - if (s == nullptr) - return path; - - s++; - - return s; -} diff --git a/src/utils/PathUtils.h b/src/utils/PathUtils.h deleted file mode 100644 index 71a3797d..00000000 --- a/src/utils/PathUtils.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2016 Team Kodi - * http://kodi.tv - * - * 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, 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; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/>. - * - */ -#pragma once - -#include <string> - -namespace LIBRETRO -{ - class PathUtils - { - public: - /*! - * \brief Remove the slash at the end of a path - * - * NOTE: Trailing slash causes some libretro cores to fail - */ - static void RemoveSlashAtEnd(std::string& path); - - /*! - * \brief Get the base filename, or empty if path ends in a / or \ - */ - static std::string GetBasename(const std::string& path); - }; -} diff --git a/src/video/VideoStream.cpp b/src/video/VideoStream.cpp index 6e8d8d59..77d60588 100644 --- a/src/video/VideoStream.cpp +++ b/src/video/VideoStream.cpp @@ -22,35 +22,35 @@ #include "VideoGeometry.h" #include "libretro/LibretroEnvironment.h" -#include "libKODI_game.h" +#include "client.h" using namespace LIBRETRO; CVideoStream::CVideoStream() : - m_frontend(nullptr), + m_addon(nullptr), m_geometry(new CVideoGeometry) { } -void CVideoStream::Initialize(CHelper_libKODI_game* frontend) +void CVideoStream::Initialize(CGameLibRetro* addon) { - m_frontend = frontend; + m_addon = addon; } void CVideoStream::Deinitialize() { - if (m_frontend == nullptr) + if (m_addon == nullptr) return; CloseStream(); - m_frontend = nullptr; + m_addon = nullptr; } void CVideoStream::SetGeometry(const CVideoGeometry &geometry) { // Close stream so it can be reopened with the updated geometry - if (m_frontend != nullptr) + if (m_addon != nullptr) CloseStream(); *m_geometry = geometry; @@ -58,7 +58,7 @@ void CVideoStream::SetGeometry(const CVideoGeometry &geometry) void CVideoStream::EnableHardwareRendering(const game_stream_hw_framebuffer_properties &properties) { - if (m_frontend == nullptr) + if (m_addon == nullptr) return; CloseStream(); @@ -68,23 +68,23 @@ void CVideoStream::EnableHardwareRendering(const game_stream_hw_framebuffer_prop streamProps.type = GAME_STREAM_HW_FRAMEBUFFER; streamProps.hw_framebuffer = properties; - m_stream = m_frontend->OpenStream(streamProps); + m_stream.Open(streamProps); m_streamType = GAME_STREAM_HW_FRAMEBUFFER; } uintptr_t CVideoStream::GetHwFramebuffer() { - if (m_frontend == nullptr) + if (m_addon == nullptr) return 0; - if (m_stream == nullptr || m_streamType != GAME_STREAM_HW_FRAMEBUFFER) + if (!m_stream.IsOpen() || m_streamType != GAME_STREAM_HW_FRAMEBUFFER) return 0; if (!m_framebuffer) { m_framebuffer.reset(new game_stream_buffer{}); - if (!m_frontend->GetStreamBuffer(m_stream, 0, 0, *m_framebuffer)) + if (!m_stream.GetBuffer(0, 0, *m_framebuffer)) return 0; } @@ -93,10 +93,10 @@ uintptr_t CVideoStream::GetHwFramebuffer() bool CVideoStream::GetSwFramebuffer(unsigned int width, unsigned int height, GAME_PIXEL_FORMAT requestedFormat, game_stream_sw_framebuffer_buffer &framebuffer) { - if (m_frontend == nullptr) + if (m_addon == nullptr) return false; - if (m_stream == nullptr) + if (!m_stream.IsOpen()) { game_stream_properties properties{}; @@ -108,18 +108,18 @@ bool CVideoStream::GetSwFramebuffer(unsigned int width, unsigned int height, GAM properties.sw_framebuffer.max_height = m_geometry->MaxHeight(); properties.sw_framebuffer.aspect_ratio = m_geometry->AspectRatio(); - m_stream = m_frontend->OpenStream(properties); + m_stream.Open(properties); m_streamType = GAME_STREAM_SW_FRAMEBUFFER; } - if (m_stream == nullptr || m_streamType != GAME_STREAM_SW_FRAMEBUFFER) + if (!m_stream.IsOpen() || m_streamType != GAME_STREAM_SW_FRAMEBUFFER) return false; if (!m_framebuffer) { m_framebuffer.reset(new game_stream_buffer{}); - if (!m_frontend->GetStreamBuffer(m_stream, width, height, *m_framebuffer)) + if (!m_stream.GetBuffer(width, height, *m_framebuffer)) return false; } @@ -130,7 +130,7 @@ bool CVideoStream::GetSwFramebuffer(unsigned int width, unsigned int height, GAM void CVideoStream::AddFrame(const uint8_t* data, unsigned int size, unsigned int width, unsigned int height, GAME_PIXEL_FORMAT format, GAME_VIDEO_ROTATION rotation) { - if (m_frontend == nullptr) + if (m_addon == nullptr) return; // Only care if format changes for video stream @@ -143,7 +143,7 @@ void CVideoStream::AddFrame(const uint8_t* data, unsigned int size, unsigned int } } - if (m_stream == nullptr) + if (!m_stream.IsOpen()) { game_stream_properties properties{}; @@ -155,14 +155,14 @@ void CVideoStream::AddFrame(const uint8_t* data, unsigned int size, unsigned int properties.video.max_height = m_geometry->MaxHeight(); properties.video.aspect_ratio = m_geometry->AspectRatio(); - m_stream = m_frontend->OpenStream(properties); + m_stream.Open(properties); m_streamType = GAME_STREAM_VIDEO; // Save format to detect unwanted changes m_format = format; } - if (m_stream == nullptr) + if (!m_stream.IsOpen()) return; game_stream_packet packet{}; @@ -193,15 +193,15 @@ void CVideoStream::AddFrame(const uint8_t* data, unsigned int size, unsigned int return; } - m_frontend->AddStreamData(m_stream, packet); + m_stream.AddData(packet); } void CVideoStream::RenderHwFrame() { - if (m_frontend == nullptr) + if (m_addon == nullptr) return; - if (m_stream == nullptr || m_streamType != GAME_STREAM_HW_FRAMEBUFFER) + if (!m_stream.IsOpen() || m_streamType != GAME_STREAM_HW_FRAMEBUFFER) return; if (!m_framebuffer) @@ -212,30 +212,29 @@ void CVideoStream::RenderHwFrame() packet.type = GAME_STREAM_HW_FRAMEBUFFER; packet.hw_framebuffer.framebuffer = m_framebuffer->hw_framebuffer.framebuffer; - m_frontend->AddStreamData(m_stream, packet); + m_stream.AddData(packet); } void CVideoStream::OnFrameEnd() { - if (m_frontend == nullptr) + if (m_addon == nullptr) return; - if (m_stream == nullptr) + if (!m_stream.IsOpen()) return; if (!m_framebuffer) return; - m_frontend->ReleaseStreamBuffer(m_stream, *m_framebuffer); + m_stream.ReleaseBuffer(*m_framebuffer); m_framebuffer.reset(); } void CVideoStream::CloseStream() { - if (m_stream != nullptr) + if (m_stream.IsOpen()) { - m_frontend->CloseStream(m_stream); - m_stream = nullptr; + m_stream.Close(); m_format = GAME_PIXEL_FORMAT_UNKNOWN; } } diff --git a/src/video/VideoStream.h b/src/video/VideoStream.h index 3ecfd383..b878be50 100644 --- a/src/video/VideoStream.h +++ b/src/video/VideoStream.h @@ -19,12 +19,12 @@ */ #pragma once -#include "kodi_game_types.h" +#include <kodi/addon-instance/Game.h> #include <memory> #include <stdint.h> -class CHelper_libKODI_game; +class CGameLibRetro; namespace LIBRETRO { @@ -35,7 +35,7 @@ namespace LIBRETRO public: CVideoStream(); - void Initialize(CHelper_libKODI_game* frontend); + void Initialize(CGameLibRetro* addon); void Deinitialize(); void SetGeometry(const CVideoGeometry &geometry); @@ -55,10 +55,10 @@ namespace LIBRETRO void CloseStream(); // Initialization parameters - CHelper_libKODI_game* m_frontend; + CGameLibRetro* m_addon; // Stream properties - void *m_stream = nullptr; + kodi::addon::CInstanceGame::CStream m_stream; std::unique_ptr<CVideoGeometry> m_geometry; GAME_STREAM_TYPE m_streamType = GAME_STREAM_UNKNOWN; GAME_PIXEL_FORMAT m_format = GAME_PIXEL_FORMAT_UNKNOWN; // Guard against libretro changing formats