diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index efe804b0c..c71d9e075 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -156,6 +156,9 @@ const std::string FileData::getROMDirectory() { #if defined(__ANDROID__) return AndroidVariables::sROMDirectory; +#elif defined(__IOS__) + std::string dir {Utils::FileSystem::getHomePath() + "/Documents/ROMs"}; + return dir; #endif const std::string& romDirSetting {Settings::getInstance()->getString("ROMDirectory")}; @@ -187,6 +190,10 @@ const std::string FileData::getROMDirectory() const std::string FileData::getMediaDirectory() { +#if defined(__IOS__) + return Utils::FileSystem::getAppDataDirectory() + "/downloaded_media/"; +#endif + const std::string& mediaDirSetting {Settings::getInstance()->getString("MediaDirectory")}; std::string mediaDirPath; diff --git a/es-app/src/PDFViewer.cpp b/es-app/src/PDFViewer.cpp index 9d52d77e7..fc09de4d7 100644 --- a/es-app/src/PDFViewer.cpp +++ b/es-app/src/PDFViewer.cpp @@ -21,7 +21,7 @@ #include #endif -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) #include "ConvertPDF.h" #endif @@ -56,7 +56,7 @@ bool PDFViewer::startPDFViewer(FileData* game) { ViewController::getInstance()->pauseViewVideos(); -#if !defined(__ANDROID__) +#if !defined(__ANDROID__) && !defined(__IOS__) #if defined(_WIN64) const std::string convertBinary {"/es-pdf-converter/es-pdf-convert.exe"}; #else @@ -305,7 +305,7 @@ bool PDFViewer::getDocumentInfo() // Close process and thread handles. CloseHandle(pi.hProcess); CloseHandle(pi.hThread); -#elif defined(__ANDROID__) +#elif defined(__ANDROID__) || defined(__IOS__) if (ConvertPDF::processFile(mManualPath, "-fileinfo", 0, 0, 0, commandOutput) == -1) return false; #else @@ -449,7 +449,7 @@ void PDFViewer::convertPage(int pageNum) CloseHandle(childStdoutRead); WaitForSingleObject(pi.hThread, INFINITE); WaitForSingleObject(pi.hProcess, INFINITE); -#elif (__ANDROID__) +#elif (__ANDROID__) || defined(__IOS__) ConvertPDF::processFile(mManualPath, "-convert", pageNum, static_cast(mPages[pageNum].width), static_cast(mPages[pageNum].height), imageData); @@ -478,7 +478,7 @@ void PDFViewer::convertPage(int pageNum) #if defined(_WIN64) if (!processReturnValue || (static_cast(imageDataSize) < mPages[pageNum].width * mPages[pageNum].height * 4)) { -#elif defined(__ANDROID__) +#elif defined(__ANDROID__) || defined(__IOS__) if (static_cast(imageDataSize) < mPages[pageNum].width * mPages[pageNum].height * 4) { #else if (returnValue != 0 || (static_cast(imageDataSize) < diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index db5e89b5b..79bb92d51 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -44,6 +44,10 @@ #include "utils/PlatformUtilAndroid.h" #endif +#if defined(__IOS__) +#include "InputOverlay.h" +#endif + #include #include @@ -1332,7 +1336,7 @@ void GuiMenu::openInputDeviceOptions() } }); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) // Touch overlay size. auto touchOverlaySize = std::make_shared>( getHelpStyle(), _("TOUCH OVERLAY SIZE"), false); @@ -1585,6 +1589,7 @@ void GuiMenu::openOtherOptions() std::bind([this] { mWindow->pushGui(new GuiAlternativeEmulators); })); s->addRow(alternativeEmulatorsRow); +#if !defined(__IOS__) // Game media directory. ComponentListRow rowMediaDir; auto mediaDirectory = std::make_shared( @@ -1626,6 +1631,7 @@ void GuiMenu::openOtherOptions() } }); s->addRow(rowMediaDir); +#endif // Maximum VRAM. auto maxVram = std::make_shared(128.0f, 2048.0f, 16.0f, "MiB"); @@ -1663,6 +1669,7 @@ void GuiMenu::openOtherOptions() }); #endif +#if !defined(__IOS__) // Display/monitor. auto displayIndex = std::make_shared>( getHelpStyle(), _("DISPLAY/MONITOR INDEX"), false); @@ -1683,6 +1690,7 @@ void GuiMenu::openOtherOptions() s->setNeedsSaving(); } }); +#endif // Screen contents rotation. auto screenRotate = std::make_shared>( @@ -1918,6 +1926,7 @@ void GuiMenu::openOtherOptions() } }); +#if !defined(__IOS__) // Custom event scripts, fired using Scripting::fireEvent(). auto customEventScripts = std::make_shared(); customEventScripts->setState(Settings::getInstance()->getBool("CustomEventScripts")); @@ -1929,6 +1938,7 @@ void GuiMenu::openOtherOptions() s->setNeedsSaving(); } }); +#endif // Only show games included in the gamelist.xml files. auto parseGamelistOnly = std::make_shared(); diff --git a/es-app/src/guis/GuiThemeDownloader.cpp b/es-app/src/guis/GuiThemeDownloader.cpp index d6f6b6797..b31fe0e32 100644 --- a/es-app/src/guis/GuiThemeDownloader.cpp +++ b/es-app/src/guis/GuiThemeDownloader.cpp @@ -166,7 +166,7 @@ GuiThemeDownloader::GuiThemeDownloader(std::function updateCallback) git_libgit2_init(); -#if defined(__ANDROID__) && defined(USE_BUNDLED_CERTIFICATES) +#if (defined(__ANDROID__) || defined(__IOS__)) && defined(USE_BUNDLED_CERTIFICATES) git_libgit2_opts( GIT_OPT_SET_SSL_CERT_LOCATIONS, ResourceManager::getInstance().getResourcePath(":/certificates/curl-ca-bundle.crt").c_str(), @@ -178,7 +178,7 @@ GuiThemeDownloader::GuiThemeDownloader(std::function updateCallback) std::promise().swap(mPromise); mFuture = mPromise.get_future(); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) mThemeDirectory = Utils::FileSystem::getInternalAppDataDirectory() + "/themes"; #else const std::string defaultUserThemeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"}; diff --git a/es-app/src/main.cpp b/es-app/src/main.cpp index 28e27f5cb..88ac66d7e 100644 --- a/es-app/src/main.cpp +++ b/es-app/src/main.cpp @@ -35,9 +35,13 @@ #include "views/ViewController.h" #include -#include #include +// TODO: Not needed after moving to SDL3. +#if !defined(__IOS__) +#include +#endif + #if defined(__ANDROID__) #include "utils/PlatformUtilAndroid.h" #endif @@ -570,7 +574,7 @@ int main(int argc, char* argv[]) SDL_SetHint(SDL_HINT_APP_NAME, "ES-DE"); -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(__IOS__) // This is a workaround to disable the incredibly annoying save state functionality in // macOS which forces a restore of the previous window state. The problem is that this // removes the splash screen on startup and it may have other adverse effects as well. @@ -598,7 +602,7 @@ int main(int argc, char* argv[]) outputToConsole(); #endif -#if !defined(__ANDROID__) +#if !defined(__ANDROID__) && !defined(__IOS__) { std::vector arguments; for (int i {0}; i < argc; ++i) @@ -871,7 +875,7 @@ int main(int argc, char* argv[]) } { -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) const std::string themeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"}; if (!Utils::FileSystem::exists(themeDir)) { LOG(LogInfo) << "Creating themes directory \"" << themeDir << "\"..."; @@ -881,6 +885,7 @@ int main(int argc, char* argv[]) LOG(LogWarning) << "Couldn't create directory, permission problems?"; } } +#if defined(__ANDROID__) if (!Utils::FileSystem::exists(themeDir + "/.nomedia")) { LOG(LogInfo) << "Creating \"no media\" file \"" << themeDir + "/.nomedia" << "\"..."; Utils::FileSystem::createEmptyFile(themeDir + "/.nomedia"); @@ -888,6 +893,7 @@ int main(int argc, char* argv[]) LOG(LogWarning) << "Couldn't create file, permission problems?"; } } +#endif #else // Create the themes folder in the application data directory (or elsewhere if the // UserThemeDirectory setting has been defined). @@ -932,6 +938,7 @@ int main(int argc, char* argv[]) #endif } +#if !defined(__IOS__) { // Create the scripts folder in the application data directory. This is only required // for custom event scripts so it's also created as a convenience. @@ -949,6 +956,7 @@ int main(int argc, char* argv[]) } } } +#endif { // Create the screensavers and screensavers/custom_slideshow directories. @@ -1064,9 +1072,11 @@ int main(int argc, char* argv[]) return 1; } -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) InputOverlay::getInstance().init(); +#endif +#if defined(__ANDROID__) LOG(LogDebug) << "Android API level: " << SDL_GetAndroidSDKVersion(); Utils::Platform::Android::printDeviceInfo(); int storageState {SDL_AndroidGetExternalStorageState()}; @@ -1313,5 +1323,9 @@ int main(int argc, char* argv[]) FreeConsole(); #endif +#if defined(__IOS__) + exit(0); +#endif + return 0; } diff --git a/es-app/src/scrapers/ScreenScraper.h b/es-app/src/scrapers/ScreenScraper.h index 708696cb0..0df888bb8 100644 --- a/es-app/src/scrapers/ScreenScraper.h +++ b/es-app/src/scrapers/ScreenScraper.h @@ -67,6 +67,8 @@ public: const std::string platformIdentifier {" P"}; #elif defined(__linux__) const std::string platformIdentifier {" L"}; +#elif defined(__IOS__) + const std::string platformIdentifier {" I"}; #elif defined(__APPLE__) const std::string platformIdentifier {" M"}; #elif defined(_WIN64) diff --git a/es-app/src/views/ViewController.cpp b/es-app/src/views/ViewController.cpp index fde4a2810..d4953b3c7 100644 --- a/es-app/src/views/ViewController.cpp +++ b/es-app/src/views/ViewController.cpp @@ -266,7 +266,7 @@ void ViewController::invalidSystemsFileDialog() void ViewController::noGamesDialog() { -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) mNoGamesErrorMessage = _("NO GAME FILES WERE FOUND, PLEASE PLACE YOUR GAMES IN " "THE CONFIGURED ROM DIRECTORY. OPTIONALLY THE ROM " "DIRECTORY STRUCTURE CAN BE GENERATED WHICH WILL " @@ -289,7 +289,7 @@ void ViewController::noGamesDialog() mRomDirectory = FileData::getROMDirectory(); #endif -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) mNoGamesMessageBox = new GuiMsgBox( HelpStyle(), mNoGamesErrorMessage + mRomDirectory, #else @@ -404,7 +404,7 @@ void ViewController::noGamesDialog() quit.type = SDL_QUIT; SDL_PushEvent(&quit); }, -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) "", nullptr, nullptr, true, false, (mRenderer->getIsVerticalOrientation() ? 0.90f : diff --git a/es-core/src/InputManager.cpp b/es-core/src/InputManager.cpp index e528aa1d0..22e5c98a8 100644 --- a/es-core/src/InputManager.cpp +++ b/es-core/src/InputManager.cpp @@ -30,6 +30,10 @@ #include "utils/PlatformUtilAndroid.h" #endif +#if defined(__IOS__) +#define TOUCH_GUID_STRING "-3" +#endif + namespace { int SDL_USER_CECBUTTONDOWN {-1}; @@ -38,7 +42,7 @@ namespace InputManager::InputManager() noexcept : mWindow {Window::getInstance()} -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) , mInputOverlay {InputOverlay::getInstance()} #endif , mKeyboardInputConfig {nullptr} @@ -92,7 +96,7 @@ void InputManager::init() LOG(LogInfo) << "Added keyboard with default configuration"; } -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) mTouchInputConfig = std::make_unique(DEVICE_TOUCH, "Touch", TOUCH_GUID_STRING); loadTouchConfig(); #endif @@ -301,7 +305,7 @@ int InputManager::getNumConfiguredDevices() if (mKeyboardInputConfig->isConfigured()) ++num; -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) if (mTouchInputConfig->isConfigured()) ++num; #endif @@ -335,7 +339,7 @@ std::string InputManager::getDeviceGUIDString(int deviceId) { if (deviceId == DEVICE_KEYBOARD) return KEYBOARD_GUID_STRING; -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) else if (deviceId == DEVICE_TOUCH) return TOUCH_GUID_STRING; #endif @@ -358,7 +362,7 @@ InputConfig* InputManager::getInputConfigByDevice(int device) { if (device == DEVICE_KEYBOARD) return mKeyboardInputConfig.get(); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) else if (device == DEVICE_TOUCH) return mTouchInputConfig.get(); #endif @@ -542,7 +546,7 @@ bool InputManager::parseEvent(const SDL_Event& event) Input(DEVICE_KEYBOARD, TYPE_KEY, event.key.keysym.sym, 0, false)); return true; } -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) case SDL_FINGERDOWN: { if (!Settings::getInstance()->getBool("InputTouchOverlay")) return false; @@ -736,7 +740,7 @@ void InputManager::loadDefaultControllerConfig(SDL_JoystickID deviceIndex) void InputManager::loadTouchConfig() { -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) InputConfig* cfg {mTouchInputConfig.get()}; if (cfg->isConfigured()) diff --git a/es-core/src/InputManager.h b/es-core/src/InputManager.h index cba5d53c4..8b10ce2b8 100644 --- a/es-core/src/InputManager.h +++ b/es-core/src/InputManager.h @@ -13,7 +13,7 @@ #include "CECInput.h" -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) #include "InputOverlay.h" #endif @@ -68,7 +68,7 @@ private: Window* mWindow; CECInput mCECInput; -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) InputOverlay& mInputOverlay; #endif diff --git a/es-core/src/Scripting.cpp b/es-core/src/Scripting.cpp index 4d6be41a9..300ef6312 100644 --- a/es-core/src/Scripting.cpp +++ b/es-core/src/Scripting.cpp @@ -30,6 +30,9 @@ namespace Scripting const std::string& arg3, const std::string& arg4) { +#if defined(__IOS__) + return; +#endif if (!Settings::getInstance()->getBool("CustomEventScripts")) return; diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index ced874ceb..93040b133 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -245,7 +245,7 @@ void Settings::setDefaults() // Input device settings. mStringMap["InputControllerType"] = {"xbox", "xbox"}; -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) mStringMap["InputTouchOverlaySize"] = {"medium", "medium"}; mStringMap["InputTouchOverlayOpacity"] = {"normal", "normal"}; mIntMap["InputTouchOverlayFadeTime"] = {6, 6}; @@ -263,7 +263,9 @@ void Settings::setDefaults() mBoolMap["FavStarCustom"] = {false, false}; // Other settings. +#if !defined(__IOS__) mStringMap["MediaDirectory"] = {"", ""}; +#endif #if defined(STEAM_DECK) || defined(RETRODECK) mIntMap["MaxVRAM"] = {512, 512}; #elif defined(RASPBERRY_PI) @@ -274,7 +276,9 @@ void Settings::setDefaults() #if !defined(USE_OPENGLES) mIntMap["AntiAliasing"] = {0, 0}; #endif +#if !defined(__IOS__) mIntMap["DisplayIndex"] = {1, 1}; +#endif mIntMap["ScreenRotate"] = {0, 0}; #if defined(__APPLE__) mStringMap["KeyboardQuitShortcut"] = {"CmdQ", "CmdQ"}; @@ -304,7 +308,9 @@ void Settings::setDefaults() mBoolMap["AlternativeEmulatorPerGame"] = {true, true}; mBoolMap["ShowHiddenFiles"] = {true, true}; mBoolMap["ShowHiddenGames"] = {true, true}; +#if !defined(__IOS__) mBoolMap["CustomEventScripts"] = {false, false}; +#endif mBoolMap["ParseGamelistOnly"] = {false, false}; mBoolMap["MAMENameStripExtraInfo"] = {true, true}; #if defined(__unix__) && !defined(__ANDROID__) @@ -351,11 +357,11 @@ void Settings::setDefaults() mBoolMap["LegacyGamelistFileLocation"] = {false, false}; mBoolMap["CreatePlaceholderSystemDirectories"] = {false, false}; mStringMap["OpenGLVersion"] = {"", ""}; -#if !defined(__ANDROID__) +#if !defined(__ANDROID__) && !defined(__IOS__) mStringMap["ROMDirectory"] = {"", ""}; #endif mStringMap["UIMode_passkey"] = {"uuddlrlrba", "uuddlrlrba"}; -#if !defined(__ANDROID__) +#if !defined(__ANDROID__) && !defined(__IOS__) mStringMap["UserThemeDirectory"] = {"", ""}; #endif mIntMap["LottieMaxFileCache"] = {150, 150}; diff --git a/es-core/src/ThemeData.cpp b/es-core/src/ThemeData.cpp index a6dd56e8e..d2bb50db5 100644 --- a/es-core/src/ThemeData.cpp +++ b/es-core/src/ThemeData.cpp @@ -21,6 +21,10 @@ #include #include +#if defined(__IOS__) +#include "utils/PlatformUtilIOS.h" +#endif + // clang-format off std::vector ThemeData::sSupportedViews { {"all"}, @@ -770,6 +774,8 @@ void ThemeData::populateThemes() #if defined(__ANDROID__) const std::string userThemeDirectory {Utils::FileSystem::getInternalAppDataDirectory() + "/themes"}; +#elif defined(__IOS__) + const std::string userThemeDirectory; #else const std::string defaultUserThemeDir {Utils::FileSystem::getAppDataDirectory() + "/themes"}; const std::string userThemeDirSetting {Utils::FileSystem::expandHomePath( @@ -801,6 +807,10 @@ void ThemeData::populateThemes() const std::vector themePaths {Utils::FileSystem::getProgramDataPath() + "/themes", Utils::FileSystem::getAppDataDirectory() + "/themes", userThemeDirectory}; +#elif defined(__IOS__) + const std::vector themePaths {Utils::Platform::iOS::getPackagePath() + "themes", + Utils::FileSystem::getAppDataDirectory() + + "/themes"}; #elif defined(__APPLE__) const std::vector themePaths { Utils::FileSystem::getExePath() + "/themes", diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index 11dc0540e..fdba4678a 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -19,7 +19,7 @@ #include "resources/Font.h" #include "utils/LocalizationUtil.h" -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) #include "InputOverlay.h" #endif @@ -436,7 +436,7 @@ void Window::update(int deltaTime) if (mScreensaver && mRenderScreensaver) mScreensaver->update(deltaTime); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) if (Settings::getInstance()->getBool("InputTouchOverlay")) InputOverlay::getInstance().update(deltaTime); #endif @@ -657,7 +657,7 @@ void Window::render() if (mRenderScreensaver) mScreensaver->renderScreensaver(); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__IOS__) if (Settings::getInstance()->getBool("InputTouchOverlay")) InputOverlay::getInstance().render(mRenderer->getIdentity()); #endif diff --git a/es-core/src/renderers/Renderer.cpp b/es-core/src/renderers/Renderer.cpp index 281b7c70a..c75dcc46b 100644 --- a/es-core/src/renderers/Renderer.cpp +++ b/es-core/src/renderers/Renderer.cpp @@ -69,6 +69,9 @@ bool Renderer::createWindow() mInitialCursorState = (SDL_ShowCursor(0) != 0); +#if defined(__IOS__) + int displayIndex {0}; +#else int displayIndex {Settings::getInstance()->getInt("DisplayIndex")}; // Check that an invalid value has not been manually entered in the es_settings.xml file. if (displayIndex != 1 && displayIndex != 2 && displayIndex != 3 && displayIndex != 4) { @@ -88,6 +91,7 @@ bool Renderer::createWindow() else { LOG(LogInfo) << "Using display: " << std::to_string(displayIndex + 1); } +#endif SDL_DisplayMode displayMode; SDL_GetDesktopDisplayMode(displayIndex, &displayMode); @@ -217,6 +221,8 @@ bool Renderer::createWindow() else // If the resolution has been manually set from the command line, then keep the border. windowFlags = SDL_WINDOW_OPENGL; +#elif defined(__IOS__) + windowFlags = SDL_WINDOW_FULLSCREEN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL; #elif defined(__APPLE__) // Not sure if this could be a useful setting. // SDL_SetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, "0"); @@ -249,19 +255,22 @@ bool Renderer::createWindow() mDisplayIndex = displayIndex; #if defined(__APPLE__) - // The code below is required as the high DPI scaling on macOS is very bizarre and is - // measured in "points" rather than pixels (even though the naming convention sure looks - // like pixels). For example there could be a 1920x1080 entry in the OS display settings - // that actually corresponds to something like 3840x2160 pixels while at the same time - // there is a separate 1080p entry which corresponds to a "real" 1920x1080 resolution. + // The code below is required as the high DPI scaling on macOS and iOS is measured in "points" + // rather than pixels. For example there could be a 1920x1080 entry in the macOS display + // settings that actually corresponds to something like 3840x2160 pixels while at the same + // time there is a separate 1080p entry which corresponds to a "real" 1920x1080 resolution. // Therefore the --resolution flag results in different things depending on whether a high - // DPI screen is used. E.g. 1280x720 on a 4K display would actually end up as 2560x1440 - // which is incredibly strange. No point in struggling with this strangeness though, - // instead we simply indicate the physical pixel dimensions in parenthesis in the log - // file and make sure to double the window and screen sizes in case of a high DPI - // display so that the full application window is used for rendering. + // DPI screen is used. E.g. 1280x720 on a 4K display would actually end up as 2560x1440 pixels. + // The scale factor on macOS and iOS can be 1, 2 or 3 and we use this factor to calculate the + // actual physical pixel dimensions. We indicate these numbers inside parenthesis in the log + // file and we multiply the internal pixel resolution accordingly so that the full display + // or window size is always used for rendering. int width {0}; +#if defined(__IOS__) + SDL_GetWindowSizeInPixels(mSDLWindow, &width, nullptr); +#else SDL_GL_GetDrawableSize(mSDLWindow, &width, nullptr); +#endif int scaleFactor {static_cast(width / mWindowWidth)}; LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x" diff --git a/es-core/src/renderers/RendererOpenGL.cpp b/es-core/src/renderers/RendererOpenGL.cpp index 299174ecc..e963d14c6 100644 --- a/es-core/src/renderers/RendererOpenGL.cpp +++ b/es-core/src/renderers/RendererOpenGL.cpp @@ -14,9 +14,17 @@ #include #endif +#if defined(__IOS__) +#include +#endif + RendererOpenGL::RendererOpenGL() noexcept : mShaderFBO1 {0} , mShaderFBO2 {0} + , mFramebuffer {0} +#if defined(__IOS__) + , mColorbuffer {0} +#endif , mVertexBuffer1 {0} , mVertexBuffer2 {0} , mSDLContext {nullptr} @@ -112,7 +120,7 @@ GLenum RendererOpenGL::convertTextureType(const TextureType type) #else case TextureType::BGRA: { return GL_BGRA; } break; #endif -#if defined(__EMSCRIPTEN__) || defined(__ANDROID__) +#if defined(__EMSCRIPTEN__) || defined(__ANDROID__) || defined(__IOS__) case TextureType::RED: { return GL_LUMINANCE; } break; #else case TextureType::RED: { return GL_RED; } break; @@ -251,6 +259,28 @@ bool RendererOpenGL::createContext() #endif #endif +#if defined(__IOS__) + SDL_SysWMinfo info {}; + SDL_VERSION(&info.version); + + UIWindow* uiWindow {nullptr}; + if (SDL_GetWindowWMInfo(getSDLWindow(), &info) && info.subsystem == SDL_SYSWM_UIKIT) + uiWindow = (UIWindow*)info.info.uikit.window; + + if (uiWindow) { + mFramebuffer = info.info.uikit.framebuffer; + mColorbuffer = info.info.uikit.colorbuffer; + } + + GL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer)); + GL_CHECK_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mColorbuffer)); + GLenum status {glCheckFramebufferStatus(GL_FRAMEBUFFER)}; + + if (status != GL_FRAMEBUFFER_COMPLETE) { + LOG(LogError) << "Couldn't setup framebuffer: " << status; + } +#endif + GL_CHECK_ERROR(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); GL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0)); GL_CHECK_ERROR(glEnable(GL_BLEND)); @@ -306,7 +336,7 @@ bool RendererOpenGL::createContext() GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mPostProcTexture2, 0)); - GL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); + GL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer)); return true; } @@ -379,7 +409,7 @@ void RendererOpenGL::setSwapInterval() void RendererOpenGL::swapBuffers() { -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(__IOS__) // On macOS when running in the background, the OpenGL driver apparently does not swap // the frames which leads to a very fast swap time. This makes ES-DE use a lot of CPU // resources which slows down the games significantly on slower machines. By introducing @@ -444,8 +474,17 @@ unsigned int RendererOpenGL::createTexture(const unsigned int texUnit, GL_UNSIGNED_BYTE, data)); } else { +#if defined(__IOS__) + if (type == TextureType::RED) + GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, + textureType, GL_UNSIGNED_BYTE, data)); + else + GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, textureType, + GL_UNSIGNED_BYTE, data)); +#else GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType, GL_UNSIGNED_BYTE, data)); +#endif } #else GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, textureType, @@ -756,7 +795,7 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders, for (int p {0}; p < shaderPasses; ++p) { if (!textureRGBA && i == shaderList.size() - 1 && p == shaderPasses - 1) { - GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer)); if (offsetOrPadding) setViewport(mViewport); drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA, @@ -818,10 +857,10 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders, GL_CHECK_ERROR( glReadPixels(0, 0, height, width, GL_BGRA, GL_UNSIGNED_BYTE, textureRGBA)); #endif - GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer)); } - GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); + GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer)); if (offsetOrPadding) setViewport(mViewport); diff --git a/es-core/src/renderers/RendererOpenGL.h b/es-core/src/renderers/RendererOpenGL.h index 9b7970c96..6013f4bed 100644 --- a/es-core/src/renderers/RendererOpenGL.h +++ b/es-core/src/renderers/RendererOpenGL.h @@ -13,7 +13,11 @@ #include "renderers/ShaderOpenGL.h" #if defined(USE_OPENGLES) +#if defined(__IOS__) +#include +#else #include +#endif #include #else #include @@ -78,6 +82,10 @@ private: std::vector> mShaderProgramVector; GLuint mShaderFBO1; GLuint mShaderFBO2; + GLuint mFramebuffer; +#if defined(__IOS__) + GLuint mColorbuffer; +#endif GLuint mVertexBuffer1; GLuint mVertexBuffer2; diff --git a/es-core/src/renderers/ShaderOpenGL.h b/es-core/src/renderers/ShaderOpenGL.h index 59463b068..55dd8e5df 100644 --- a/es-core/src/renderers/ShaderOpenGL.h +++ b/es-core/src/renderers/ShaderOpenGL.h @@ -14,13 +14,21 @@ #include "renderers/Renderer.h" #include "utils/MathUtil.h" +#if defined(__IOS__) +#define GLES_SILENCE_DEPRECATION +#endif + #if defined(_WIN64) #include #endif #include #if defined(USE_OPENGLES) +#if defined(__IOS__) +#include +#else #include +#endif #include #else #include diff --git a/es-core/src/resources/ResourceManager.cpp b/es-core/src/resources/ResourceManager.cpp index c79ac3985..dcba40821 100644 --- a/es-core/src/resources/ResourceManager.cpp +++ b/es-core/src/resources/ResourceManager.cpp @@ -16,6 +16,10 @@ #include +#if defined(__IOS__) +#include "utils/PlatformUtilIOS.h" +#endif + ResourceManager& ResourceManager::getInstance() { static ResourceManager instance; @@ -32,14 +36,21 @@ std::string ResourceManager::getResourcePath(const std::string& path, bool termi if (Utils::FileSystem::exists(testHome)) return testHome; -#if defined(__APPLE__) +#if defined(__IOS__) + const std::string iOSPackagePath {Utils::Platform::iOS::getPackagePath() + &path[2]}; + + if (Utils::FileSystem::exists(iOSPackagePath)) + return iOSPackagePath; +#endif + +#if defined(__APPLE__) && !defined(__IOS__) // For macOS, check in the ../Resources directory relative to the executable directory. std::string applePackagePath {Utils::FileSystem::getExePath() + "/../Resources/resources/" + &path[2]}; - if (Utils::FileSystem::exists(applePackagePath)) { + if (Utils::FileSystem::exists(applePackagePath)) return applePackagePath; - } + #elif (defined(__unix__) && !defined(APPIMAGE_BUILD)) || defined(__ANDROID__) || defined(__HAIKU__) // Check in the program data directory. std::string testDataPath {Utils::FileSystem::getProgramDataPath() + "/resources/" + @@ -71,10 +82,12 @@ std::string ResourceManager::getResourcePath(const std::string& path, bool termi LOG(LogError) << "Program resource missing: " << path; LOG(LogError) << "Tried to find the resource in the following locations:"; LOG(LogError) << testHome; -#if defined(__APPLE__) +#if defined(__IOS__) + LOG(LogError) << iOSPackagePath; +#elif defined(__APPLE__) LOG(LogError) << applePackagePath; #elif defined(__unix__) && !defined(APPIMAGE_BUILD) - LOG(LogError) << testDataPath; + LOG(LogError) << testDataPath; #endif #if !defined(__ANDROID__) LOG(LogError) << testExePath; diff --git a/es-core/src/utils/FileSystemUtil.cpp b/es-core/src/utils/FileSystemUtil.cpp index 1bf55bc3f..6bcffbacf 100644 --- a/es-core/src/utils/FileSystemUtil.cpp +++ b/es-core/src/utils/FileSystemUtil.cpp @@ -260,7 +260,10 @@ namespace Utils { #if defined(__ANDROID__) return getHomePath(); -#else +#elif defined(__IOS__) + return getHomePath() + "/Documents/ES-DE"; +#endif + if (FileSystemVariables::sAppDataDirectory.empty()) { #if !defined(_WIN64) if (getenv("ESDE_APPDATA_DIR") != nullptr) { @@ -282,7 +285,6 @@ namespace Utils } return FileSystemVariables::sAppDataDirectory; -#endif } std::string getInternalAppDataDirectory() diff --git a/es-core/src/utils/PlatformUtil.cpp b/es-core/src/utils/PlatformUtil.cpp index d3b63b2ac..5ae0dc12b 100644 --- a/es-core/src/utils/PlatformUtil.cpp +++ b/es-core/src/utils/PlatformUtil.cpp @@ -41,6 +41,9 @@ namespace Utils { int runRebootCommand() { +#if defined(__IOS__) + return 0; +#else #if defined(_WIN64) return system("shutdown -r -t 0"); #elif defined(__APPLE__) || defined(__FreeBSD__) @@ -48,11 +51,15 @@ namespace Utils return system("shutdown -r now"); #else return system("shutdown --reboot now"); +#endif #endif } int runPoweroffCommand() { +#if defined(__IOS__) + return 0; +#else #if defined(_WIN64) return system("shutdown -s -t 0"); #elif defined(__APPLE__) @@ -62,11 +69,15 @@ namespace Utils return system("shutdown -p now"); #else return system("shutdown --poweroff now"); +#endif #endif } int runSystemCommand(const std::string& cmd_utf8) { +#if defined(__IOS__) + return 0; +#else #if defined(_WIN64) // On Windows we use _wsystem to support non-ASCII paths // which requires converting from UTF-8 to a wstring. @@ -74,6 +85,7 @@ namespace Utils return _wsystem(wchar_str.c_str()); #else return system(cmd_utf8.c_str()); +#endif #endif } @@ -102,7 +114,11 @@ namespace Utils LOG(LogDebug) << "Platform::launchGameUnix(): Launching game while keeping ES-DE running " "in the background, no command output will be written to the log file"; +#if defined(__IOS__) + return 0; +#else return system(command.c_str()); +#endif } FILE* commandPipe;